Mic*_*tta 2 c# c++ com com-interop
我在使用COM传递指向本机代码的指针时遇到问题.我想在托管(C#)代码中构建一个字节数组,并将该数组传递给本机(C++)代码.我正在处理托管代码方面,我的同事拥有本机方面.请注意,我在托管方面更强大,而且我几乎一直在使用COM对象.
COM签名(简化)看起来像这样:
unsafe void DoSomething([In] byte* buffer, [In] uint length)
Run Code Online (Sandbox Code Playgroud)
我称之为:
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);
}
Run Code Online (Sandbox Code Playgroud)
在托管端调试,我看到打印出来的内存位置的数据(使用Visual Studio的内存视图).当我调试非托管端时,我也在该位置看到了正确的数据.但是,指针并没有指向正确的位置!它指向一个完全不同的内存位置.该位置包含我的数据的正确的第一个字节,但其余部分包含垃圾.然后,当然,发生了许多奇妙的崩溃.
所以,例如,我看到:
p)为0x1234567,0x1234567处的内存包含我文件的内容.buffer)是0x5678901,该位置的内存的第一个字节包含我文件的第一个字节,其余是垃圾.内存0x1234567包含我的文件的内容.我也试过自动封送:
void DoSomething([In] [MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.U1)]
byte[] buffer,
[In] uint length)
Run Code Online (Sandbox Code Playgroud)
...在管理端使用直字节数组; 同样的结果.
我已经尝试分配内存Marshal.AllocHGlobal,将数据复制到其中Marshal.Copy并将结果传递IntPtr给a byte*.结果相同.
我到底错过了什么?
这是一个32位进程.我尝试过小型(300B)和大型(10MB)缓冲区大小.C#3.5,VS 2010.
核心问题是您的COM方法不兼容自动化.字节*不明确.它可以表示通过引用传递的单个字节(C#中的ref字节),也可以表示通过值传递的数组指针(C#中的byte []).类型库无法表达差异.自动化要求您将数组作为SAFEARRAY传递.
当您使用C++程序中的方法时,您只需将指针传递给数组即可.但是,在Tlbimp.exe将类型库转换为互操作库之后,这会出错,互操作存根将声明为ref字节.这是您看到只复制一个字节的确切原因.
如果无法修复COM服务器,修复此问题会很痛苦.您将不得不使用ildasm.exe/out反汇编互操作库.然后编辑IL文件中的方法声明,然后将humpty-dumpty与ilasm.exe一起重新组合.使用一个小测试程序来了解IL应该编辑的确切方式.
| 归档时间: |
|
| 查看次数: |
1414 次 |
| 最近记录: |