delphi编写dll用Pchar返回数据的问题,急~~~~~~~~(100)

  • 主题发起人 主题发起人 zhhg975
  • 开始时间 开始时间
Z

zhhg975

Unregistered / Unconfirmed
GUEST, unregistred user!
使用delphi6编写一个dll,因为有可能被其它语言调用,所以想用Pchar来返回一些值,现在dll函数定义如下:function ReadInfo(iPort:Integer;var SN,ID,No,PCode:Pchar):Pchar;stdcall;然后我用delphi写了个小程序调用, Retcode : PChar; iPort : integer; sn,ID,No,PCode:Pchar;begin iCommPort := cmbComm1.ItemIndex +1; Retcode := ReadInfo_HF(iPort,SN,ID,No,PCode);这样调用取出来的Pchar的值不对,经常改变,这个dll应该如何定义呢,程序又改如何调用呢希望大大们赐教
 
Retcode : String; // 必须改 PChar; tmpchar:pchar; iPort : integer; sn,ID,No,PCode:Pchar;begin iCommPort := cmbComm1.ItemIndex +1; setlength(Retcode,1024);// 尽量大 tmpchar:=@Retcode[1]; tmpchar := ReadCardInfo_HF(iPort,SN,ID,No,PCode); setlength(Retcode,pos(#0,Retcode));
 
感谢LS的回答,能再详细点吗,加一些说明就更好了我现在主要就是想获得 sn,ID,No,PCode:Pchar 这几个值,这个是调用程序传入的,现在得到的这几个值有问题
 
PChar 实际是是一个指针,最好是加个返回长度
 
返回长度是不定的,只有dll里面才能确定,应该怎么加呢?
 
其实你按照 wql 的方法就可以做了的.var Retcode : String; iPort : integer; sn,ID,No,PCode,tmpchar:Pchar;begin iCommPort := cmbComm1.ItemIndex +1; GetMem(TmpChar,1024); // 设定好 sn,id,no,pcode 的值 TmpChar:= ReadCardInfo_HF(iPort,SN,ID,No,PCode); Retcode:=StrPas(TmpChar); freemem(TmpChar,1024);end;
 
好像写错了, 返回值可以直接引用. 不需要申请内存空间
 
最好不要这样做 因为你不知道你获得的PChar什么时候会被DLL释放掉
 
Delphi例子:function Test_GetXML( const XML : PChar; const XMLLen : Integer ):Integer;stdcall;var s : string; l : integer;begin s := '..........................';//获取值 Result := Length(s); //值长度 l := Result; if xmllen < l then l := xmllen; //处理分配长度不够的情况 ZeroMemory(XML, XMLLen); CopyMemory(XML, @s[1], l); //写入调用者分配的内存end;C#调用声明: public class Dll_Test { private const string Dll_FileName = @"D:/Test.dll"; [DllImport(Dll_FileName)] public static extern int Test_GetXML( StringBuilder XML, //输出参数,XML文档内容,请分配足够的空间 int XMLLen //上面分配空间大小 ); //返回XML文档大小 }C#调用: StringBuilder s = new StringBuilder(5000); Dll_Test.Test_GetXML( s, s.Capacity ); textbox.Text = s.ToString();内存管理原则:谁分配的空间谁释放你返回PChar的话,是DLL分配的内存,应该DLL释放,而调用者不知道DLL什么时候会释放,容易出错,特别在跨语言调用的情况下所以参考WINAPI的约定写代码就行了
 
我是个250,但我想出的是100%的方法:wql 的思想还是荒唐!其它语言调,不是多少的问题,而是连地址都不对的问题! 例如:一个delphi .dll,被重复调用2次,第二次就死翘翘了!
 
还是有些迷茫,这样定义是不是正确function ReadInfo(iPort:Integer;var SN,ID,No,PCode:Pchar):Pchar;stdcall;因为看到一个帖子说这种dll如果其它语言调用,不能使用 var 来传值,如果将定义改为function ReadInfo(iPort:Integer;var SN,ID,No,PCode:Pchar):integer;stdcall;是不是要好点呢?我的主要目的是获得var SN,ID,No,PCode:Pchar,这几个变量里面的值,函数返回值是什么类型无所谓,只是一个标识
 
