Converting Between Native and Managed Types

Introduction

One of the most useful aspects of C++.NET is the ability to interface seamlessly with existing native code. To do this, you have to be able to convert between native memory and managed memory.

The garbage collector can be considered a seperate process that controls all memory in a .NET application and ensures that memory is released when it is no longer being used.

Because the memory in .NET is managed differently than in C++, you cannot access native memory using .NET safely, and you cannot safely access .NET memory in native C++.

To use managed memory in native code, you must copy the contents of the managed memory into native memory.

Equally, to use native memory in a .NET application, you must copy the contents of the native memory into managed memory.

There is an exception to this rule in the __pin keyword, which is covered later.

.NET Memory Conversion

Memory conversions are performed by use of the System::Runtime::InteropServices::Marshal::Copy method.

const int nLength     = 20;
BYTE *pbData          = new BYTE[nLength];
System::Byte abData[] = new System::Byte[nLength];

// unmanaged to managed
System::Runtime::InteropServices::Marshal::
        Copy(IntPtr((void *)pbData), abData, 0, nLength);

// managed to unmanaged
System::Runtime::InteropServices::Marshal::
        Copy(abData, 0, IntPtr((void *)pbData, nLength);

delete [] pbData;

The System::Runtime::InteropServices::Marshal::Copy class has various methods to copy managed to unmanaged memory and vice versa. See MSDN for more details.

The IntPtr class takes a void * pointer, and converts this to a managed pointer for .NET to use.

The __pin Keyword

Because .NET (garbage collected) memory is in effect controlled by a seperate process, it can change location at any time.

In C++.NET, the __pin keyword prevents the garbage collector from moving the memory until the pointer goes out of scope.

This gives native C++ the ability to directly access managed memory safely.

The above can therefore be alternatively performed the following way:

{
   const int nLength         = 20;
   BYTE *pbData              = new BYTE[nLength];
   System::Byte abData[]     = new System::Byte[nLength];
   BYTE __pin *pbManagedData = &(abData[0]);

   // from unmanaged to managed...
   ::memcpy(pbManagedData, pbData, nLength);

   // from managed to unmanaged...
   ::memcpy(pbData, pbManagedData, nLength);

    delete [] pbData;
}
// going out of scope releases the __pin

This is less efficient than the former method because it requires that the unmanaged 'memcpy' function be called from managed code.

Strings

Strings in .NET are held as unicode values, which are 2-byte characters.

Note: In non-UNICODE builds, the string is converted into 8-bit characters using the current system language's code page.

Managed to Native

String *psString = S"Hello";
__wchar_t __pin *wszString = ::PtrToStringChars(psString);

CString sString(wszString);    // uses the LPCWSTR constructor

Native to Managed

const CString sString = "Hello";
String *psString      = new String(sString);

This method uses the LPCWSTR constructor for String in UNICODE builds, and the LPCSTR constructor for String in non-unicode builds.

Conclusion

We have seen how to convert between managed and native memory, as well as how to convert strings from managed to native. These conversions are the backbone of being able to write your own wrappers so that .NET applications can use existing C++ code.

You can also use these conversions to interface with existing C++ libraries, or write your own interoperability wrapper for COM objects.



About the Author

David McClarnon

He first encountered Windows programming using Visual C++/MFC version 1.5 on Windows 3.11 a very long time ago. He is now a contract developer specialising in .NET/native interop with p/invoke.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • When individual departments procure cloud service for their own use, they usually don't consider the hazardous organization-wide implications. Read this paper to learn best practices for setting up an internal, IT-based cloud brokerage function that service the entire organization. Find out how this approach enables you to retain top-down visibility and control of network security and manage the impact of cloud traffic on your WAN.

  • Thanks to the Internet of Things (IoT), physical assets are turning into participants in real-time global digital markets. The countless types of assets around us will become as easily indexed, searched and traded as any online commodity. While some industries will be tougher to transform than others – those with physical limitations, such as manufacturing, will be harder to digitize – untold economic opportunities exist for growth and advancement. Our research shows this will create a new "Economy …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date