Conversion between managed class and unmanaged structure

  • Thread starter Thread starter zhphust
  • Start date Start date
Z

zhphust

I want to convert a object of a managed class to a unmanaged structure
that has the same member with that managed class. Can anybody tell me
how i can do it?
Thanks in advance.
 
As long as all of the structure parameters are value types you can just cast
the a pointer of managed structure to a pointer of the same unmanaged
structure, e.g.:

void GetUnmanagedLayout(IN ManagedStruct *pms, OUT UnmanagedStruct &ums)
{
ManagedStruct __pin* pPtr = pms;

memcpy(&ums, (PBYTE)pPtr, sizeof(ums));
OR
ums = *(UnmanagedStruct*)pPtr;
}
make sure to verify the compiler byte alignment ( #pragma pack... )

However, when the structure contain properties other then value types ( such
as arrays ) the memory layout of the managed struct will be different from
the layout of the same unmanaged struct ( as managed arrays are resembled by
'classes' rather then direct heap/stack pointers ) so direct conversion could
not be done, rather the struct to be accessed through unmanaged code could be
exposed through COMInterop ( which will impose a development time increase ).

Hope this helps...

Nadav
http://www.ddevel.com
 
Thanks for answering my question!
I think the scene that you have described is a little defferent from my
original needs.

The source type that I want to convert is a mananged gc object such as
__gc class User
{
public:
int user_id;
String *user_name;
};

Then, the target type that I want to covert to is a umanaged structure such as
struct User
{
int user_id;
char *user_name;
};

I do can use P/Invoke and unmanaged dll to realize the above scene in my
project, but I think if I can do this conversion with mixing managed code and
unmanaged code in VC++.NET instead of using P/Invoke, it will be great help
to shorten the development time.
 
Well, there are several problems I see here:
1. The managed class include a String* variable which is not a value type,
hence, simple unmanaged casting is not appropriate.
2. The managed class contains a String* variable while the unmanaged strict
contain char* variable, it is not possible to directly reference the String*
variable by the char* variable as managed strings are UNICODE e.g. 2 bytes
aligned in contrast to char* which is 1 bye aligned, converting a String* to
char*in this manner will require a W2A conversion AND memory copying which
may effect the performance of the application.

Resolution:
1. .NET doesn't provide direct memory access in the same manner C++ does (
this what makes it managed ) this is why managed strings are defined as
classes and not as direct memory pointers, so as long as there are reference
types in your class there is nothing realy you can do to have a direct
unmanaged access to your class.
2. using BSTR or USHORT* rather then char* in your unmanaged strict may
resolve the memory duplication issue ( later explained in details ).

Conclusion:
Direct reference of a managed class containing reference types to an
unmanaged pointer is not possible, rather I would suggest to replace the
char* of the unmanaged struct with USHORT* and to use the 'PtrToStringChars'
API to get direct string memory access ( this will resolve the memory copying
), the following snippet demonstrate what was just said:
#using <mscorlib.dll>

#include <vcclr.h>

using namespace System;

#pragma unmanaged

struct User
{
int user_id;
const unsigned short* user_name;
};

void PrintUser(User &u) {
wprintf(L"id: %i\nname: %s\n", u.user_id, u.user_name);
}

#pragma managed

__gc class CTest
{
protected:
String *user_name;
public:
System::Int32 user_id;
__property String* get_UserName() { return user_name; }
__property void set_UserName(String* value) { user_name = value; }
__property const System::Char* get_UserRawName()
{ return PtrToStringChars(user_name); }
};

int _tmain() {
CTest *pTest = new CTest();
const unsigned short __pin *pustmp = pTest->get_UserRawName();
User u = { pTest->user_id, pustmp };
PrintUser(u);
return 0;
}

Still this solution impose some limitations: the usage of 'pustmp' is
limited to the scope of it's stack frame, out of this stack frame it is not
Guaranteed that the value of 'pustmp' will be valid as the GC may move it, to
overcome this limitation the string buffer should be copied... Another thing
to keep in mind while pinning variables is that variables should not be
pinned for long periods of time, pinning variables for long periods of time
prevents the GC from moving managed blocks of memory which may cause a
Derogation of the GC and the application performance...

Hope this helps.
Nadav.
 
Back
Top