2Pascal-新时代的Pascal
标题:
关于 DLL 和 DLL 字符串的传递 V2015-08-29
[打印本页]
作者:
wang_80919
时间:
2015-8-28 17:23
标题:
关于 DLL 和 DLL 字符串的传递 V2015-08-29
(* ************************************************ *)
(* *)
(* *)
(* 编写:爱吃猪头肉 & Flying Wang 2015-08-28 *)
(* 上面的版权声明请不要移除。 *)
(* *)
(* ************************************************ *)
本人所在的群(① FireMonkey[移动开发] 165232328)
1. 使用 PAnsiChar PWideChar。跨平台使用 PByte。
2. 不要用 Char PChar,否则死了活该。
3. 函数返回值不要是 P任何Char。否则死了活该。
4. 任何内存,任何对象。都是谁创建,谁销毁。你弄错了。死了活该。
5. 需要返回的 string 用 var (不是必须的),而且需要带一个 字符串长度的整数参数。
6. 假设 DLL 的某接口如下
dlltestfun(InString: PAnsiChar; var OutString: PAnsiChar; var OutStrLength: Integer): Integer; stdcall;
6.1 内部代码建议如下
var
sInString: string;
sOutString: string;
CharCount, ByteCount,
sOutStrLen: Integer;
begin
SetString(sInString, InString, StrLen(InString)); //输入的字符串,必须这样获取。
SetString(sOutString, OutString, StrLen(OutString));
//你的一些代码之后。
sOutString := '';
sOutString := '你要输出的字符串';
if (OutString = nil) then
begin
//没有办法输出字符串,因为调用者没有初始化。
exit;
end;
CharCount := Length(sOutString);
if CharCount > OutStrLength then
begin
OutStrLength := CharCount;
//靠,你的保存区空间不够。
exit;
end;
ByteCount := Min(OutStrLength, CharCount) * Sizeof(AnsiChar);
if(OutString <> nil) then
begin
CopyMemory(OutString, PAnsiChar(AnsiChar(sOutString)), ByteCount);
//总算是返回了。
end;
end;
6.2 调用者代码如下
var
sInString: string;
sOutString: string;
InString: PAnsiChar;
OutString: PAnsiChar;
OutStrLength: Integer;
begin
sInString := '你需要输入的字符串';
sOutString := '';
InString := PAnsiChar(AnsiString(sInString));
OutStrLength := 200; 不够你自己加。
OutString := GetMem(OutStrLength);
FillMemory(OutString, OutStrLength, 0);
dlltestfun(InString, OutString, OutStrLength);
SetString(sOutString, OutString, Min(StrLen(OutString),OutStrLength));
//总算是得到返回字符串了。
end;
6.3 以上是 ansi 版本的代码。
6.4 如果你希望支持多国语言,请使用 WideChar
7 以下是使用 TEncoding 和 TBytes 的新版本写法。以及 WideChar 版本。
7.1 dll 代码
function dlltestfunA(InString: PAnsiChar; var OutString: PAnsiChar; var OutStrLength: Integer): Integer; stdcall;
var
sInString: string;
sOutString: string;
CharCount, ByteCount,
sOutStrLen: Integer;
OutBytes: TBytes;
begin
Result := 0;
SetString(sInString, InString, StrLen(InString)); //输入的字符串,必须这样获取。
SetString(sOutString, OutString, StrLen(OutString));
//你的一些代码之后。
sOutString := '';
sOutString := '你要输出的字符串';
if (OutString = nil) then
begin
Result := -1;
//没有办法输出字符串,因为调用者没有初始化。
exit;
end;
OutBytes := TEncoding.ANSI.GetBytes(sOutString + #0); // + #0 这样可以比较安全的传输字符串。
ByteCount := Length(OutBytes);
// #0 不算。
CharCount := ByteCount div Sizeof(AnsiChar) - 1;
if CharCount > OutStrLength then
begin
Result := -2;
OutStrLength := CharCount;
//靠,你的保存区空间不够。
exit;
end;
if (OutString <> nil) then
begin
Result := ByteCount;
Move(OutBytes[0], OutString[0], ByteCount);
//总算是返回了。
end;
end;
function dlltestfunW(InString: PWideChar; var OutString: PWideChar; var OutStrLength: Integer): Integer; stdcall;
var
sInString: string;
sOutString: string;
CharCount, ByteCount,
sOutStrLen: Integer;
OutBytes: TBytes;
begin
Result := 0;
SetString(sInString, InString, StrLen(InString)); //输入的字符串,必须这样获取。
SetString(sOutString, OutString, StrLen(OutString));
//你的一些代码之后。
sOutString := '';
sOutString := '你要输出的字符串';
if (OutString = nil) then
begin
Result := -1;
//没有办法输出字符串,因为调用者没有初始化。
exit;
end;
OutBytes := TEncoding.Unicode.GetBytes(sOutString + #0); // + #0 这样可以比较安全的传输字符串。
ByteCount := Length(OutBytes);
// #0 不算。
CharCount := ByteCount div Sizeof(WideChar) - 1;
if CharCount > OutStrLength then
begin
Result := -2;
OutStrLength := CharCount;
//靠,你的保存区空间不够。
exit;
end;
if (OutString <> nil) then
begin
Result := ByteCount;
Move(OutBytes[0], OutString[0], ByteCount);
//总算是返回了。
end;
end;
7.2 调用代码
procedure TForm1.Button1Click(Sender: TObject);
var
sInString: string;
sOutString: string;
InBytes: TBytes;
OutBytes: TBytes;
OutStrLength: Integer;
InString: PAnsiChar;
OutString: PAnsiChar;
begin
sInString := '你需要输入的字符串';
sOutString := '';
InBytes := TEncoding.ANSI.GetBytes(sInString + #0); // + #0 这样安全,也是各种语言要求的。
OutStrLength := 200; //不够你自己加。
SetLength(OutBytes, OutStrLength * Sizeof(AnsiChar));
FillChar(OutBytes[0], OutStrLength * Sizeof(AnsiChar), 0);
InString := Addr(InBytes[0]);
OutString := Addr(OutBytes[0]);
dlltestfunA(InString, OutString, OutStrLength);
SetString(sOutString, OutString, Min(StrLen(OutString),OutStrLength)); //输出的字符串,必须这样获取。
//总算是得到返回字符串了。
ShowMessage(sOutString);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
sInString: string;
sOutString: string;
InBytes: TBytes;
OutBytes: TBytes;
OutStrLength: Integer;
InString: PWideChar;
OutString: PWideChar;
begin
sInString := '你需要输入的字符串';
sOutString := '';
InBytes := TEncoding.Unicode.GetBytes(sInString + #0); // + #0 这样安全,也是各种语言要求的。
OutStrLength := 200; //不够你自己加。
SetLength(OutBytes, OutStrLength * Sizeof(WideChar));
FillChar(OutBytes[0], OutStrLength * Sizeof(WideChar), 0);
InString := Addr(InBytes[0]);
OutString := Addr(OutBytes[0]);
dlltestfunW(InString, OutString, OutStrLength);
SetString(sOutString, OutString, Min(StrLen(OutString),OutStrLength)); //输出的字符串,必须这样获取。
//总算是得到返回字符串了。
ShowMessage(sOutString);
end;
最后,再提醒一下 var xxx: PXXXXChar 中 var不是必须的。
特别是 跨语言互相调用的时候。建议去掉。
欢迎光临 2Pascal-新时代的Pascal (http://2pascal.com/)
Powered by Discuz! X3