An intereseting issue in mixed-mode application
A few definitions to start with:
Managed code: Code executing under the control of the CLR is called managed code. For example, any code written in C# or Visual Basic .NET is managed code.
Unmanaged code: Code that runs outside the CLR is referred to as "unmanaged code." COM components, ActiveX components, and Win32 API functions are examples of unmanaged code.
Users may have a mixed-mode application where a managed code is accessing an unmanaged code or vice-versa. There are three technologies which enable managed/unmanaged interaction:
1) Platform Invoke (P/Invoke)
2) COM Interop
3) C++ Interop (IJW)
I am writing about the third technology here. We should use C++ interop for wrapping complex unmanaged flat APIs, or for wrapping unmanaged flat APIs that are changing while managed code is under development. C++ interop allows direct access to unmanaged APIs—which requires no rewriting, just the inclusion of a header file. The wrapper is compiled using /clr compiler switch which generates mixed-mode native/managed output.
The header of native C++ code is included in the managed wrapper. This causes the native C++ code to get compiled as managed code. Sometimes this may cause problems.
One of such problems may happen when the application has some static or global objects. The life time of such objects is until module unloading happens. So these objects are destructed at the end, even after the CLR is shut down. To avoid any error, we should make sure that these objects are purely unmanaged. We should not have any global objects that use .NET. All managed objects should be destroyed before the CLR shuts down.
As I wrote earlier, native code gets compiled as managed when their headers are included in managed code. The native code may have global or static objects which become managed in this way. The destructor of such objects will be called after the CLR is shut down which causes BOOTUP_EXCEPTION_COMPLUS exception to be raised. The application will crash just before it exits.
To solve such issues, we should wrap the include statements of these native header files (which declare classes whoes global objects exist) in the managed C++ code as follows:
//Managed code file
//compile the native file as unmanaged:
#pragma managed(push, off)
#include <xyz.h> //The unmanaged code header.
#pragma managed(pop)
The above wrapper statements cause the compilation of class declared in “xyz.h” as unmanaged. This solves the issue. The application can have a global or static object of this class.
Comments
- Anonymous
July 09, 2010
Thank you very much! Really helped me!