Friday, February 27, 2009

Debugger won't break in managed dll when running from unmanaged project

In the previously described scenario, where a native MFC C++ application calls a .NET assembly via a bridge dll, I ran into some debugging issues.

  1. The debugger doesn't stop at break points set in the bridge dll or the .NET assembly code.
  2. The debugger doesn't step into the bridge dll source code.

This problem is solved by setting Configuration Properties | Debugger Type to Mixed mode for each project.

Note: this is a different than setting "Mixed Platforms", which appears when you have a C++ project and a C# project in the same solution.

Thursday, February 26, 2009

Call Managed DLL From Unmanaged EXE

Here's a quick run-through showing how to call a .NET assembly from a native MFC C++ application.

Why would anyone want to do that? Useful for extending a large existing MFC codebase to use new CLR features without modifying the build settings of the original MFC projects.

Unmanaged Native C++ application calls through a bridge dll to the managed .NET Assembly:

MFC exe --> MFC Extension DLL --> .NET Assembly

The MFC executable doesn't need to have /clr turned on because the MFC Extension DLL acts as a cover over the .NET code. The .NET Assembly can be written in your favorite .NET language, like C#.



1. This example assumes you're starting with an existing MFC application solution. Set up the .NET Assembly by adding a new CLR Class Library project to your solution.

  • Add a new CLR Class Library, called BackEnd.dll for this example.
  • Add a new class to the dll, use the standard export declarations.
namespace BackEnd {

public ref class Class1
{
public:
int BCount(int a, int b)
{
return a + b;
}
};
}


2. Add the bridge dll to sit between the managed dll and your unmanaged application:

  • Add a new MFC Extension DLL, called Bridge.dll for this example.
  • Don't forget to add Linker Additional Dependancies : "..\bin\Bridge.lib" to your executables project settings.
  • Turn on CLR support, set the /clr flag in the bridge dll project settings.
  • Add a new class to the dll, use the standard export declarations.

Check.h

class __declspec(dllexport) Check
{
public:
Check(void);
virtual ~Check(void);

int Count(int a, int b);
};

Check.cpp

#include "StdAfx.h"
#include "Check.h"

#using "..\Debug\BackEnd.dll"

using namespace System;
using namespace BackEnd;

Check::Check(void)
{
}

Check::~Check(void)
{
}

int Check::Count(int a, int b)
{
// Note this is dll uses C++/CLI style coding
Class1^ test = gcnew Class1();
return test->BCount(a, b);
}

Also, be sure to set the debugger to mixed mode to allow breaking in managed code when running from the native executable.