C#Dll库不会将输出参数值返回给Delphi应用程序
我用C#编写了一个Dll,其中包含一个保存文件的导出函数 这是C代码 在Delphi中,我加载库并调用导出函数,它工作正常 这是Delphi代码C#Dll库不会将输出参数值返回给Delphi应用程序,c#,delphi,dll,parameter-passing,pass-by-reference,C#,Delphi,Dll,Parameter Passing,Pass By Reference,我用C#编写了一个Dll,其中包含一个保存文件的导出函数 这是C代码 在Delphi中,我加载库并调用导出函数,它工作正常 这是Delphi代码 procedure TForm1.Button1Click(Sender: TObject); var lStream : TMemoryStream; lArBytes : array of Byte; lInDocSize : Integer; lHndle : THandle; Funcion : proc
procedure TForm1.Button1Click(Sender: TObject);
var
lStream : TMemoryStream;
lArBytes : array of Byte;
lInDocSize : Integer;
lHndle : THandle;
Funcion : procedure(pDataIn : array of Byte;
pInSize : Integer;
var pDocumento : Integer
); stdcall;
begin
try
lHndle := LoadLibrary('ClassLibrary1.dll');
if (lHndle <> 0) then
begin
Funcion := GetProcAddress(lHndle, 'Funcion');
if Assigned(Funcion) then
begin
try
lStream := TMemoryStream.Create;
lStream.LoadFromFile('Document1.PDF');
lStream.Position := 0;
SetLength(lArBytes, lStream.Size);
lStream.Read(lArBytes[0], lStream.Size);
lInDocSize := 0;
Funcion(lArBytes, lStream.Size, lInDocSize);
Label1.Caption := IntToStr(lInDocSize);
except on E : Exception do
begin
RaiseLastOSError;
ShowMessage(e.Message);
end;
end;
end;
end;
finally
end;
end;
及
但是当函数完成时,我得到一个内存异常
使用封送,函数完成良好,没有内存错误,但输出参数值始终为cero(0)
我在Stackoverflow的这篇文章中读到了这个问题
但就我而言,它不起作用
我做错了什么
我希望你能帮助我。。。非常感谢您在Delphi方面,直接声明为
数组的函数参数称为。编译器使用2参数(指向第一个数组元素的指针和数组的高索引(不是长度!)传递“开放数组”。这允许调用代码将静态数组或动态数组传递给同一参数,编译器将相应地传递数组数据
但是,您的.NET代码只需要数组的1个参数—指向第一个数组元素的原始指针。这就是为什么您没有正确获得输出值的原因。您的lStream.Size
参数值在.NET代码期望第三个参数的位置传递,因此Size
值被误解为.NET代码将其输出pArchivo
值写入的内存地址,因此内存错误。这一点都不重要,因为您正在破坏调用堆栈!最后将4参数值推送到堆栈上,然后当函数退出时,.NET端的stdcall
在堆栈清理过程中仅弹出3参数值
您需要通过以下方式更改函数
变量的声明:
- 保持
pDataIn
参数声明为字节数组
,但删除显式pInSize
参数。让编译器隐式地传递它:
Funcion : procedure(pDataIn : array of Byte;
//pInSize : Integer;
var pDocumento : Integer
); stdcall;
然后,您必须更改function()
的调用,为lArBytes
数组再分配+1个字节,以便编译器将正确的大小值传递给pSize
参数:
SetLength(lArBytes, lStream.Size+1); // <-- +1 here!
lStream.Read(PByte(lArBytes)^, High(lArBytes)); // <-- no +1 here!
...
Funcion(lArBytes{, High(lArBytes)}, lInDocSize);
然后必须更改function()
的调用,以传递指向第一个数组元素的指针,并显式传递数组长度:
SetLength(lArBytes, lStream.Size); // <-- no +1 here!
lStream.Read(PByte(lArBytes)^, Length(lArBytes)); // <-- or here!
...
Funcion(@lArBytes[0]{or: PByte(lArBytes)}, Length(lArBytes), lInDocSize);
out int pArchivo是正确的。用那个。另一个错误是由于打开的数组与c#不匹配。嗨,雷米,我已经尝试了你建议的所有更改,所有这些都很好。我选择了最后一种选择,因为这是我所需要的最简单的方式。再次感谢你的帮助和时间!!!
[Out, MarshalAs(UnmanagedType.I4)] int pArchivo
Funcion : procedure(pDataIn : array of Byte;
//pInSize : Integer;
var pDocumento : Integer
); stdcall;
SetLength(lArBytes, lStream.Size+1); // <-- +1 here!
lStream.Read(PByte(lArBytes)^, High(lArBytes)); // <-- no +1 here!
...
Funcion(lArBytes{, High(lArBytes)}, lInDocSize);
Funcion : procedure(pDataIn : PByte; // <-- here
pInSize : Integer;
var pDocumento : Integer
); stdcall;
SetLength(lArBytes, lStream.Size); // <-- no +1 here!
lStream.Read(PByte(lArBytes)^, Length(lArBytes)); // <-- or here!
...
Funcion(@lArBytes[0]{or: PByte(lArBytes)}, Length(lArBytes), lInDocSize);
procedure TForm1.Button1Click(Sender: TObject);
var
lStream : TMemoryStream;
lInDocSize : Integer;
lHndle : THandle;
Funcion : procedure(pDataIn : Pointer;
pInSize : Integer;
var pDocumento : Integer
); stdcall;
begin
lHndle := LoadLibrary('ClassLibrary1.dll');
if (lHndle <> 0) then
try
Funcion := GetProcAddress(lHndle, 'Funcion');
if Assigned(Funcion) then
begin
lInDocSize := 0;
lStream := TMemoryStream.Create;
try
lStream.LoadFromFile('Document1.PDF');
Funcion(lStream.Memory, lStream.Size, lInDocSize);
finally
lStream.Free;
end;
Label1.Caption := IntToStr(lInDocSize);
end;
finally
FreeLibrary(lHndle);
end;
end;