如何在函数返回之前将新大小的数组从C++DLL发送到Delphi



如果C++DLL函数复制较长的数组,我想在Delphi程序中更改缓冲区数组的大小。Delphi代码:

function sendUserAllocatedArray(AllocatedArrayPtr: PAnsiChar; Length: Integer): Integer; cdecl;
external 'DLLlibrary.dll';
var
myCharPtr : PAnsiChar;
size : integer;  
UserAllocatedArray: array[0..10] of AnsiChar;
arrayPtr: PAnsiChar;
begin
UserAllocatedArray :=  'test123';
arrayPtr := UserAllocatedArray;
size := sendUserAllocatedArray(arrayPtr, Length(UserAllocatedArray));   
end

C++DLL:

extern "C" __declspec(dllexport) int sendUserAllocatedArray(char* data, int length);
int sendUserAllocatedArray(char* data, int length)
{
char char_array[] = "this array length is more than 10";
datLength = sizeof(char_array);
if(datLength < length)
strcpy_s(data, length, char_array);
else
....;   
return length;
}

因此,如果在DLL函数将数据复制到数组之前需要更大的缓冲区,我需要分配更多的空间。我需要管理员吗。怎么能做到。

给定您显示的代码,执行您想要的操作(不更改DLL函数的签名(的唯一方法是,如果输入缓冲区太小,则DLL函数return为所需的缓冲区长度,例如:

extern "C" __declspec(dllexport) int sendUserAllocatedArray(char* data, int length);
int sendUserAllocatedArray(char* data, int length)
{
char char_array[] = "this array length is more than 10";
int datLength = sizeof(char_array);
if ((data) && (datLength <= length))
memcpy(data, char_array, length);
return datLength;
}

然后Delphi代码可以做到这一点:

function sendUserAllocatedArray(AllocatedArrayPtr: PAnsiChar; Length: Integer): Integer; cdecl; external 'DLLlibrary.dll';
var
myCharPtr : array of AnsiChar;
size : integer;  
UserAllocatedArray: array[0..10] of AnsiChar;
arrayPtr: PAnsiChar;
begin
UserAllocatedArray := 'test123';
size := sendUserAllocatedArray(UserAllocatedArray, Length(UserAllocatedArray));
if size <= Length(UserAllocatedArray) then
begin
arrayPtr := UserAllocatedArray;
end else
begin
SetLength(myCharPtr, size);
arrayPtr := PAnsiChar(myCharPtr);
StrLCopy(arrayPtr, UserAllocatedArray, size-1);
size := sendUserAllocatedArray(arrayPtr, size);
end;
// use arrayPtr up to size chars as needed...
end;

可以简化为:

function sendUserAllocatedArray(AllocatedArrayPtr: PAnsiChar; Length: Integer): Integer; cdecl; external 'DLLlibrary.dll';
var
size : integer;  
UserAllocatedArray: array of AnsiChar;
begin
SetLength(UserAllocatedArray, 10);
StrLCopy(PAnsiChar(UserAllocatedArray), 'test123', Length(UserAllocatedArray)-1);
repeat
size := sendUserAllocatedArray(PAnsiChar(UserAllocatedArray), Length(UserAllocatedArray));
if size <= Length(UserAllocatedArray) then Break;
SetLength(UserAllocatedArray, size);
until False;
// use UserAllocatedArray up to size chars as needed...
end;

或者这个:

function sendUserAllocatedArray(AllocatedArrayPtr: PAnsiChar; Length: Integer): Integer; cdecl; external 'DLLlibrary.dll';
var
size : integer;  
UserAllocatedArray: array of AnsiChar;
begin
size := sendUserAllocatedArray(nil, 0);
SetLength(UserAllocatedArray, size);
StrLCopy(PAnsiChar(UserAllocatedArray), 'test123', size-1);
size := sendUserAllocatedArray(PAnsiChar(UserAllocatedArray), size);
// use UserAllocatedArray up to size chars as needed...
end;

它是API中广泛使用的解决方案(用内容填充传递的内存数组(,用于将内存数组输入参数NIL值解释为计算必要内存需求的模式开关。

此功能应:

  1. 因此将需要的内存传递回
  2. 检查内存指针是否为零
  3. 检查传递的内存数组大小,在正确的情况下抛出异常。(注释:C有NOT异常机制!在C的情况下,您必须使用特殊的返回值来通知调用方无效的输入参数值/处理错误(
  4. 当然,如果您调用C/C++DLL函数,则必须设置调用调用调用。多数病例为CCD_ 2/CCD_

CDLL函数的示例代码:

unit Unit3;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TDLLFunction = function ( buffer_ : pointer; memSize_ : integer ) : integer; cdecl;
TForm3 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
fDLLFunction : TDLLFunction;
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
function testDLLFunction( mem_ : pchar; memSize_ : integer ) : integer; cdecl;
const
CONST_text_Viered : array [0..3] of char = '1234';
begin
result := ( length( CONST_text_Viered ) + 1 )*sizeOf( char );
if ( mem_ <> NIL ) then
if ( memSize_ >= result ) then
strPCopy( mem_, CONST_text_Viered )
else
result := -1;
end;

procedure TForm3.Button1Click(Sender: TObject);
var
memSize : integer;
memArray : pchar;
begin
memSize := fDLLFunction( NIL, 0 );
getMem( memArray, memSize );
try
if ( fDLLFunction( memArray, memSize ) >= 0 ) then
begin
// Do some usefull think with memArray
end else
showMessage( 'Unsufficient memory error!' );
finally
freeMem( memArray );
end;
end;
procedure TForm3.FormCreate(Sender: TObject);
begin
fDLLFunction := @testDLLFunction;
end;
end.

C++DLL函数的示例代码:

unit Unit3;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TDLLFunction = function ( buffer_ : pointer; memSize_ : cardinal ) : cardinal; stdcall;
TForm3 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
fDLLFunction : TDLLFunction;
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
type
EUnsufficientMemoryError = class ( Exception )
public 
constructor Create( currentSize_, minimumSize_ : cardinal );
end;
constructor EUnsufficientMemoryError.Create( currentSize_, minimumSize_ : cardinal );
begin
inherited Create( 'Unsufficient memory! Current size: ' + intToStr( currentSize_ ) + ' Minimum size: ' + intToStr( minimumSize_ ) );
end;
function testDLLFunction( mem_ : pchar; memSize_ : cardinal ) : cardinal; stdcall;
const
CONST_text_Viered : array [0..3] of char = '1234';
begin
result := ( length( CONST_text_Viered ) + 1 )*sizeOf( char );
if ( mem_ <> NIL ) then
if ( memSize_ >= result ) then
strPCopy( mem_, CONST_text_Viered )
else
raise EUnsufficientMemoryError.Create( memSize_, result );
end;

procedure TForm3.Button1Click(Sender: TObject);
var
memSize: cardinal;
memArray : pchar;
begin
memSize := fDLLFunction( NIL, 0 );
getMem( memArray, memSize );
try
try
fDLLFunction( memArray, memSize );
// Do some useful think with memArray
except
on e : EUnsufficientMemoryError do
//...
;
end;
finally
freeMem( memArray );
end;
end;
procedure TForm3.FormCreate(Sender: TObject);
begin
fDLLFunction := @testDLLFunction;
end;
end.

最新更新