Intro to Managed C++, Part 2: Mixing Managed and Unmanaged Code
Pages: 1, 2
Making Your Classes Managed
As I have stated previously, when native C++ code is recompiled with /clr, the
classes don't automatically become managed and are marked __nogc for the
reasons I cited. If your class does meet the requirements of the CLR, however,
you can make your class managed by marking it with the __gc modifier to
indicate that it is a garbage-collected class, or the __value modifier to
indicate that it is a CTS value type.
Embedding Unmanaged Types in Managed Classes
What if your class cannot be made managed by adding the __gc or __value
modifiers? You may have code that uses templates or multiple inheritance. You
may have code that uses inline assembly to reuse the functionality from
something you would usually inherit from that class. For obvious reasons
outlined earlier, you cannot inherit a managed class from an unmanaged one, and
vice versa. So what do you do if you want to reuse the functionality? For
problems like this, the general solution is to either "aggregate" or "embed a
pointer." Without going into a lot of low-level details, aggregating an
unmanaged class within a managed one causes a lot of problems, and the compiler
cannot convert an object from the fc heap to a non-GC reference. The way to do
this is to embed a pointer to an unmanaged type within the managed class. It
looks something like this (a contrived example):
#using <mscorlib.dll>
using namespace System;
#include <string>
__nogc class Container
{
int value_;
public:
Container() : value_(0) {}
void SetValue(int *val) { value_ = *val;}
const int& GetValue() { return value_; }
};
__gc class ManagedContainer
{
Container* pContainer;
public:
ManagedContainer()
{
pContainer = new Container();
}
void SetValue(int val)
{
int someValue = val;
pContainer->SetValue(&someValue);
}
~ManagedContainer()
{
delete pContainer;
}
};
void main()
{
ManagedContainer *mc = new ManagedContainer();
int someValue = 42;
mc->SetValue(someValue);
System::Console::WriteLine("The value is ",
someValue.ToString());
}
In this solution, I create an embedded pointer to the the unmanaged class type
Container inside ManagedContainer and control it explicitly. Will this code
work? Perhaps sometimes, but there is a big problem with the code as it stands.
Pinning Pointers
The problem is that the CLR, in its GC, moves object references around. This
is not a problem until such a reference is passed to an unmanaged function or
used in an unmanaged object. The CLR has no way to keep track of the reference
once it transitions to unmanaged code. So in order to prevent the value from
getting corrupted, we need to "pin" the pointer using the __pin keyword:
#using <mscorlib.dll>
using namespace System;
#include <string>
__nogc class Container
{
int value_;
public:
Container() : value_(0) {}
void SetValue(int *val) { value_ = *val;}
const int& GetValue() { return value_; }
};
__gc class ManagedContainer
{
Container* pContainer;
public:
ManagedContainer()
{
pContainer = new Container();
}
void SetValue(int val)
{
int someValue = val;
int __pin* pinnedInt = &someValue;
pContainer->SetValue(pinnedInt);
}
~ManagedContainer()
{
delete pContainer;
}
};
void main()
{
ManagedContainer *mc = new ManagedContainer();
int someValue = 42;
mc->SetValue(someValue);
System::Console::WriteLine("The value is ",
someValue.ToString());
}
This type of approach leads to the ability to wrap your C++ code with managed wrappers, enabling your C++ code to be used from other managed languages like C# and VB.NET. I will explore more of this in detail, in the next article of this series.
Now, what if we want to go the other way? That is, use managed types from unmanaged code?
Using Managed Types from Unmanaged Code
Managed types cannot directly be used from unmanaged types. This is again
related to the fact that the CLR must keep track of object references to implement
garbage collection. What if we did want to use an object reference in an unmanaged
type? The CLR provides a type, System::Runtime::InteropServices::GCHandle, that
treats object references as integers from unmanaged code. The technique for
using this function is quite simple: call GCHandle::Alloc() to generate a handle
and GCHandle::Free() to free it.
However, this pattern can get quite messy, so there is a better way. In the file
gcroot.h, the VC++ team has provided a smart pointer, called gcroot<>, to
simplify the use of GCHandle in unmanaged types. With this template, we are
able to use a System::String in an unmanaged class, like so:
#using <mscorlib.dll>
#include <vcclr.h>
using namespace System;
class CppClass {
public:
gcroot<String*> str; // can use str as if it were String*
CppClass() {}
};
int main() {
CppClass c;
c.str = new String("hello");
Console::WriteLine( c.str ); // no cast required
}
What's Next?
In this article, I have only scratched the surface of what's possible. The next step is to further look at what IJW accomplishes and where it falls short, and how to make functions managed, how to make your data managed, and how to write managed wrappers around unmanaged functions.
Sam Gentile is a well-known .NET consultant and is currently working with a large firm, using Visual C++ .NET 2003 to develop both unmanaged and managed C++ applications.
Return to ONDotnet.com
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 27 of 27.
-
Managed C++ with Unmanaged C++
2007-04-04 22:46:10 mugaland [Reply | View]
Because of performance reasons I did not re-write my program (using intense interative vector / matix calculations) in C#. Instead, I ported it to an MFC DLL and wrote the GUI in C# windows forms. Using PInvoke I connect the two up using an intermediate C# managed DLL. With the help of your article I think I can eliminate the need for the intermediate DLL. I just need to use the InteropServices from within C++. The fact that managed C++ and unmanaged C++ can exist in the same file is great.
Thanks,
Frank Neubecker
-
nice article
2006-03-12 11:55:58 himanshuabc [Reply | View]
initially i also faced much trouble to understand the basics of the .net stuff ..
then i read this wonderful article . . must c for every .net novice
http://codemaster.wordpress.com/2006/02/10/managed-code-vs-unmanaged-one/
-
Correction: Inheriting from unmanaged type
2005-08-04 01:57:00 Chanveda [Reply | View]
Hello Sam,
Thanks for the good article yet again. Please let us know when can we expect your third article.
Also , meanwhile I have a challenging scenario for all those hungry techies. I need to extend an existing UNManaged type (A, extended as B), so that It operates on the Managed type(C). The extended Type (B) will again be used by another UNManaged class(D).
The issue here is the type (D) should always be UNManaged. I can always extend A in C++ provide wraper and use but Given MC++ and .NET world. Why should I use plain C++?
Can my MC++ class implement Unmanaged Interface ?
Can the unmanaged class use the MC++ class (that implements an unmanaged interface) as a normal unmanaged class ?
IF NOT what is the solution to this problem ??? Think...
-
Inheriting from unmanaged code
2005-08-04 01:53:35 Chanveda [Reply | View]
Hello Sam,
Thanks for the good article yet again. Please let us know when can we expect your third article.
Also , meanwhile I have a challenging scenario for all those hungry techies. I need to extend an existing UNManaged type (A, extended as B), so that It operates on the Managed type(C). The extended Type (B) will again be used by another UNManaged class(D).
The issue here is the type (C) should always be UNManaged. I can always extend A in C++ provide wraper and use but Given MC++ and .NET world. Why should I use plain C++?
Can my MC++ class implement Unmanaged Interface ?
Can the unmanaged class use the MC++ class (that implements an unmanaged interface) as a normal unmanaged class ?
IF NOT what is the solution to this problem ??? Think...
-
Unmanaged to managed c++
2005-05-30 01:14:49 lubo [Reply | View]
Hello!
I want to make a web service in .NET. My code is unmanaged c++. It is not a simple application, but a big one. I want to make a web service which uses managed extensions for c++. The code has to be transformed to managed before I can make web service.
I know about those three methods,IJW, Pinvoke and classwrapper. Which of those methods works best and which should I use?
Eddi!
-
c++ threads using .net libraries
2004-02-12 12:31:05 lukedickens [Reply | View]
At the moment I am having big problems trying to program threads in C++. I want to use the functionlity that .net offers me, but find when I call the threadstart constructor it tells me that I "cannot create a delegate handler...from a non-member function or a memeber of an unmanaged class". I've tried the pragma statements and _gc to prefic my class name but this diesn't work either.
Am I barking up the wrong tree or am I just missing one salient point?
Cheers for the helpful little site by the way.
Luke
-
Object browsing
2003-12-05 07:41:39 anonymous2 [Reply | View]
Dear Sam,
This is a great article. I have a question for you regarding object browsing issue. I wrapped one of my MFC projects by Managed C++ and it works well. When I attempt to watch the assembly generated by MC++ in .NET environment, I see some other stuff added to the assembly by .NET and they're visible through objetc browser. Is it possible to make an MC++ assembly as clean as C# assemblies? I meant how we can prevent the assembly to expose the unnecessary info in the object browser?
Thank you
Arash
-
Specialized C++ DLLs Too?
2003-08-05 10:31:40 anonymous2 [Reply | View]
Can an ISAPI filter written in C++ call managed code? I'd like an ISAPI filter that writes into a .Net Remoted object. Is this possible?
-
base type array problems
2003-07-24 02:08:56 anonymous2 [Reply | View]
Can anybody shed some light on my little problem?
I am trying to build a manged c++ dll.
When I try the code:
double *d = new double[10];
or any other base type, the code compiles, but will not link, erroring with unresolved symbols or tokens for 'new' and 'delete'
If I try this building an exe, the linker is fine. The code appears to reside in LIBCMTD, which - unfortunatly is the start-up code, and so requires a 'main' function.
Has anybody seen this before, and how can I fix it?
Cheers,
Dave -
base type array problems
2003-09-03 03:56:50 anonymous2 [Reply | View]
Try this...
To convert the managed DLL to mixed mode
Link with /NOENTRY. In Solution Explorer, right-click the project node and click Properties. In the project's Property Pages dialog box, click Linker, and then click Command Line. Add this switch to the Additional Options field.
Link msvcrt.lib. In the project's Property Pages dialog box, click Linker, and then click Input. Add msvcrt.lib to the Additional Dependencies property.
Remove nochkclr.obj. On the Input page (same page as previous step), remove nochkclr.obj from the Additional Dependencies property.
Link in the CRT. On the Input page (same page as previous step), add __DllMainCRTStartup@12 to the Force Symbol References property.
-
some questions
2003-07-01 08:32:30 barriegreen@msn.com [Reply | View]
great article - as usual ;).
I need to wrap a com object by mc++. and have chosen to do it using the atl helpers CComptr et al, if these helper are in headers are they converted to managed (__nogc) classes ? and if so presumably that means no thunking is taking place (unless the atl code calls out to other stuff)?
-
managed C++ example
2003-06-25 06:46:47 anonymous2 [Reply | View]
Hi Sam.
Thanks for sharing your knowledge with us.
I understand the general concepts and few of the specific ones, but that is not enough for implementing a managed code invoking unmanaged code.
A lot of unmanaged C++ code is found in DLLs that were written by external companies, thus the code in the dll cannot be modified.
Can you refer me to an example of a managed C++ class that instantiates a class that is found in a DLL ?
I would appreciate if the managed class would invoke methods of the unmanaged class that is found in the DLL.
Thanks.
-
Exception handling in mixed mode
2003-04-30 06:21:38 anonymous2 [Reply | View]
Terrific article Sam,looking forward to the next one. Could you spare a few words about exception handling (& cleaning up) when using mixed mode (unMC/MC).
Thanks.
SBC
-
Calling MFC from .NET
2003-04-20 23:36:00 anonymous2 [Reply | View]
My employeer has a 1 milion+ code lines MFC Client/Server program. There are clear (more or less) separation between GUI and DB classes. We want to be able to mantain a unique set of DB classes and share them between .NET (ASP .NET) and C/S (there are 400+ clients to mantain). It's best to recompile them with /clr or to wrap all classes with proxy managed wrappers?
-
Pinning a stack variable?
2003-04-10 10:47:39 anonymous2 [Reply | View]
Is it really necessary to pin an int before passing a pointer to it to unmanaged code here:
void SetValue(int val)
{
int someValue = val;
int __pin* pinnedInt = &someValue;
pContainer->SetValue(pinnedInt);
}
Isn't someValue a "value" type? In this case doesn't this value type live on the stack with no danger of moving? What is the point of pinning something that cannot move?
-Bern McCarty
-
great article !
2003-03-17 03:36:34 anonymous2 [Reply | View]
Sam, great article you wrote - it clarified a lot :) thanx
-
calling a C# function in a C++ program
2003-03-13 08:01:19 anonymous2 [Reply | View]
Dear Sam,
After reading the first article in the series, I left a comment there. This is really sort of a repeat of the same question. You mentioned at the end of this second article how to use managed C# in an unmanaged C++ ( or rather MC++, instead). I'm afraid that I'm still not very clear about how to exactly call a C# function (let's say SomeFunc()) in a MC++ wrapper class that I generate for my existing traditional C++. I simply want the two pieces to communicate!
Thank you very much for all your ideas!
-
Error with example
2003-03-05 19:14:50 anonymous2 [Reply | View]
I get the following error when I try to compile the example with mixed managed & unmanaged code.
cl.exe /clr /Zi mixed_case1.cpp
Microsoft (R) C/C++ Standard Compiler Version 13.00.9466 for .NET Framework
Copyright (C) Microsoft Corporation 1984-2001. All rights reserved.
mixed_case1.cpp
mixed_case1.cpp(4) : fatal error C1083: Cannot open include file: 'string': No such file or directory -
Error with example
2003-05-09 12:08:35 anonymous2 [Reply | View]
I ran into the same problem. I think what may be the case is that the SDK has these header files missing, where as the Visual Studio environments do not. That is a shame. -
Sam - Not shipped with .NET
2003-05-09 12:16:44 anonymous2 [Reply | View]
As I answered him in email, those header files like string and such are normal, ordinary C++ header files that have nothing to do wth .NET. Of course, they would not ship with a *free* .NET SDK. They ship with a pay C++ compiler as expected.
That is teh point of the sample - to combine ordinary unmanaged C++ you have before .NET came around with managed code.
--Sam Gentile
-
No error
2003-03-07 13:07:11 samgentile [Reply | View]
This is no error with the sample. I just re-compilled to make sure:
----- Rebuild All started: Project: Mixed2, Configuration: Debug Win32 ------
Deleting intermediate files and output files for project 'Mixed2', configuration 'Debug|Win32'.
Compiling...
Mixed2.cpp
AssemblyInfo.cpp
Generating Code...
Compiling resources...
Linking...
Build log was saved at "file://c:\Documents and Settings\Sam Gentile\My Documents\ORielly\Mixed2\Debug\BuildLog.htm"
Mixed2 - 0 error(s), 0 warning(s)
---------------------- Done ----------------------
Rebuild All: 1 succeeded, 0 failed, 0 skipped
String is the C++ Standard version of the String class as opposed to <string.h> which is the "old version. You either have something wrong with the way your VS.NET C++ directories are set up or its something with V1 of VS.NET. I am using VS.NET 2003 (Everett). I can see if I can did up an old copy of V1 but it should work the same way.
It's there for me:
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include
I just checked and it's there in VS.NET 1.0 too. You need to set up your directories correctly:
C:\Program Files\Microsoft Visual Studio .NET\Vc7\include
-
Why C#?
2003-03-05 14:34:52 anonymous2 [Reply | View]
In your article you suggest more than once the idea of porting to C#. Why? Why not just leave everything in managed/unmanaged C++, or even just managed C++? What is with the emphasis on C# everywhere? -
Why C#?
2003-03-07 12:56:51 samgentile [Reply | View]
Good question. The issue is accessibilty from managed code. I have no problem leaving everything in MC++ but there are hordes of .NET programmers who inist on C# or VB and believe it or not call C++ and MC++ "dead" languages in the face of the CLR-) There may be "consumers" of said MC++ code that want to access that code from C# or VB.NET so I show how to do it.
Also, previous to Everett, there was no forms designer in VS.NET so it made sense to "port" the C++ code to managed and then use C# to quickly write up the UI because of its WinForms Visual Designer and then call from it to the MC++ code.
Its not me thats pushing C#. Its Microsoft. -
Why C#?
2008-02-03 06:41:10 ailyag [Reply | View]
Hello everybody!
I've got the concept you discuss.
But I have difficulties with using C++ managed DLL in C#.
There is no problem call just a funtion from DLL by declaring as follows:
[DllImport("CFS01.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern MyClass unmanagedMethod(float x, float y);
But I have difficulties in working with the instance of managed class in C#. I cann't call the member functions of class without declaring its body.
In my DLL I have managed class which wraps the unmanaged one and operates with it.
How should I adapt my managed class for my application?
How should I make visible my managed class with all its member functions without declaring?
Can you show a simple example of similar situation solved?
I guess that it may be the configuration problem.
Thank you for help!






In your example, what would it changed if the passed argument was a char instead of a char *?
Would you still need the pin pointer?
Thanx,
--mike