dll中的函数要返回pchar怎么做?(100分)

  • 主题发起人 主题发起人 FreeAndNil
  • 开始时间 开始时间
//Dll
library Project1;

uses
SysUtils,
Classes;

{$R *.res}

function GetDate() : PChar; stdcall;
var
sToday : string;
begin
sToday := FormatDateTime('YYYY-MM-DD', Date);
Result := PChar(sToday);
end;

exports
GetDate;

begin
end.

//exe
procedure TForm1.Button3Click(Sender: TObject);
var
sToday : array[0..10] of Char;
begin
StrCopy(sToday, GetDate());
Edit1.Text := TButton(Sender).Caption + ' : ' + sToday ;
end;
 
==================================
我一直认为dll并非进程,而是和调用程序同一个进程,难道我一直错了?不解。
==================================
很遗憾地告诉你,DLL和调用它的客户程序的确不是同一个进程。不要被那句经典的“可执行程序动态载入DLL时会在自己的进程空间中拥有它的一份拷贝”解释所迷惑了,它的意思只是说由于DLL不能自己运行,所以它只能“寄宿”在调用它的那个程序的进程(内存)空间里面,而这也同时保证了一个DLL可以被不同的程序所调用,每个调用该DLL的程序都各自拥有属于自己的一份DLL的拷贝,不同程序载入的DLL拷贝互不干扰。但这并不是说DLL和它的宿主程序是属于同一个进程的了,这么理解是不对的。
 
=====================================================
我之所以有这样的想法,是因为要写个dll,给用户调用,用户要求只要一个无参数的函数,返回一字符串,所以才引发了这个问题,是否用户的要求的确是无非实现的?
=====================================================
如果客户的要求是不合理的,你当然应该据理力争,而不是盲目地想着怎么满足要求。既然DLL编程有它不可抗拒的规律,那么你的客户要么只能正视这个事实,学习如何正确地使用DLL,而不是一味地用非DLL函数的那一套法则来理解甚至是要求“DLL应该怎么样怎么样”。要么只能放弃DLL的方式,采用控件或静态函数库的方式来给他提供你的例程。
 
多谢韦剑,但如果dll不是与调用者同一进程,那它在哪个进程?
 
DLL自己就是一个进程呀,只不过它不像EXE那样是自己启动,而是由EXE用“调用”的方式启动的而已。
 
声明的变量
pchar(它)传递
 
TO: 韦剑
近来我又温习了一下windows核心编程,看了内存管理这章。dll确实是被当作内存影射
文件到调用进程的的地址空间里面。而且里面也不推荐象楼主那样的做法。 因为你在dll
所分配的内存,不一定就能是你使用相同的工具进行调用。如果你是使用别的工具呢。比如
C++等。 那么delphi 是使用freeMem释放,但是C++ 根本就不是这个,估计就是dll不允许
你在dll分配内存之后,在调用exe进行释放的限制。后来他给了个解决方案是,你在dll定
义一个释放内存的函数,就可以解决问题。 因为在windows核心编程是这么讲的。而且是使用C++的例子,还请楼住测试一下吧!

呵呵:韦剑 其实已经回答你的问题了, 他的第一次回答就是正确的。
 
韦剑: DLL函数内部当然也可以动态分配内存,但这个动态分配的内存一定要由这个函数或同一个DLL里面的其他函数释放掉,不能让调用DLL的程序来释放。这是DLL编程的一个通用的铁律和常识,并不是Delphi所独有的,所有编程语言在编写DLL时都要遵守这个守则,因为这涉及到的是Windows内存共享的问题。
这句讲得很清楚了。
 
//帮楼主写了, 呵呵.测试通过了的.
//dll 部分

library dllmem;

uses
SysUtils,
Classes;
var
G_Buffer: PChar;
{$R *.res}
function AlloMem: PChar;
begin
GetMem(G_Buffer, 100);
G_Buffer[0] := 'A';
G_Buffer[1] := 'B';
G_Buffer[2] := 'C';
Result := G_Buffer;
end;
function DealMem: Integer;
begin
Result := 0;
try
FreeMem(G_Buffer, 100);
except
Exit;
end;
Result := 1;
end;
exports
AlloMem,
DealMem;
begin
end.
//EXE部分
unit uMain;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses Math;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
type
TAlloMem = function: PChar;
TDealMem = function: Integer;
var
AlloMem: TAlloMem;
DealMem: TDealMem;
dllHandle: Cardinal;
Ph: PChar;
begin
dllHandle := LoadLibrary(PChar('D:/dll内存分配/dllmem.dll'));
If dllHandle <= 0 then Exit;
AlloMem := GetProcAddress(dllHandle, Pchar('AlloMem'));
DealMem := GetProcAddress(dllHandle, Pchar('DealMem'));
if (@AlloMem = nil) or (@DealMem = nil) then
begin
FreeLibrary(dllHandle);
Exit;
end;
try
Ph := AlloMem; {dll分配内存}
ShowMessage(StrPas(Ph));
finally
DealMem; {dll释放内存}
end;
end;
end.
 
调用者负责申请和释放,这是最基本的编程原则,虽然我总是打破他,但是调用dll函数,应该是绝对不可以返回指针类型的吧。虽然语法上可以。正常的调用应该使用指针传递内存到dll中,填充返回,至于长度信息往往是静态长度,或者先获取长度。
 
后退
顶部