delphi XE7中生成的DLL,返回用于delphi 2007的字符串数组
我正在尝试为Delphi2007中的项目创建一个dll,它使用XE7中的TAmazonStorageService组件delphi XE7中生成的DLL,返回用于delphi 2007的字符串数组,delphi,cloud,delphi-xe7,Delphi,Cloud,Delphi Xe7,我正在尝试为Delphi2007中的项目创建一个dll,它使用XE7中的TAmazonStorageService组件 type TAnsiCharArray = array of PAnsiChar; function ListBuckets(const PrivateKEY: PAnsiChar; const PublicKEY: PAnsiChar; out ArrayBuckets: TAnsiCharArray;
type
TAnsiCharArray = array of PAnsiChar;
function ListBuckets(const PrivateKEY: PAnsiChar; const PublicKEY: PAnsiChar;
out ArrayBuckets: TAnsiCharArray;
out MensagemErro: PAnsiChar): Boolean; stdcall;
external 'Test.dll';
function ListBucketsDelphi(const PrivateKEY: string; const PublicKEY: string;
out StringListBuckets: TStringList;
out Error: string): Boolean;
var
vAnsiPrivateKEY: PAnsiChar;
vAnsiPublicKEY: PAnsiChar;
vAnsiError: PAnsiChar;
vStringArray: TAnsiCharArray;
I: Integer;
begin
{$IFDEF UNICODE}
vAnsiPrivateKEY := PAnsiChar(RawByteString(PrivateKEY));
vAnsiPublicKEY := PAnsiChar(RawByteString(PublicKEY));
{$ELSE}
vAnsiPrivateKEY := PAnsiChar(PrivateKEY);
vAnsiPublicKEY := PAnsiChar(PublicKEY);
{$ENDIF}
//StringListBuckets need to be created before...
Result := ListBuckets(vAnsiPrivateKEY, vAnsiPublicKEY, vStringArray, vAnsiMensagemErro);
if not (Result) then
Error := string(vAnsiError);
try
if Result then
begin
for I := Low(vStringArray) to High(vStringArray) do
StringListBckets.Append(vStringArray[I]);
end;
except
Result := False;
Error := '"StringListBuckets" not created.';
end;
end;
但是,我有几个内存泄漏,或者数组的所有索引都返回最后一个字符串
以下是我的功能:
function ListBuckets(const PrivateKEY: PAnsiChar; const PublicKEY: PAnsiChar;
out ArrayBuckets: TArray<PAnsiChar>;
out Error: PAnsiChar): Boolean; stdcall;
var
AmazonConn: TAmazonConnectionInfo;
AmazonS3: TAmazonStorageService;
ResponseInfo: TCloudResponseInfo;
BucketsList: TStrings;
I: Integer;
begin
Result := True;
AmazonConn := TAmazonConnectionInfo.Create(nil);
AmazonConn.AccountName := string(PublicKEY); { AccessKeyID }
AmazonConn.AccountKey := string(PrivateKEY); { SecretAccessKeyID }
AmazonS3 := TAmazonStorageService.Create(AmazonConn);
ResponseInfo := TCloudResponseInfo.Create;
Error := '';
try
BucketsList := AmazonS3.ListBuckets(ResponseInfo);
if not Assigned(BucketsList) then
begin
Result := False;
Error := PAnsiChar(AnsiString(ResponseInfo.StatusMessage));
end
else
begin
SetLength(ArrayBuckets, BucketsList.Count);
for I := 0 to BucketsList.Count - 1 do
ArrayBuckets[I] := PAnsiChar(AnsiString(BucketsList.Strings[I]));
end;
finally
BucketsList.Free;
ResponseInfo.Free;
AmazonS3.Free;
AmazonConn.Free;
end;
end;
exports ListBuckets;
我搜索了一点,但在unicode dll中没有找到关于返回数组的内容,或者可能我搜索错了
有人能帮忙吗
提前感谢。该函数根本无法安全调用。您有以下问题:
- 除非共享内存管理器,否则您将在一个模块中分配内存,并在另一个模块中销毁它。那是违反规定的
- 当函数返回时,返回的字符串指针(两个
参数)无效。换句话说,一旦函数返回,这些指针指向的东西就不再存在了out
- 您正在跨模块边界传递Delphi动态数组。Delphi动态数组对互操作无效
try/finally
实现不正确。你必须遵循众所周知的标准模式,这在无数地方都可以看到。我不认为这是重复这一点的地方
你需要重新设计。一些选择:
WideString
返回字符串,因为该字符串是从共享堆中分配的WideString
利用共享COM堆我不确定这一点,问题是@DavidHeffernan:既然widestring是CCOMBSTR(一个引用计数的COM对象)的包装器,那么返回一个没有预初始化内存的对象难道不安全吗?(我知道这与“最佳实践”背道而驰,我永远不会做这样的事情(如果我做了,我的PM会对我大喊大叫),但只有从理论上讲,它在现实生活中不安全吗?(我对COM不是很熟悉,但我猜它有自己的对象引用计数。再说一次:我不确定。)@mg30rg
WideString
是BSTR
的包装,而不是CComBSTR
的包装。普通BSTR
不包含引用计数。跨模块边界使用out WideString
参数是可以的。