Spence Green

التكرار يعلم الحمار

I work at Lilt. In addition to computers and languages, my interests include travel, running, and scuba diving. more...

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

with 1,270 comments

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:

  • Do *NOT* use CString as a parameter in any of your DLL methods. The template changed between VC6 and VC7/VS.NET. You will receive linking errors. Instead, use a std::string and then convert that to a CString in the member methods.
  • Be careful when using Standard Library headers in your .NET project. For some of the libraries, if you add the “.h” extension to the #include, the linker will link the static C library. Then you’ll get the aforementioned errors.
  • If you use this approach, you shouldn’t need the “.def” file in the DLL. There are some performance benefits associated with using the .def method for exports, but IJW seems easier.

References:

Written by Spence

June 30th, 2005 at 9:50 am

Posted in .NET

Leave a Reply

You must be logged in to post a comment.