Introduction
The natural choice today for a programming language for writing a new piece of software in the Microsoft environment is C#. For various reasons, some parts of the project may be written in other languages (existing packages, third party, performance, etc.). In this short article, I'll suggest what seems to me like a good, easy to manage, alternative for interoperation between managed and unmanaged code.
The .NET Environment
Microsoft got jealous of Java and created its own virtual machine, the CLR. Compilation of code in C# generates a machine code suitable for this virtual machine. Microsoft went one step further so that the code of other languages, such as C++, compiles to the same machine language. It is possible therefore to call from a DLL or an executable in C# to a DLL in C++, and vise versa. Each team uses its preferred programming language and it all fits together in the linkage.
Managed Code vs. Unmanaged Code
Code that runs in the .NET environment is called a managed code. Code that runs as in old days is called unmanaged code. The "management" brings a lot of advantages such as "garbage collection" of memory that was allocated but will never be used again. The disadvantages of the "management" are lesser performance, and the difficulty to interact with existing libraries in unmanaged code.
IJW
Microsoft brings a friendly solution which exists to the best of my knowledge only for C++. The solution enables calling from managed code to unmanaged code and vise versa, It Just Works! The only limitation is that there will be no use of "managed" data types in the unmanaged code. Hence it is possible to pass basic data types such as int
, double
, and data types that were defined as "not managed". In order to use that feature, we'll create the new DLL, or executable, as a C++ project for CLR (managed), and then we'll surround unmanaged code with:
#pragma unmanaged
#pragma managed
Use Case Example and a Code Snippet
In a project, I defined some classes in C# and created a DLL to hold those. The classes were intended to present a configuration for a real-time program. We decided that the real-time loops and logic will be written in unmanaged C++ code. I've created another DLL which was written in C++ and was also using the CLR. That way the DLL written in C++ could reference the DLL written in C# and use the classes representing the configuration. The program itself wrapping everything was written in C#. Hence the program is familiar with the classes in the C# DLL. It passes them to the C++ DLL, which is also familiar with those classes. There is still one problem left. We need to translate "managed" data types to "unmanaged" data types, in order to call unmanaged code. The work involved here is either trivial or Sisyphean, yet it will be a no-brainer. There is another alternative, which is working with unmanaged data types throughout both the unmanaged and managed code. I suggest that explicit translation is more convenient and self explanatory and is done at the last moment on the border between managed code and unmanaged code.
Following is a code snippet:
*.h File (C++)
public ref class CConfig
{
public:
CConfig (int _a, String ^_str, double _d);
void doTheStuff ();
int m_a;
String ^m_str;
double m_d;
};
*.cpp File
#include <stdio.h>
#include <stdlib.h>
#include <vcclr.h>
#include <iostream>
void someMoreInManaged ()
{
Console::WriteLine("C++ Managed – someMoreInManaged");
}
#pragma unmanaged
void doTheStuff1 (int _a, double _d, const wchar_t* const _str) {
std::cout << "C++ unmanaged – doTheStuff1" << std::endl;
std::cout << _a << _std::endl;
printf_s("%S\n", _str);
std::cout << _d << _std::endl;
someMoreInManaged();
}
#pragma managed
CConfig::CConfig
(int _a, String ^_str, double _d) {
m_a = _a;
m_str = _str;
m_d = _d;
}
void CConfig::doTheStuff () {
Console::WriteLine("C++ Managed – doTheStuff");
pin_ptr<const wchar_t> wch = PtrToStringChars(m_str);
doTheStuff1 (m_a,m_d,wch);
}
History
- 15th April, 2009: Initial post