Re: Marshal::StringToHGlobalAnsi and System.AccessViolationException

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



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;
Marshal::FreeHGlobal(static_cast<IntPtr>(const_cast<void*>(static_cast<const
void*>(str))));

Here's a much shorter and cleaner way of doing the same thing:

{
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.
.



Relevant Pages

  • Re: Print Document && Wrapping
    ... everything that doesn't fit to print on a second page, ... you can use MeasureString to find out how wide your string is going to be when printed in a specified font. ... If the length exceeds the page width, you remove a character from the string and execute MeasureString again to find out how long the string is with one character less. ... I've done this and it is quite fast but if you find it to be inefficient, you can do a dicothomic search instead of removing characters one by one to find out the optimal length. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: string combination
    ... combination of letters of any inputted string? ... characters as a first character, and then print all the permutations ... void rotate(char *ptr, int len) ... void recurse_perms(char *str, char *ptr, int len) ...
    (comp.lang.c)
  • Re: Defacto standard string library
    ... The str* functions don't work properly and the mem* functions do. ... knife and you may damage the screw and you may bust your knuckles. ... Lots of string manipulation code never needs to find particular characters in a string. ... Plenty of useful string manipulation code written to deal with ASCII will work unchanged and correctly with strings containing UTF-8 multibyte characters. ...
    (comp.lang.c)
  • Printing problem
    ... I must create a routine to print a customer sales quote and having problem ... with a section where a rather big string must be devided into several lines ... and my problem is to calculate how many character from the big line will fit ... Is there a way to calculate how many characters will fit within a specific ...
    (microsoft.public.vb.general.discussion)
  • Request for comments for my parse-float
    ... parse floating-point numbers from a string, ... (defun empty-string-p (str) ... "Predicate for sign characters" ...
    (comp.lang.lisp)