从 ref ushort 获取字符串





0/5 (0投票)
2007年8月17日
2分钟阅读

18627
处理错误声明为 ref ushort 的字符串参数
引言
MSHTML 的 Microsoft PIA 包含许多方法签名,错误地将字符串参数声明为 ref ushort,导致它们无法使用。
本文解释了如何获取和设置错误声明为 ref ushort
的字符串。
背景
PIA(主互操作程序集)是供应商对某些 COM 对象接口的官方呈现。它已签名等等,因此您无法更改它。当 PIA 包含参数或编组提示的错误声明时,使用错误声明的方法几乎不可能。
您无法通过类型转换来规避这个问题。相关字符串声明为 POLECHAR
,它是指向以空字符结尾的 Unicode 字符数组的第一个元素的指针。Unicode 字符宽度为 16 位且无符号,您需要指向它的指针,因此为 ref ushort
。
您可以使用 tlbimp.exe
导入接口,然后更正它们。您所要做的就是将 "ref ushort" 替换为 "string"。但事情从来都不是那么简单。Webbrowser 控件使用 Microsoft PIA,并且 C# 强类型将您的声明和 PIA 等效项视为完全不同的东西。您可以显式类型转换,但您必须类型转换所有内容。这可行,但代码难以阅读且难以维护(我尝试过)。
因此,tblimp.exe
并没有完全出错,但无法直接将 ref ushort
类型转换为 string
,我们无法更改互操作程序集,也无法替换它。
现在一切都丢失了……或者不是。Marshal
类登场。
我们像这样获取字符串
//create a managed string and copy the content of the OLECHAR //string pointed at by lpwszBlah into this string string blah = Marshal.PtrToStringUni((IntPtr)lpwszBlah);
并且反过来(如果我们更改它)…
//lpwszBlah is a pointer, so we return a value by writing it to //global memory and putting a pointer to the new value into lpwszBlah //but first we free the old buffer Marshal.FreeHGlobal(lpwszBlah); lpwszBlah = Marshal.StringToHGlobalUni(blah);
关注点
大多数字符串编组方法都有 Unicode、ANSI 和 Auto 版本。Auto 根据底层平台选择 ANSI 或 Unicode 行为。在某些情况下,例如处理 COM,字符串类型与平台无关,这些调用的 Auto 版本将在旧平台上失败。例如,MSHTML 在所有平台上使用 POLECHAR,而 Marshal.PtrToStringAuto((IntPtr)lpwszBlah) 会在 Windows 9x 下将数据错误地解析为 ANSI 字符串。
Marshal 类本身就是一个有趣的焦点。您认为 Microsoft 如何执行所有神奇的转换?当然,您可以使用属性提示该过程,但迟早橡胶会与道路接触,通常 Marshal 会参与其中。Microsoft 非常周到地使这个非常方便的类可以直接访问,并且甚至偏离传统进行了文档记录。