Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# COM互操作传递错误的指针,只有一个字节的数据_C#_C++_Com_Com Interop - Fatal编程技术网

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

C# COM互操作传递错误的指针,只有一个字节的数据,c#,c++,com,com-interop,C#,C++,Com,Com Interop,我在使用COM传递指向本机代码的指针时遇到问题。我想在托管(C#)代码中构建一个字节数组,并将该数组传递给本机(C++)代码。我负责托管代码端,我的同事负责本机端。请注意,我在托管方面的能力更强,而且我几乎一直在使用编写的COM对象 COM签名(简化)如下所示: unsafe void DoSomething([In] byte* buffer, [In] uint length) 我这样称呼它: var arr = File.ReadAllBytes(@"c:\temp\foo.bar");

我在使用COM传递指向本机代码的指针时遇到问题。我想在托管(C#)代码中构建一个字节数组,并将该数组传递给本机(C++)代码。我负责托管代码端,我的同事负责本机端。请注意,我在托管方面的能力更强,而且我几乎一直在使用编写的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);
}
在托管端调试时,我会看到在内存位置打印出来的预期数据(使用VisualStudio的内存视图)。当我调试非托管端时,我也会在该位置看到正确的数据。但是,指针没有指向正确的位置!它指向一个完全不同的内存位置。该位置包含正确的数据的第一个字节,但其余部分为垃圾。然后,当然,发生了很多奇妙的粗俗的坏事

例如,我看到:

  • 托管端:指针(
    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
传递到
字节*
。同样的结果

我到底错过了什么

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

您是否尝试过:

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

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

当你从C++程序中使用方法时,你只需要传递一个指向数组的指针。但是,当Tlbimp.exe将类型库转换为互操作库后,互操作存根会将参数声明为ref byte。这正是您只看到一个字节被复制的原因


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

是的,然后再试一次。相同的结果(第一个字节正确,其余为垃圾)。验证
length
是否正确传递和接收。不过,谢谢。这正是我们下一步要尝试的:更改接口以使用SAFEARRAYs。我会告诉你事情的进展。是的,就是这样。另外,封送处理代码要简单得多/根本不存在。这是一篇旧文章,但您几分钟前刚刚链接到它。我想知道,另一种解决方案是编写一个小的CLI/C++存根来代替interop包装器吗?技术上是的,您可以包含生成的.h文件。然而,这并不能使组件更容易使用,在本地C++中COM代码并不十分美观。