gpt4 book ai didi

c# - COM 互操作传递错误的指针,只有一个字节的数据

转载 作者:太空狗 更新时间:2023-10-29 23:53:52 25 4
gpt4 key购买 nike

我在使用 COM 将指针传递给 native 代码时遇到问题。我想在托管 (C#) 代码中构建一个字节数组,并将该数组传递给 native (C++) 代码。我正在处理托管代码方面,而我的同事拥有 native 方面。请注意,我在托管方面要强大得多,而且我几乎一直在使用编写的 COM 对象。

COM 签名(简化)如下所示:

unsafe void DoSomething([In] byte* buffer, [In] uint length)

我这样调用它:

var arr = File.ReadAllBytes(@"c:\temp\foo.bar");
fixed (byte* p = arr)
{
// let's see what we're actually pointing at
IntPtr ip = new IntPtr(p);
Console.WriteLine(ip.ToInt32().ToString("x"));

interop.DoSomething(p, arr.Length);
}

在托管端进行调试时,我看到打印出的内存位置上我期望的数据(使用 Visual Studio 的内存 View )。当我调试非托管端时,我也在那个位置看到了正确的数据。但是,指针没有指向正确的位置!它指向一个完全不同的内存位置。该位置包含我数据的正确第一个字节,但其余部分是垃圾。然后,当然,会发生很多令人崩溃的坏事。

所以,例如,我看到:

  • 托管端:指针 (p) 为 0x1234567,0x1234567 处的内存包含我文件的内容。
  • 非托管端:指针 (buffer) 为 0x5678901,该位置内存的第一个字节包含我文件的第一个字节,其余为垃圾。 0x1234567 处的内存包含我的文件的内容。

我也尝试过自动编码:

void DoSomething([In] [MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.U1)]
byte[] buffer,
[In] uint length)

... 在托管端使用直接字节数组;同样的结果。

我已经尝试使用 Marshal.AllocHGlobal 分配内存,使用 Marshal.Copy 将数据复制到其中并传递生成的 IntPtr,转换为 byte*。相同的结果。

我到底错过了什么?

这是一个 32 位进程。我试过较小的 (300B) 和较大的 (10MB) 缓冲区大小。 C# 3.5,VS 2010。

最佳答案

核心问题是您的 COM 方法与自动化不兼容。一个 byte* 是不明确的。它可以表示通过引用传递的单个字节(C# 中的 ref 字节),也可以表示通过值传递的数组指针(C# 中的 byte[])。类型库无法表达差异。自动化要求您将数组作为 SAFEARRAY 传递。

当您使用 C++ 程序中的方法时,您将摆脱这种情况,您只需传递一个指向数组的指针。但是在 Tlbimp.exe 将类型库转换为互操作库之后,这就出错了,互操作 stub 会将参数声明为 ref 字节。这就是您只看到 一个 字节被复制的确切原因。

如果不能修复 COM 服务器,修复这个问题会很痛苦。您必须使用 ildasm.exe/out 反汇编互操作库。然后编辑 IL 文件中的方法声明,然后将 humpty-dumpty 与 ilasm.exe 放回一起。使用一个小测试程序来了解应该编辑 IL 的确切方式。

关于c# - COM 互操作传递错误的指针,只有一个字节的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8829479/

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