How to convert from managed to unmanaged (and viceversa) byte arrays and strings???

B

Bob Rock

Hello,

converting from the managed to the unmanaged world (and viceversa strings)
and byte arrays is something I do often and I'd like to identify the most
correct and efficient way to do it.
Also, I was wondering could there be issues in not making copies when
converting??? I was thinking, when "pointing" to the same data with both
managed and unmanaged strings/arrays couldn't there be issues such as the
garbage collector trying to reclaim memory that may not be freed (read only
memory of global unmanaged arrays and strings) or should not be yet freed
(managed strings also pointed by unmanaged string pointers)??? Should I then
always be making copies???


Bob Rock
 
W

William DePalo [MVP VC++]

Bob Rock said:
converting from the managed to the unmanaged world (and viceversa strings)
and byte arrays is something I do often and I'd like to identify the most
correct and efficient way to do it.
Also, I was wondering could there be issues in not making copies when
converting??? I was thinking, when "pointing" to the same data with both
managed and unmanaged strings/arrays couldn't there be issues such as the
garbage collector trying to reclaim memory that may not be freed (read only
memory of global unmanaged arrays and strings) or should not be yet freed
(managed strings also pointed by unmanaged string pointers)??? Should I then
always be making copies???

"Essay" questions are hard to do in a newsgroup post. :)

That said, if you have a managed string s and you need to pass a pointer to
its constituent characters, I think that this is the way to go:

wchar_t __pin *pStr = PtrToStringChars(s);

In case you don't know, the __pin modifier "pins" the string in memory
during the time that the pointer is in scope to keep the GC at bay.

Now bytes are the same on both sides of the .Net fence, so you won't find an
equivalent to PtrToStringChars(). You can simply pin a pointer.

If you find yourself doing much "interop" you might want to peruse the book
"Essential Guide to Managed Extensions for C++" (ISBN: 1-893115-28-3). It's
authors, Challa and Laksberg, come from inside the big house. :)

Regards,
Will
 
B

Bob Rock

"Essay" questions are hard to do in a newsgroup post. :)
That said, if you have a managed string s and you need to pass a pointer to
its constituent characters, I think that this is the way to go:

wchar_t __pin *pStr = PtrToStringChars(s);

In case you don't know, the __pin modifier "pins" the string in memory
during the time that the pointer is in scope to keep the GC at bay.

Now bytes are the same on both sides of the .Net fence, so you won't find an
equivalent to PtrToStringChars(). You can simply pin a pointer.

If you find yourself doing much "interop" you might want to peruse the book
"Essential Guide to Managed Extensions for C++" (ISBN: 1-893115-28-3). It's
authors, Challa and Laksberg, come from inside the big house. :)

Regards,
Will

Hello,

I found an article that well describes the string to char*, CString and
wchar conversion:

http://support.microsoft.com/default.aspx?scid=kb;EN-US;311259

Is char* __gc[] the same as string???

Will, if I convert a global unmanaged string to managed without making a
copy (having both point the same memory area) first or later the GC will try
to reclaim a memory resource that may not be freed .... this will probably
cause an exception. Am I mistaken??? I suppose in this case a copy must
necessarily be made.

Bob Rock
 
G

Guest

You can stop the GC from cleaning memory by using a pin pointer. As long as that variable points to the string, the GC won't move or cleanup that memory. This line

wchar_t __pin *pStr = PtrToStringChars(s)

Creates a pinned pointer. As long as that variable doesn't change it should be safe to read the memory. You do have to watch out if the pointer is used avter the variable (pStr above) goes out of scope. For example

class U
public
wchar_t* ptr


void set_ptr(U* u)
String* str = "hello"
wchar_t __pin * pStr = PtrToStringChars(str)

U->ptr = pStr
cout<<U->ptr<<endl; // Memory access error, the string is no longer pinned


void get_ptr(U* u)
cout<<U->ptr<<endl; // Memory access error, the string is no longer pinned


void (test)
U u
set_ptr(&u)
get_ptr(&u)


So, when assigning an unmanaged pointer as a static variable or a class member variable it is a better idea to copy it. When you are just gonig to use it within the scope of the function, you can use the pinned pointer.
 
B

Bob Rock

mccoyn said:
You can stop the GC from cleaning memory by using a pin pointer. As long
as that variable points to the string, the GC won't move or cleanup that
memory.

I don't seem to be able to explain myself properly.
Ok, using a pin pointer prevents the GC from reclaiming the memory. But the
problem is, first or later the CG WILL try reclaiming it. Right???
Now, consider this situation: I have a global unmanaged unicode string such
as the following:

tchar* myString = "This is my string";

Now, global strings such as the following are keep (if I'm not mistaken) in
a read-only memory area. Now, consider what may happen if a managed string
is made to use that same exact unicode string instead of making a copy.
First or later the GC will try to reclaim that space, which is read-only and
may not be reclaimed. The consequence is obvious. Am I correct in saying
that in such situations I should always make copies when converting to a
managed string???

Bob Rock
 
W

William DePalo [MVP VC++]

Bob Rock said:
Is char* __gc[] the same as string???

Well, to paraphrase a former president it depends on what you mean by
'string'. <g>

Usually when one says 'string' in a .Net context, one refers to the class
named System::String.

On the other hand, 'strings' in C are null terminated arrays of characters,
so in some sense what you describe is the managed analog of C 'strings'.
Will, if I convert a global unmanaged string to managed without making a
copy (having both point the same memory area) first or later the GC will try
to reclaim a memory resource that may not be freed .... this will probably
cause an exception. Am I mistaken??? I suppose in this case a copy must
necessarily be made.

What kind of 'strings' are we talking about? Why not just create a managed
System::String from your character array and be done with it?

Regards,
Will
 
G

Guest

Thats right, but I don't think it is possible. When you assign a tchar* to a String* you end up with a function call that does the copying automatically.

tchar* myString = "This is my string";
String* str = myString;

The above code will make a copy of myString automatically. This copy will be managed by the String class and cleaned up by the GC, leaving the original myString alone. I don't know of any way to assign a __gc pointer the value from a __nogc pointer, which would lead to the problem you described. Therefore, it is always necesarry to copy the string when going from unmanaged to managed.
 
B

Bob Rock

Is char* __gc[] the same as string???
Well, to paraphrase a former president it depends on what you mean by
'string'. <g>

Usually when one says 'string' in a .Net context, one refers to the class
named System::String.

On the other hand, 'strings' in C are null terminated arrays of characters,
so in some sense what you describe is the managed analog of C 'strings'.

What kind of 'strings' are we talking about? Why not just create a managed
System::String from your character array and be done with it?

Regards,
Will

I've seen functions request parameters of the type char* __gc[]. I don't
know what they are ... I was asking if when I find such parameter types I
can pass in string arguments.

Bob Rock
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top