Mixed Mode DLL and “/Zl”

I spent 8 hours today debugging a stupid switch set by the VS.NET 2003 AppWizard. I’m trying to wrap some DLLs into a mixed mode DLL for use in some managed code. After laboring with an unmanaged wrapper compiled with /clr, I gave up and tried a “.NET Class Library” AppWizard. Then I added my DLLs, classes, etc. The project compiles correctly and then the linker fails, issuing this error:

LNK2020: unresolved token (0A00002C) ??_7type_info@@6B@

Right. I finally determined that the /Zl switch caused the issue. You will find this setting in Properties->C/C++->Command Line->Additional Options.

Mixed mode DLLs have significant issues in both .NET 1.0 and 1.1.

MFC / COM Interop with .NET (Managed C++)

Approach:

For my current project, I needed to write a plugin for an MFC-based application. I wanted both the rich GUI components and XML support provided in .NET, though, so I needed to wrap the MFC / OLE automation functionality and then connect to it via managed code. The MFC application provided a type library (.tlb). Here are the steps I took and some references.

1) The tlb only contains interface definitions. Therefore, you must generate instances of those interfaces. Unfortunately, the .NET AppWizards do not provide that capability for .NET classes. Start a new MFC project and click “Add new class” from the project menu. You can then “Add an MFC class from a type library.” Load the tlb file in the next dialog. The available interfaces appear in the left box. Select the desired interfaces and continue. A new header file will appear in the project for each interface. You can now instantiate the classes.

2) I elected to place all of the MFC code into an extension DLL and then implicitly link the DLL into my .NET code (the “It Just Works” or IJW method for mixed/unmanaged Dlls). This approach hides all of the MFC headers, types, etc. in the DLL. The managed code may operate with no notion of the underlying MFC functionality. Create a new “MFC extension DLL” project and add the classes generated in (1).

3) You must then export all functions and classes from the DLL. Instead of using the AFX_EXT_CLASS macro, I used the following code:


#ifdef _WINDLL
/* #include MFC headers here */
#define DLLExport __declspec( dllexport )
#else
#define DLLExport __declspec( dllimport )
#endif

class DLLExport MyClass
{
...
};

Add the DLLExport macro to non-member functions like this:

void DllExport MyFunc(void);

This approach mirrors the AFX_EXT_CLASS macro, but allows the .NET code to use the header without the MFC libraries.

4) I used the stock DllMain function generated by the AppWizard. Add *safe* startup code to DllMain. See the “DllMain Restrictions” section in this article.

5) Build the project. Ensure that you dynamically link the C Runtime Library (CRT) by setting the /MD or /MDd switch in Project Properties->C/C++->Code Generation. The .NET application in the next step *MUST* use the same switch. Otherwise, the exe/dll application will have two versions of the CRT and you will experience some nasty problems.

6) Implicitly link (IJW) the DLL to the .NET exe. #include the header from (3) in the EXE. Add the DLL’s .lib file to the Linker->Input->Additional dependencies box. The .lib file contains compile-time information for linking the DLL. Finally, copy the .dll file to the project output directory.

Issues:

References:

Software Blogs

I’ve discovered several great software commentaries over the last few days:

Powered by WordPress
Entries and comments feeds. Valid XHTML and CSS.