【问题标题】:Calling Delphi DLLs from C# and passing bitmap and byte array从 C# 调用 Delphi DLL 并传递位图和字节数组
【发布时间】:2016-02-23 23:38:02
【问题描述】:

我正在尝试从 C# 调用几个 Delphi 函数:

  MyType =array [1 .. 124] of byte
  procedure f(bytes: MyType); stdcall;
  external 'my.dll' name 'f';

这是我的第一个问题。我试过了:

    [DllImport("Delphi/my.dll",
        CallingConvention = CallingConvention.StdCall,
        CharSet = CharSet.Auto)]
    public static extern
    void sygLadSyg([MarshalAs(UnmanagedType.LPArray)] byte[] myArray);
    void sygLadSyg([MarshalAs(UnmanagedType.SafeArray)] byte[] myArray); 

我得到异常:

对 PInvoke 函数的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

我做错了什么?

第二个问题是传递位图。

function sygAnaliz(bitmapa: TBitmap): byte; stdcall;
  external 'awSygnat1.dll' name 'sygAnaliz';
 [DllImport("Delphi/awSygnat1.dll",
            CallingConvention = CallingConvention.StdCall,
            CharSet = CharSet.Ansi)]
        public static extern
        byte sygAnaliz(IntPtr bitmapPtr);
// and call itself
sygAnaliz(firstIMG.GetHbitmap());

我得到异常: 尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

这两个函数肯定是内存安全的,因为它们已经使用了几年,效果很好。也许我想念一些明显的东西?

【问题讨论】:

  • 对于数组,Remy's andwers 也允许你使用 bytes[1]:=6; Delphi 函数内部。

标签: c# delphi bitmap interop marshalling


【解决方案1】:

您没有使用 COM 安全数组,因此 UnmanagedType.SafeArray 将不起作用。

为了使用UnmanagedType.LPArray,您必须将您的Delphi函数改为:

procedure sygLadSyg(bytes: PByte); stdcall;
begin
  // use bytes as needed, but do not exceed 124 bytes...
end;

然后将您的 C# 声明更改为:

DllImport("Delphi/my.dll",
    CallingConvention = CallingConvention.StdCall)]
public static extern
void sygLadSyg([MarshalAs(UnmanagedType.LPArray, SizeConst=124)] byte[] myArray);

至于您的第二个问题,您的 Delphi 函数接受 VCL TBitmap 对象作为输入,但 C# 没有这个概念。它正在传递一个 Win32 HBITMAP 句柄,因此您需要相应地更改您的 Delphi 函数。它可以在内部创建一个临时的TBitmap 对象并将HBITMAP 分配给它的Handle 属性:

function sygAnaliz(bitmapa: HBITMAP): byte; stdcall;
var
  Bmp: TBitmap;
begin
  try
    Bmp := TBitmap.Create;
    try
      Bmp.Handle := bitmapa;
      // use Bmp as needed...
    finally
      Bmp.Free;
    end;
    Result := ...;
  except
    Result := ...;
  end;
end;

然后C#声明应该是:

[DllImport("Delphi/awSygnat1.dll",
    CallingConvention = CallingConvention.StdCall)]
public static extern
byte sygAnaliz(IntPtr bitmapPtr);

【讨论】:

  • 感谢您的回答。至于第一个问题,是的,我试过 void sygLadSyg([MarshalAs(UnmanagedType.LPArray)] byte[] myArray);,它没有用。我最终禁用了堆栈不平衡异常,现在程序继续进行,我认为它应该做的。至于位图,我没有 Delphi 源,所以我现在无法检查。我会联系作者,看看我们是否可以稍微修改一下。不过,很好的答案:)
  • @user 禁用堆栈不平衡 mda 是一个巨大的错误。你显然对你正在做的事情没有感激之情。雷米的回答是正确的,你应该接受。
  • @Remy procedure f(const bytes: MyType); stdcall; 也是一种选择
  • 好吧,没有冒犯的意思,伙计们。这只是我试图解决这个问题的最后几天。这不是我关闭的第一个异常(stackoverflow.com/questions/56642/loader-lock-error,这只是现在,因为我只想让那些 DLL 工作,稍后我想在更大的应用程序中使用它们)并且给出的答案对我没有帮助,因为这是我已经尝试过的场景。当我检查位图答案并且它有效时,我当然会将帖子标记为答案:)
  • 雷米写的很准确,你不可能做到他说的。
猜你喜欢
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多