在COM对象编程中,经常会遇到需要与COM对象交互的情况。这些对象的接口通常通过PIA(Primary Interop Assembly)提供,它是COM对象接口的官方实现。然而,有时PIA中的参数声明可能是错误的,导致无法直接使用这些接口。本文将介绍如何正确地获取和设置被错误声明为ref ushort的字符串参数。
PIA是COM对象接口的官方实现,它是经过签名的,因此不能对其进行修改。当PIA中包含错误的参数声明或封送提示时,使用这些错误声明的方法几乎是不可能的。在这种情况下,不能通过类型转换来绕过这个问题。问题中的字符串被声明为POLECHAR,这是一个指向以null结尾的Unicode字符数组的第一个元素的指针。Unicode字符是16位宽的无符号字符,因此需要一个指向它的指针,即ref ushort。
可以使用tlbimp.exe工具来导入接口,然后更正它们。只需要将"ref ushort"替换为"string"。但事情并不总是那么简单。WebBrowser控件使用Microsoft PIA,而C#的强类型将声明和PIA等效物视为完全不同的东西。可以显式类型转换,但必须转换所有内容。这种方法虽然可行,但代码可读性差且难以维护(尝试过)。
可以使用Marshal类来获取字符串,如下所示:
// 创建一个托管字符串并复制OLECHAR的内容
string pointed at by lpwszBlah into this string
string blah = Marshal.PtrToStringUni((IntPtr)lpwszBlah);
如果改变它,那么反向操作如下:
// lpwszBlah是一个指针,所以通过将新值写入全局内存并将新值的指针放入lpwszBlah来返回值
// 但首先释放旧的缓冲区
Marshal.FreeHGlobal(lpwszBlah);
lpwszBlah = Marshal.StringToHGlobalUni(blah);
大多数字符串封送方法都有Unicode、ANSI和Auto版本。Auto根据底层平台选择ANSI或Unicode行为。在某些情况下,例如处理COM时,字符串类型是平台不变的,这些调用的Auto版本将在旧平台上失败。例如,MSHTML在所有平台上都使用POLECHAR,而Marshal.PtrToStringAuto((IntPtr)lpwszBlah)将在Windows 9x下错误地将数据解析为ANSI字符串。