Implementing a Managed Interface in C++
Using Managed C++ for Platform Invoke
Less than a month ago I was certain I'd never have to write managed code in C++. With such a set of mind I didn't really care about the new features being added and improvements being made to managed C++ since the first Visual Studio .NET. Luckily there were people thinking otherwise and as a result this – often overlooked – member of the .NET family got better with every release and is actually quite nice in the 2005 version. Don't get me wrong – it still is C++ and you probably wouldn't want to use it if you could get away with C# or VB. But if platform invoke is giving you too many headaches you might want to take a look at it. It could be the easiest way to solve your problem.
To make this a little bit easier for those of you who haven't used C++ for some time and didn't bother to check managed C++ at all, I'll provide a small sample to help out with the beginner's problems I had when starting out.
In a situation like mine you'll usually want to write a class library to wrap the unmanaged calls for undisturbed use within your managed project. In my case I'll be implementing an interface but writing a standalone class is not much different.
The Header File
Let's start with the header file. You might remember that C++ requires the separation of class declaration from method definition, the former being done in a header (*.h
) file and the latter in a code (*.cpp
) file. I admit being a little bit spoiled by not having to do that any more in C#. Let's name our header MCPP.h
(feel free to guess what it stands for):
using namespace System;
namespace DamirsCorner
{
namespace Samples
{
namespace LateBinding
{
public ref class MCPP : IBind
{
public:
virtual String^ Together(String^ first, String^ second);
};
}
}
}
It looks like a hybrid between C++ and C# and one could argue that's what it actually is. I'd like to point out the following:
- The
using
directive has an additional keywordnamespace
. Also a double colon (static separator in C++) would be used to separate nested namespaces instead of a dot. You'll see this in the code file which follows. - To put your own code into a nested namespace, you'll have to actually nest the
namespace
declarations. Separating several of them with double colons won't work. - To declare a managed class, use the additional keyword
ref
. - Don't forget the different use of the
public
keyword for the members in C++ compared to C#. - The
^
character denotes a reference to a managed object (stored on the managed heap), separating it from unmanaged pointers (*
character). - Notice the interface
IBind
being implemented by the class. A standalone class wouldn't need this of course. Thevirtual
keyword in the method declaration would also be skipped in this case.
The Code File
This is it for the header file. Let's look at the code file now:
#include "MCPP.h"
using namespace System;
using namespace DamirsCorner::Samples::LateBinding;
String^ MCPP::Together(String^ first, String^ second)
{
return String::Empty;
}
It's pretty obvious the method doesn't really do anything but it's the skeleton we're focusing on at the moment. You should turn your attention to the following:
- The code file must
include
the header file it implements (i.e. defines its methods). To refresh your C++ knowledge: it's a good habit to use quotes for internal project header files and pointy brackets for external library header files. The compiler looks in the project directory first for the former and in the include directories first for the latter. It checks the other location if it doesn't find the file but it will work faster if you use the right one (not to mention that by doing it you're avoiding the problem of locating the wrong include with the same name). - You can notice the double colons as namespace separators as I mentioned before.
- The methods you're implementing are not within the class declaration any more. You already declared the class in the header file therefore you only set the method class membership here by prefixing its name with the class name and a colon, just like you were calling a static method.
There's a reason I used String
for parameter and return value type. While value types can be directly used in unmanaged code, reference types have to be correctly marshaled. But that's a complex enough topic to justify a separate posting. The only thing left for this one is to make the code above compile. Just start a new Class Library project in C++ (you'll find it in the CLR group) and paste the code to the right files. After you reference the assembly containing the interface used (similar to doing it in C#) the code should build successfully.