0
votes

I have inherited an old MFC/Win32 C++ application who's source code I am not supposed to edit.

This MFC application needs to host an old MFC/Win32 C++ DLL. This DLL also tries to make function calls through a Mixed-mode wrapper to a managed C++/CLI DLL. I know it sounds a little confusing, so here's a diagram of what I mean:

Old MFC/Win32 Application (NO CLR)

    ---> Hosting old MFC/Win32 DLL (NO CLR)

                 ---> Making function calls to Mixed-Mode wrapper (CLR)

                              ---> Sending function calls to C++/CLI DLL (CLR)

My problem currently is that when I try to mount an object of the C++/CLR wrapper class let's say WrapperClass WC;, the MFC/Win32 application encounters an "Unhandled exception."

I have a feeling that I may need to somehow host the CLR in a separate process in order to be able to make the object. Is this the right idea? Or am I completely out of whack here?

The code compiles time and this only occurs at run-time.

Any ideas?

Here is an example of the code I am trying to run:

MFC/Win32 DLL

#include "WrapperClass.h"

BOOL Test::bTest() //This function is called elsewhere within MFC/Win32 DLL
{
    DWORD dwTest;

    WrapperClass WC; //Unhandled exception here!

    return WC.FunctionToCall(dwTest); //FunctionToCall is a BOOL
}

Mixed-Mode Wrapper Class

BOOL WrapperClass::FunctionToCall(DWORD dw)
{
    GCHandle h = GCHandle::FromIntPtr(IntPtr(m_impl)); //m_impl def'd as void *
    CPPCLIClass^ CCC = safe_cast<CPPCLIClass^>(h.Target);

    return (BOOL)CCC->FunctionToCall(dw);
}

C++/CLI DLL

bool CPPCLIClass::FunctionToCall(UInt32 ui32)
{
    if (ui32 == 42)
    {
        return true;
    }
}

UPDATE: I've managed to coax a real exception out of the program. I am now receiving a System.IO.FileNotFound exception with additional information stating:

An unhandled exception of type 'System.IO.FileNotFoundException' occured in 
Unknown Module.

Additional information: Could not load file or assembly 'CPPCLIProject,
Version=1.0.4351.29839, Culture=neutral, PublicKeyToken=null' or one of its 
dependencies. The system cannot find the file specified.

Does this mean anything? I understand that it apparently cannot find CPPCLIProject (Note: this is not the wrapper project), but then if I'm linking on the .lib file from the Mixed-mode wrapper, how would I not receive linker errors then?

2
What is your perceived distinction between C++/CLR and C++/CLI? The former is merely a common misspelling of the latter, i.e. they're the same thing.ildjarn
I should have said Mixed-Mode DLL instead of C++/CLR, I will fix this now. Please see updated question :)Brutick

2 Answers

2
votes

Are you sure that the implementation of WrapperClass::FunctionToCall() isn't throwing the exception? It looks like you're caching the memory location of a CLR object, and then trying to call one of its members. I think the CLR is free to move objects around, so it's possible that you're trying to use an object that has moved.

If you change the implementation of WrapperClass::FunctionToCall() to something simple (i.e. create a CLR object, call a member function), do you still get the same unhandled exception?

UPDATE: Which class is in CPPCLIProject - CPPCLIClass? Assuming this project represents the C++/CLI DLL, it sounds like it just can't find the assembly to load it when it needs to call your class.

Where is this assembly on disk relative to the rest of the application? If your root EXE is unmanaged (which it sounds like it is, since it is MFC/Win32), then the CLR looks in the EXE's directory and the GAC in order to load assemblies (I don't think it looks in the Path, but I'm not positive on that).

So if the CPPCLIProject isn't in the same directory as the EXE, that could be your problem.

1
votes

Your best bet is to

  • run under a debugger (add the additional DLLs with debug information to the debug session)
  • enable break on all (first-chance) exceptions
  • trace/assert all HRESULT codes
  • in general try to catch
    • C++ exceptions (try/catch...)
    • Windows Structured Exceptions (IIRC _try/_catch, but see MSDN)

The idea is to convert the 'unkown exception' into 'known exception'.

Normally speaking there is no need to host the CLR part out of process. This is what a mixed-mode DLL is about. Then again, if this is legacy code, you might be running into complicated mixes of runtime dependencies that, shall we say, could clash.


Further thoughts:

If I understand correctly, you have the option to recompile all sources (just not touch the legacy codebase?). If so, make sure all code is compiled against the same version (think Service Packs) and type (think Static vs Dynamic/Multithread/Debug) of the runtime libraries.

While you are checking additional pathways, keep an eye on potentially conflicting dependencies on

  • ATL server libs
  • MFC libs (again static vs dynamic/Multithread/Debug flavours).