//DLLfunction ReadInfo(iPort:Integer;SN,ID,No,PCode:Pchar):integer;stdcall;begin StrCopy(SN,PChar('1')); StrCopy(ID,PChar('2')); StrCopy(No,PChar('3'));end;//调用var //使用静态分配内存的方式 vSN,vID,vNo:array[0..255] of char;//视具体情况分配内存begin FillChar(vSN,255,#0); FillChar(vID,255,#0); FillChar(vNo,255,#0); ReadInfo(1,vSN,vID,vNo);//vSN,vID,vNo就可以得到返回值了end;或者 用动态分配内存的方式var vSN,vID,vNo:PChar;begin GetMem(vSN,255); GetMem(vID,255); GetMem(vNo,255); ReadInfo(1,vSN,vID,vNo);//vSN,vID,vNo就可以得到返回值了 FreeMem(vSN); FreeMem(vID); FreeMem(vNo);end;
 
function ReadInfo(iPort:Integer; SN,ID,No,PCode:Pchar):Pchar;stdcall;或者可以使用function ReadInfo(iPort:Integer;SN,ID,No,PCode:WideString):WideString;stdcall;由于返回值都是指针类型的数据。只要传入的数据指针不为空,而且大小符合,就没有问题。建议使用WideString,因为PChar在别的语言里调用有时候会有问题,而WideString是Windows的标准数据类型。
 
to 草原骏马如果这样定义function ReadInfo(iPort:Integer;SN,ID,No,PCode:Pchar):integer;stdcall;可以吗,返回值定义为integer,其它语言调用会有问题吗?WideString在C、VC中应该用什么类型?
 
对于 zhhg975 同学的问题,要分两种情况,主要是看谁分配内存。第一种情况,DLL分配内存。这是针对 zhhg975 同学的。函数定义不用改变,下面这样就可以,要改变的是它的实现function ReadInfo(iPort:Integer;var SN,ID,No,PCode:Pchar):Pchar;stdcall;begin //1 分别分配内存 //2 将分配的内存分别赋给SN,ID,No,PCode //如 sn := pchar(AllocMem(Size)); //返回值也一样 result := pchar(AllocMem(Size)); //当然对SN[x]的赋值是必须的,否则总变化 end;第二种情况,调用程序分配内存,这时DLL中直接使用就可以了,不用再分配了。注意,最好把关键字var去掉。当然返回值还是要分配内存的function ReadInfo(iPort:Integer;SN,ID,No,PCode:Pchar):Pchar;stdcall;begin //sn[x] := ....; //result := pchar(AllocMem(Size)); //...end;按照个人的用途可选用不同的内存分配函数。
 
to JohnYale现在采用你说的dll分配内存,依然用这种定义方式function ReadInfo(iPort:Integer;var SN,ID,No,PCode:Pchar):Pchar;stdcall;那样调用程序里面定义的 SN,ID,No,PCode:Pchar 这些就不需要分配内存,dll里面分配内存后是否需要在dll里面释放内存呢?这样定义,里面有var ,其它语言如VC等调用不会有问题?
 
to zhhg975dll中分配的内存,当然应该由调用程序释放,除非dll知道你什么时间不用这块内存了。你可以把该函数放在主程序中,也可以放在Dll中,但调用还是主程序啊。给其他程序调用,用GlobalAlloc/Globalfree,localAlloc/localfree比较稳妥,因我不清楚AllocMem是如何分配内存的,和api分配有什么异同
 
我以前也遇过这样的情况,后来测试发现在调用前先给PChar变量赋值就解决了 Retcode : PChar; iPort : integer; sn,ID,No,PCode:Pchar;begin iCommPort := cmbComm1.ItemIndex +1; sn := ''; ID := ''; No := ''; PCode := ''; Retcode := ReadInfo_HF(iPort,SN,ID,No,PCode);
 
分不多,谢谢各位的回答
 
后退
顶部