Delphi XE3写DLL,用Delphi7调用,报错! 本帖最后由 wzgdyn 于 2014-08-25 22:10:20 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 我也写过一个这样的。在XE2写到DLL在Delphi2010调用,一直出错。最后没办法只能装个2010编译我写到DLL,就可以了。Delphi在处理版本之间的转换很不到位 function Test(Instr1,Instr2:PAnsiChar):PAnsiChar;stdcall;可以改成这样str1,str2:string;最好改成AnsiString str1,str2:string;换成str1,str2:AnsiString试试或者retMsg:=PAnsiChar( AnsiString( str1+'-'+str2) ); AnsiString 的问题. string 不可以直接转成 PAnsiChar 的 接口函数两边的申明不一致,retMsg上面是变参,下面是形参应该是D7的申明里漏了var 动态库修改str1,str2:AnsiString;或者retMsg:=PAnsiChar( AnsiString( str1+'-'+str2) );可以,完全正确。如果想要DelphiXE3写的DLL,用C++也可以调用,那么字符串的参数类型应该怎么定义? PAnsiChar类型可以吗?还是必须用Pchar ?? Delphi版的人越来越少了吗????????? 1 调用时type TTest=function(Instr1,Instr2:PChar; retMsg:PChar):Integer;stdcall;缺少Var标识。2 D7的Pchar是PAnsiChar XE后是PWidechar。不多说了Library TestDll;Uses System.SysUtils, System.Classes;Function Test(Instr1, Instr2: PAnsiChar; Var retMsg: PAnsiChar): Integer; Stdcall;Var str1, str2: String;Begin str1 := String(Instr1); str2 := String(Instr2); //retMsg := PAnsiChar(ansiString(str1 + '-' + str2)); StrCopy(retMsg, PAnsiChar(ansiString(str1 + '-' + str2))); Result := 1;End;Exports Test;End.Type TTest = Function(Instr1, Instr2: PAnsiChar; Var retMsg: PAnsiChar): Integer; Stdcall;Var lhandle: THandle; ltest: TTest; retMsg: PAnsiChar;Begin lhandle := LoadLibrary('TestDll.dll'); If lhandle > 32 Then Begin @ltest := GetProcAddress(lhandle, 'Test'); GetMem(retMsg, 256); If ltest(PChar(Edit1.Text), PChar(Edit2.Text), retMsg) = 1 Then Begin ShowMessage('调用成功,返回Msg:' + retMsg); End; FreeMem(retMsg); End;Type TTest = Function(Instr1, Instr2: PAnsiChar; Var retMsg: PAnsiChar): Integer; Stdcall;Var lhandle: THandle; ltest: TTest; retMsg: PAnsiChar;Begin lhandle := LoadLibrary('TestDll.dll'); If lhandle > 32 Then Begin @ltest := GetProcAddress(lhandle, 'Test'); GetMem(retMsg, 256); If ltest(PAnsiChar(Ansistring(Edit1.Text)), PAnsiChar(Ansistring(Edit2.Text)), retMsg) = 1 Then Begin ShowMessage('调用成功,返回Msg:' + retMsg); End; FreeMem(retMsg); End; AnsiChar,在xe2和D7占1个字节Char,在xe2中占2个字节,在D7占1个字节 同意7楼的,,,DLL里面出来的数据有问题。 Delphi 好像是从 2010 开始,char,AnsiChar, widechar, string, ansistring, widestring 占用的字节不一样了~一定要注意,如果想高版本的程序移到低版本,就要注意字符定义必需一一对应了.就如你dll时定义了PAnsiChar, 到了调用时,也需要 是PAnsiChar而不能用 pchar 随便,可以不用改,PAnsiChar就对应C++里的char* lz的代码有这么几个问题:1. 函数的签名不同,导出的是 var retMsg: PAnsiChar; 使用的却是 regMsg:Pansichar;后者无法接收到返回的值。2. 导出函数使用UnicodeString(xe3string是UnicodeString),却硬生生的把他强制转换为PAnsiChar;3. 函数返回的retMsg是由临时的函数内变量,函数结束,该变量消失。你获得的将是一个非法内存地址。4. 对string的编译器自动引用计数管理认识不清,string的引用计数不能跨dll的,他是delphi特有的东西。解决方法1. 签名一致用 var PansiChar2. 函数用GetMem分配内存,并使用Ansistring封装数据,然后复制到分配的内存中3. 返回分配的内存地址 调用的函数负责释放内存。因此dll还需提供一个释放内存的导出函数(将Freemem封装成导出函数); retMsg:=PAnsiChar(str1+'-'+str2);str1+''+str2的内容是保存在临时变量中的,这个临时变量是局部变量,离开函数的时候就被回收了.你转成PAnsiChar的地址指向的是无效的地址,之所以有时候会是正常的是因为内存管理器没有重用这块内存的话看上去像是对的. PAnsiChar, PChar,string 都改成 WideString 试试看。 Ravereport中怎么用代码创建的报表? Delphi6的dbgrid能否设置只有某一行或某一列可以修改,其它行列不许修改? 如何发布程序? 关于spcomm控件的讨论,进者有分! fastreport乱出纸 两个应用程序之间怎么实现类似Alt+Tab的功能 韓國人都是色狼!同意者請進來報個名。 请教一个打印方面的问题! 这么多数据用怎么处理? 我用QUERY1查询结果放到DBGRID中然后我修改记录,怎样反映到DGGRID中不用 Delphi控件遮挡问题 ESC/POS 指令打印图片
在XE2写到DLL在Delphi2010调用,一直出错。最后没办法只能装个2010编译我写到DLL,就可以了。
Delphi在处理版本之间的转换很不到位
最好改成AnsiString
换成
str1,str2:AnsiString试试
或者
retMsg:=PAnsiChar( AnsiString( str1+'-'+str2) );
应该是D7的申明里漏了var
str1,str2:AnsiString;
或者
retMsg:=PAnsiChar( AnsiString( str1+'-'+str2) );
可以,完全正确。如果想要DelphiXE3写的DLL,用C++也可以调用,那么字符串的参数类型应该怎么定义?
PAnsiChar类型可以吗?还是必须用Pchar ??
2 D7的Pchar是PAnsiChar XE后是PWidechar。
不多说了
Library TestDll;Uses
System.SysUtils,
System.Classes;Function Test(Instr1, Instr2: PAnsiChar; Var retMsg: PAnsiChar): Integer; Stdcall;
Var
str1, str2: String;
Begin
str1 := String(Instr1);
str2 := String(Instr2);
//retMsg := PAnsiChar(ansiString(str1 + '-' + str2));
StrCopy(retMsg, PAnsiChar(ansiString(str1 + '-' + str2)));
Result := 1;
End;Exports
Test;End.Type
TTest = Function(Instr1, Instr2: PAnsiChar; Var retMsg: PAnsiChar): Integer; Stdcall;
Var
lhandle: THandle;
ltest: TTest;
retMsg: PAnsiChar;
Begin
lhandle := LoadLibrary('TestDll.dll');
If lhandle > 32 Then
Begin
@ltest := GetProcAddress(lhandle, 'Test');
GetMem(retMsg, 256);
If ltest(PChar(Edit1.Text), PChar(Edit2.Text), retMsg) = 1 Then
Begin
ShowMessage('调用成功,返回Msg:' + retMsg);
End;
FreeMem(retMsg);
End;Type
TTest = Function(Instr1, Instr2: PAnsiChar; Var retMsg: PAnsiChar): Integer; Stdcall;
Var
lhandle: THandle;
ltest: TTest;
retMsg: PAnsiChar;
Begin
lhandle := LoadLibrary('TestDll.dll');
If lhandle > 32 Then
Begin
@ltest := GetProcAddress(lhandle, 'Test');
GetMem(retMsg, 256);
If ltest(PAnsiChar(Ansistring(Edit1.Text)), PAnsiChar(Ansistring(Edit2.Text)), retMsg) = 1 Then
Begin
ShowMessage('调用成功,返回Msg:' + retMsg);
End;
FreeMem(retMsg);
End;
Char,在xe2中占2个字节,在D7占1个字节
随便,可以不用改,PAnsiChar就对应C++里的char*
1. 函数的签名不同,导出的是 var retMsg: PAnsiChar; 使用的却是 regMsg:Pansichar;后者无法接收到返回的值。
2. 导出函数使用UnicodeString(xe3string是UnicodeString),却硬生生的把他强制转换为PAnsiChar;
3. 函数返回的retMsg是由临时的函数内变量,函数结束,该变量消失。你获得的将是一个非法内存地址。
4. 对string的编译器自动引用计数管理认识不清,string的引用计数不能跨dll的,他是delphi特有的东西。解决方法
1. 签名一致用 var PansiChar
2. 函数用GetMem分配内存,并使用Ansistring封装数据,然后复制到分配的内存中
3. 返回分配的内存地址 调用的函数负责释放内存。因此dll还需提供一个释放内存的导出函数(将Freemem封装成导出函数);
str1+''+str2的内容是保存在临时变量中的,这个临时变量是局部变量,离开函数的时候就被回收了.
你转成PAnsiChar的地址指向的是无效的地址,之所以有时候会是正常的是因为内存管理器没有重用这块内存的话看上去像是对的.