gpt4 book ai didi

C# Dll 库不将输出参数值返回给 Delphi 应用程序

转载 作者:行者123 更新时间:2023-11-30 23:07:49 26 4
gpt4 key购买 nike

我用 C# 编写了一个 Dll,带有一个保存文件的导出函数。

这是C#代码

using RGiesecke.DllExport;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;

namespace ClassLibrary1
{
public class Class1
{
[DllExport("Funcion", CallingConvention = CallingConvention.StdCall)]
public static void Funcion(IntPtr pDataIn, Int32 pSize, [Out, MarshalAs(UnmanagedType.I4)] int pArchivo)
{
byte[] documento = new byte[pSize];
Marshal.Copy(pDataIn, documento, 0, pSize);
File.WriteAllBytes("Document2.pdf", documento);

pArchivo = 25;
}
}
}

在 Delphi 中,我加载库并调用导出的函数,它工作正常。

这是德尔福代码

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) 值,无论我为参数分配什么值,它总是有 cero 值。

我是这样修改参数的

out int pArchivo

ref int pArchivo

但是当函数完成时我得到一个内存异常。

使用 Marshal,函数可以正常完成,没有内存错误,但输出参数值始终为 cero (0)。

[Out, MarshalAs(UnmanagedType.I4)] int pArchivo

我在 Stackoverflow 的这篇文章中读到了这个问题

Passing array of struct from c# to Delphi

但在我的情况下,它不起作用

我做错了什么?

我希望你能帮上忙...非常感谢

最佳答案

在 Delphi 方面,直接声明为 array of ... 的函数参数被称为 "open array" . “开放数组”由编译器使用 2 参数传递 - 指向第一个数组元素的指针,以及数组的高索引(不是长度!)。这允许调用代码将静态数组或动态数组传递给同一参数,编译器将相应地传递数组数据。

但是,您的 .NET 代码只需要数组的 1 个参数 - 指向第一个数组元素的原始指针。这就是为什么您没有正确获得输出值的原因。您的 lStream.Size 参数值在 .NET 代码期望第三个参数的位置传递,因此 Size 值被误解为 .NET 代码写入的内存地址它的输出 pArchivo 值,因此内存错误。反正这无关紧要,因为您正在破坏调用堆栈!您最终将 4 参数值压入堆栈,然后 .NET 端的 stdcall 在堆栈清理期间仅弹出 3 参数值函数退出。

您需要通过以下方式更改Funcion 变量的声明:

  • 保留 pDataIn 参数声明为 array of Byte,但删除显式 pInSize 参数 .让编译器隐式传递它:

    Funcion : procedure(pDataIn : array of Byte;
    //pInSize : Integer;
    var pDocumento : Integer
    ); stdcall;

    然后,您必须更改 Funcion() 的调用,为 lArBytes 数组再分配 +1 个字节,以便编译器将正确的大小值传递给 pSize 参数:

    SetLength(lArBytes, lStream.Size+1); // <-- +1 here!
    lStream.Read(PByte(lArBytes)^, High(lArBytes)); // <-- no +1 here!
    ...
    Funcion(lArBytes{, High(lArBytes)}, lInDocSize);

    不用说,这并不直观,尽管它应该有效,因为开放数组的行为是众所周知的,尽管它是 Delphi 编译器的私有(private)实现细节。

  • 使用PByte(或只是Pointer)代替字节数组:

    Funcion : procedure(pDataIn : PByte; // <-- here
    pInSize : Integer;
    var pDocumento : Integer
    ); stdcall;

    然后您必须更改 Funcion() 的调用以传递指向第一个数组元素的指针,并显式传递数组长度:

    SetLength(lArBytes, lStream.Size); // <-- no +1 here!
    lStream.Read(PByte(lArBytes)^, Length(lArBytes)); // <-- or here!
    ...
    Funcion(@lArBytes[0]{or: PByte(lArBytes)}, Length(lArBytes), lInDocSize);

    这更直观,更接近 .NET 代码的预期。

或者,我建议您完全删除 lArBytes 变量。你实际上并不需要它。由于 .NET 代码需要一个指向字节数据的原始指针,只需直接传递您的 TMemoryStream 数据即可:

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;

关于C# Dll 库不将输出参数值返回给 Delphi 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46942809/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com