Re: Marshal::StringToHGlobalAnsi and System.AccessViolationException
- From: Jeroen Mostert <jmostert@xxxxxxxxx>
- Date: Wed, 27 Feb 2008 22:48:12 +0100
Dilip wrote:
I have cross-posted this question to 3 newsgroups since I am not sure
exactly where it belongs (and some NG's have very less activity).
Apologies in advance for this. I have set the followup to the
dotnet.framework.interop NG but feel free to chage it as appopriate.
I have a question regarding converting a Managed System.String^ to
unmanaged const char*.
I inherited a code that does it like this:
String^ s = "00000";
LPCSTR str = static_cast<LPCTSTR>(const_cast<void*>(static_cast<const
void*>(Marshal::StringToHGlobalAnsi(s))));
Abominable. One cast should raise a flag. Three casts should raise a red alert. This is clearly the work of someone who didn't know what they were doing and just strung casts together until it appeared to work.
That said, this *does* happen to work, although it's unnecessarily cast-happy. It's equivalent to
char* str = static_cast<char*>(Marshal::StringToHGlobalAnsi(s).ToPointer());
char someStr[20];
strncpy_s(someStr, 19, str, 19);
This call is wrong. The second argument to strncpy_s is the *total* size of the destination, including room for the null terminator. This call tries to copy 19 characters plus null terminator into a buffer with a specified size of 19 bytes, which will not fit. This should be
strncpy_s(someStr, 20, str, 19);
or even better
strncpy_s(someStr, _countof(someStr), str, _TRUNCATE);
to copy all the characters that will fit. If truncation is not supposed to happen, then just leave it at
strncpy_s(someStr, _countof(someStr), str, strlen(str));
which will raise an error if the string does not fit.
someStr[19] = 0;Here's a much shorter and cleaner way of doing the same thing:
Marshal::FreeHGlobal(static_cast<IntPtr>(const_cast<void*>(static_cast<const
void*>(str))));
{
pin_ptr<const wchar_t> ps = PtrToStringChars(s);
size_t charsConverted;
wcstombs_s(&charsConverted, someStr, _countof(someStr), ps, _TRUNCATE);
}
This copies as much characters of "s" as will fit into the array "someStr", converting the characters from Unicode to ANSI along the way. It does not allocate additional memory, which it achieves by temporarily pinning the string.
Of course, depending on what you actually do with the string, copying to an array may be unnecessary in the first place.
--
J.
.
- Follow-Ups:
- Re: Marshal::StringToHGlobalAnsi and System.AccessViolationException
- From: Dilip
- Re: Marshal::StringToHGlobalAnsi and System.AccessViolationException
- From: Jeroen Mostert
- Re: Marshal::StringToHGlobalAnsi and System.AccessViolationException
- Prev by Date: Re: Marshal::StringToHGlobalAnsi and System.AccessViolationException
- Next by Date: Re: Marshal::StringToHGlobalAnsi and System.AccessViolationException
- Previous by thread: Re: Marshal::StringToHGlobalAnsi and System.AccessViolationException
- Next by thread: Re: Marshal::StringToHGlobalAnsi and System.AccessViolationException
- Index(es):
Relevant Pages
|