65.9K
CodeProject is changing. Read more.
Home

Using IJW in Managed C++

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (21 votes)

May 3, 2002

3 min read

viewsIcon

285563

A basic introduction to using IJW instead of P/Invoke in Managed C++. This is also the first CP article on IJW.

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.