Friday, March 20, 2009

Finding a Stack Overflow

Today I had a little difficulty tracking down a Stack Overflow problem when debugging a Windows Mobile 5.0 project using the emulator. The Call Stack Window was blank, kinda difficult to find where in the code the problem occured.

Thankfully there's an easy solution! Open the Exceptions Window (shown below) and toggle on the appropriate exception types, in this case its Stack Overflow. Now the IDE stops at the source of the problem, with a full Call Stack Window, nice!


If you're still having problems breaking in the code when the Stack Overflow occurs, check on the Linker System settings page for the Stack Reserve Size and Stack Commit Size. Try setting both the Stack Reserve Size and Stack Commit Size to zero.

The combination of turning on the Stack Overflow Exception Type, and setting Stack Reserve Size to zero seemed to allow the debugger to stop with a full Call Stack Window, giving me more information about the source of the problem.

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.