ispiro
ispiro

Reputation: 27713

PCWSTR vs LPWSTR

It is my understanding (and please correct me if I'm wrong) that the only difference between them is whether the string might be modified by the called function. (PCWSTR , LPWSTR)

I am now trying to pass a string from C# to a function expecting a PCWSTR, but all I can find is [MarshalAs(UnmanagedType.LPWStr)]. Am I correct that that is fine? (Yes, it works. That, though, is not a proof that it's fine. Some things work but then cause memory leaks etc.)

Upvotes: 10

Views: 12522

Answers (2)

Hans Passant
Hans Passant

Reputation: 942247

PCWSTR is a time anachronism, dinosaur-and-humans movie style. Finding a 16-bit program that uses short pointers on a Unicode string is like finding a white elephant. Only the distinct between LPCWSTR and LPWSTR is meaningful.

The C in LPCWSTR is simply annotation for const, a C language keyword. It promises that the called function never modifies the string that you pass. Which is very important to know in that language, it is not safe to pass a string literal to a LPWSTR argument. That is very likely to crash the program when it tries to update the string and fails because the memory page is read-only.

And it matters when you pinvoke. Passing a System.String to a LPCWSTR argument is fine, strings are immutable in .NET so you'll get a guarantee that an interned string literal isn't going to get mangled. A very hard to diagnose problem. Using [MarshalAs(UnmanagedType.LPWStr)] explicitly should not be necessary in general, you'd use the CharSet.Auto property in the [DllImport] attribute and get the LPWStr marshaling for free.

But if the argument type is LPWSTR then you must pass a StringBuilder instead. With a sufficient Capacity to allow the native code to poke around in the builder buffer to write the string.

Upvotes: 20

Dirk
Dirk

Reputation: 10968

A function taking a PCWSTR parameter can't use that parameter to modify the characters of the string, unlike a function that takes a LPWSTR parameter. Each character of the string is stored as WCHAR.

UnmanagedType.LPWStr is the right marshalling type for such a string.

Upvotes: 3

Related Questions