Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Getting a string out of a ref ushort

0.00/5 (No votes)
17 Aug 2007 1  
Handling string parameters incorrectly declared as ref ushort

Introduction

The Microsoft PIA for MSHTML is riddled with method signatures that incorrectly declare string parameters as ref ushort, making them unusable.

This article explains how to get and set strings incorrectly declared as ref ushort.

Background

A PIA (primary interop assembly) is the vendor's official rendering of the interfaces of some COM object(s). It's signed and so forth, so you can't alter it. When a PIA contains incorrect declarations of parameters or marshalling hints, it can be nigh impossible to use the incorrectly declared methods.

You can't dodge the problem with typecasting. The strings in question are declared as POLECHAR, which is a pointer to the first element of a null terminated array of unicode characters. A unicode character is 16 bits wide and unsigned, and you need a pointer to it, hence ref ushort.

You could use tlbimp.exe to import the interfaces and then correct them. All you have to do is replace "ref ushort" with "string". But nothing is ever that easy. The webbrowser control uses the Microsoft PIA and C# strong typing treats your declarations and the PIA equivalents as totally different. You can explicitly typecast, but you'll have to typecast everything. This works, but the code is illegible and unmaintainable (I tried).

So, tblimp.exe hasn't exactly got it wrong but there's no way to directly typecast a ref ushort to a string, and we can't alter the interop assembly, and we can't replace it.

All is now lost... or not. Enter the Marshal class.

We get the string like this:

//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);

And going the other way (if we change it)...

//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);

Points of Interest

There are unicode, ANSI and Auto versions of most of the string marshalling methods. Auto selects ANSI or unicode behaviour depending on the underlying platform. In some cases, such as dealing with COM, the string type is platform invariant and the auto versions of these calls will fail on legacy platforms. For exampe, MSHTML uses POLECHAR on all platforms, and Marshal.PtrToStringAuto((IntPtr)lpwszBlah) would incorrectly parse the data as an ANSI string under Windows 9x.

The Marshal class is a point of interest all on its own. How do you think Microsoft does all that wonderful magic conversion? Sure, you hint the process with attributes, but sooner or later the rubber hits the road, and generally Marshal is involved. Microsoft has very thoughtfully made this incredibly handy class directly accessible, and in a departure from tradition even documented it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here