Saturday, April 16, 2011

IntelliSense error creating simple unmanaged MFC DLL in VS2010

I am using VS2010. Sometimes (not always) I create an MFC DLL and choosing type ‘Regular DLL using Shared MFC DLL’ and just compile the solution. I get an intelligence error.  Here is exact error I face
IntelliSense: #error directive: Please use the /MD switch for _AFXDLL builds        c:\program files (x86)\microsoft visual studio 10.0\vc\atlmfc\include\afxver_.h                81
After searching it I reached following link:
Please try the following:
  1. Right-click the Project.
  2. Go to Config Properties->C/C++-> Code Gen ->. Double-click "Runtime Library" and set to "Multi-threaded Debug DLL (/MDd)" . If this value already appears to be set, make sure it is by electing it again (it should then appear as bold).
  3. Click OK.

Wednesday, April 13, 2011

Develop an unmanaged DLL (MFC DLL) in VS2010 and Import in managed C# Project



Yesterday I had a need to write a wrapper for a 3rd party ActiveX control (ATL COM dll in VC6). The purpose is to write a wrapper and call from C#. The motive is due to the way ATL ActiveX was developed, there was a design issue in marshalling and when used directly from c# not return the proper results. To cut it short, I was interested to write its wrapper. 
It has been five years; I have not touched COM and VC++ due to the focus in C# majorly. But I was interested to write a wrapper and decided to develop it in VS2010. Question was how to start?
Yes, I should start creating MFC DLL in VS2010 and export a method/calss and call the function from C#.
I decided to create a MFC DLL and choosing type ‘Regular DLL using Shared MFC DLL’. The output produced by this option (dynamically linked) is a small DLL in size. The statically linked DLLs will be of larger size, as they are built with the whole MFC libraries within themselves.  
A MFC Dll can provide/export with functions, variable values, constants and classes. I focused on exporting a function, and then whole class afterwards. 
Then I added two files Util.h and Util.cpp in the project and wrote a sample function ‘Add’. Here is header file single line of code.


extern "C" __declspec(dllexport) int Add (int a, int b);

__declspec(dllexport)'s purpose is to add the "export directive" to the method.  extern "C" is meant to be recognized by a C++ compiler and to notify the compiler that the noted function is compiled in C style.
Here is Utils.cpp code:


#include "stdafx.h"
#include "Util.h"

 __declspec(dllexport) int Add (int a, int b)
{
       return a + b;
}

Compiled the MFC DLL project and it produced TTSUnmanagedWrapper.dll and TTSUnmanagedWrapper.lib in debug folder. There are two debug folders one under project sub folder and other at project root.  Please target the right one mentioned in Output window during compilation proves in VS2010.
Oks now I have MFC DLL available, Question is how to import this Unmanaged DLL to C#?
Crate a new C# Windows Form application and create a new class as follows


using System;
using System.Runtime.InteropServices;

namespace WindowClient
{
    public class NativeDLLHelper
    {

        [DllImport( @"D:\TTSUnmanagedWrapper\Debug\TTSUnmanagedWrapper.dll",
                    EntryPoint = "Add",
                    CallingConvention = CallingConvention.Cdecl)]
        public static extern int Add(int aa, int bb);
   
    }
}

Calling convention CallingConvention.Cdecl means DLL method is in C Calling convention.
And call the method anywhere in C# code like this:

int c = NativeDLLHelper.Add(2, 7);

Next Step: How to export a class instead of single function

Define a new class in Util.h
class __declspec(dllexport) DLLWrapper{
private:

public:
       DLLWrapper();
        
       int DoAdd(int x,int y);

};

And in Util.cpp write following code:

DLLWrapper::DLLWrapper()
 {

 }

int DLLWrapper::DoAdd(int x, int y)
{
       return x+y;
}

Compile the MFC DLL again. 
Now come to NativeDLLHelper class in C# project.

[DllImport( @"D:\TTSUnmanagedWrapper\Debug\TTSUnmanagedWrapper.dll",
                    EntryPoint = "?DoAdd@DLLWrapper@@QAEHHH@Z",
                    CallingConvention = CallingConvention.Winapi )]
        public static extern int DoAdd(int aa, int bb);

I defined the entry point above. It is where ‘Dependency Walker” really helped. 



And Calling convention CallingConvention. Winapi means DLL method is in C++ Calling convention. 
And call the method anywhere in C# code like this:

int d = NativeDLLHelper.DoAdd(3, 5);

That’s it :)