Using MC++ to wrap ICorDebug for .NET 1.1

MDbg and the managed wrappers around ICorDebug only work on .NET 2.0 (VS2005). I previously discussed why they won't work on 1.1. One workaround to access ICorDebug from managed code in .NET 1.1 is to use MC++. In general, MC++ can be extremely useful for gluing managed and unmanaged code together.

Using MC++ :
MC++ will let you easily create a bunch of real managed objects that wrap the com-classic ICorDebug. This lets you control exactly how you're using ICorDebug, including how you're using IUnknown, and thus work around the the issues with COM-interop on ICorDebug in 1.1.

This beats out alternative ideas such as:
- creating your own COM-object to wrap ICorDebug and then using COM-interop to import that.
- using a lot of P/ invokes and native wrappers to access ICorDebug.
Both of these involve larger wrapper layers. Using MC++ here lets you avoid an extra component, and COM-interop altogether. We use MC++ for the native disassembly view in the SDK MDbg (mdbgdis.dll).

Fitting into application model:
I think the MC++ model here fits well into many Application's models:
1. Debuggers commonly wrap ICorDebug objects with their own classes to add additional functionality. (MDbg, VS, Cordbg all do this). Thus you can just make those wrappers be in MC++.
2. In a GUI app, you're going to have some STA UI thread that needs to make a cross thread call to access ICorDebug (which is MTA) and then get the data back to the UI thread to to do stuff like fill out some listbox for a callstack with frames. This sets up a natural boundary. The code that fills out the listbox can just be written in MC++. Or you could have some small MC++ glue to just read the data from ICorDebug and then give it back to some C# that actually fills out the listbox. The rest of the GUI can be some managed code, such as winforms app.

One testimony that it works:
Claudiu Codreanu (from Starlims) tried out this technique and found it to work very well.

Code examples:

Here's an example of part of a MC++ class wrapper for ICorDebugThread. It's using the new VS2005 MC++ syntax, but you can do the same things with the old VS2003 MC++ syntax.

 
// Managed MC++ class to wrap it.
public ref class ThreadWrapper
{
public:
    // Method 
    int GetId()
    {
        DWORD id;
        HRESULT hr = m_thread->GetID(&id);
        
        System::Runtime::InteropServices::Marshal::ThrowExceptionForHR(hr);
        return id;
    }
    
    // Above as a property
    property int Id {
        int get()
        {
            return GetId();
        }
    }

    // add other methods of interest

    // Raw pointer to COM-classic interface from ICorDebug
    ICorDebugThread * m_thread; 

    // Could have additional data 
    // (or we could put that data in a derived class)
};

C# can then access that class just like any other class. For example:

     void PrintThread(ThreadWrapper t)
    {
        Console.WriteLine("Thread's ID is: " + t.Id);
    }