Prologue
I have always loathed P/Invoke in an intense manner. I guess it's perhaps due
to the fact that I am a very simple human being and thus I naturally disliked
anything which was not simple. P/Invoke in my opinion was ugly and so
pathetically unnatural. These two facets made it an utterly complicated entity.
Then I came across these beautiful words by Nick Hodapp.
"IJW in C++ is syntactically easier than P/Invoke, and as I said, slightly
more performant." - Nick Hodapp, Microsoft
Two things struck me immediately after I read those words. The first one,
naturally was that there was no word called "performant" in the English
dictionary, though I could actually understand very clearly what Nick Hodapp had
meant by that word. The second more glaring point was that I didn't know what
IJW meant. Later on when I realized that IJW simply meant, "It just works", I
had this feeling for a few seconds that I was stuck in a world of lunacy. But
after I tried it out, I simply said aloud, "It just works". Because, it really
does work. And it's not ugly or unnatural like P/Invoke is. And as Nick Hodapp
said, it's slightly more performant.
Using IJW
All you do is to simply #include
the required C++ header file.
Of course there is always a danger that there will be several name clashes
between the definitions in the header file and the .NET framework classes and
their member functions. I found this out the hard way when I got 100s of
compilation errors. All of them simply said :- "error C2872: 'blahblahblah' :
ambiguous symbol". Now as you can assume, this was a most distressing situation
as far as I was concerned. It took my rather simple brain a couple of minutes to
figure out that, I had to include the header file before all my using
namespace
directives.
Unlike P/Invoke, where all the data marshalling between .NET types and native
types is done by the compiler, here we must do it ourselves. It's not a
complicated issue at all once you take a look at the
System.Runtime.InteropServices.Marshal
class in the framework.
Jolly nice class I tell ya, with jolly nice functions.
Without further t�te-�-t�te, let's see some sample code. In the tiny example
program listed below I shall show you how to create a managed class, which can
be instantiated from a managed block, and which uses IJW to call a native API
call. You'll see how much more nicer this looks like when compared to the foul
looking P/Invoke code.
Code Listing
#include "stdafx.h"
#using <mscorlib.dll>
#include <tchar.h>
#include <windows.h>
using namespace System;
using namespace System::Runtime::InteropServices;
public __gc class MsgBox
{
public:
MsgBox(String *str)
{
IntPtr ptrtxt = Marshal::StringToCoTaskMemUni(str);
MessageBoxW(0,(LPCWSTR)ptrtxt.ToPointer(),
L"IJW is cool",0);
Marshal::FreeCoTaskMem(ptrtxt);
}
};
int _tmain(void)
{
String *str;
str = "Nish was here";
MsgBox *m_msgbox = new MsgBox(str);
return 0;
}
I have used StringToCoTaskMemUni
which copies the string to an
unmanaged area in the heap. Once I have made my call, I must free the string
that has been allocated in the unmanaged heap area, because this will not get
garbage collected. Isn't it truly amazing that when IJW existed, a lot of us
were wasting our time with P/Invoke! Of course this is available only for
Managed C++ programmers. The poor C# and VB .NET guys will have to suffer the
P/Invoke monster as that's their only option.
I guess this is one very good reason for the use of Managed C++ ahead of C#.
I am also hoping that this is the first IJW article on CP or perhaps on any
non-Microsoft site. I guess I'll have to wait for Chris M to confirm that. I
also do hope that it has served it's simple purpose. Thank you.