最近想把MFC写的对话框程序封装成.dll文件供C#程序调用,其中遇到了很多问题,现记录如下,以供参考!
一、在做MFC对话框封装之前顺带讲下函数的封装,这个相对简单。
1- 首先创建Win32 project,命名为mydll;
2- 应用类型选择DLL,完成;
3- 生成工程目录如下;
4- 在mydll.h头文件中添加代码如下(以实现add函数封装为例);
#include <string>
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
// This class is exported from the mydll.dll
class MYDLL_API Cmydll {
public:
Cmydll(void);
// TODO: add your methods here.
};
extern MYDLL_API int nmydll;
MYDLL_API int fnmydll(void);
//以上为编译器自动生成代码
//需要导出的函数必须添加 __declspec(dllexport),MYDLL_API前面已定义
extern "C" MYDLL_API int __stdcall add(int a,int b);
5- 在mydll.cpp中完成add函数实现;
#include "stdafx.h"
#include "mydll.h"
#include <iostream>
using namespace std;
// This is an example of an exported variable
MYDLL_API int nmydll=0;
// This is an example of an exported function.
MYDLL_API int fnmydll(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see mydll.h for the class definition
Cmydll::Cmydll()
{
return;
}
//以上为编译器自动生成代码
//add函数实现
MYDLL_API int __stdcall add(int a, int b)
{
return a + b;
}
6- 编译生成dll文件;
7- 创建C#程序调用该dll文件;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;//必须添加此行
namespace usemydll
{
class Program
{
//dll路径按实际情况填写,最好将dll文件复制粘贴到项目文件根目录中
[DllImport(@"E:\Project_yuanmin\mydll\Debug\mydll.dll", EntryPoint = "add")]
extern static int add(int a, int b);
static void Main(string[] args)
{
int c = add(55,45);
Console.WriteLine(c);
Console.Read();
}
}
}
二、下面是封装MFC对话框过程,前提:我编译好了一个MFC对话框程序并调试成功,此处以一个tracker跟踪器项目为例。
1- 创建MFC DLL项目,命名为trackerdll;
2- 选择Regular DLL;
3- 生成项目目录如下(将要封装的对话框对应的类头文件及实现文件复制粘贴到dll项目文件夹并导入项目目录,
此处为TrackerDlg.h和TrackerDlg.cpp两个文件);
6-导入对话框资源文件;
7- 在trackerdll.cpp文件中添加代码如下(需在相应头文件中添加#include "resource.h",确认导入对话框资源定义);
#include "stdafx.h"
#include "trackerdll.h"//添加必要头文件,使用了第三方dll的需将对应文件添加至项目文件夹中
#include "TrackerDlg.h"
#include "HCNetSDK.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//
//TODO: If this DLL is dynamically linked against the MFC DLLs,
// any functions exported from this DLL which call into
// MFC must have the AFX_MANAGE_STATE macro added at the
// very beginning of the function.
//
// For example:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
//
// Please see MFC Technical Notes 33 and 58 for additional
// details.
//
// CtrackerdllApp
BEGIN_MESSAGE_MAP(CtrackerdllApp, CWinApp)
END_MESSAGE_MAP()
// CtrackerdllApp construction
CtrackerdllApp::CtrackerdllApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CtrackerdllApp object
CtrackerdllApp theApp;
// CtrackerdllApp initialization
BOOL CtrackerdllApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
//以上除了include项均为编译器自动生成代码
//需要导出的函数在下面按要求编写,此处以显示对话框函数为例
#define TRACKER_API extern "C" _declspec(dllexport)
TRACKER_API void showDlg()//导出显示对话框函数
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());//使用了MFC控件
NET_DVR_Init();//海康SDK初始化,此处为本项目单独要求,其他项目不需要添加
TrackerDlg dlg;//显示对话框
dlg.DoModal();
}
8- 在项目>>属性>>General中对应修改Use of MFC; Character set项,
在项目>>属性>>C/C++>>Code Generation中对应修改Runtime Library;
9- 编译生成dll文件,并创建C#程序调用,代码如下;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;//必须添加此行
namespace usemydll
{
class Program
{
//dll路径按实际情况填写,最好将dll文件复制粘贴到项目文件根目录中
[DllImport(@"E:\Project_yuanmin\trackerdll\Debug\trackerdll.dll", EntryPoint = "showDlg")]
extern static void showDlg();
static void Main(string[] args)
{
showDlg();
}
}
}
ps:涉及多线程调试错误,参考:
http://www.cnblogs.com/zwh0214/p/6048360.html:
MFC的使用,有三种设置:
1.使用标准Windows库
2.在静态库中使用MFC:是将DLL中的相关代码写进EXE文件中,文件较大,但是可以在没有相关DLL的机器上运行;
3.在共享DLL中使用MFC:指的是打包时一些MFC的DLL的内容没有被包含在EXE文件中,所以EXE文件较小,但是运行时要求系统中要有相关的DLL文件;
多线程调试
/MD:在dll中使用多线程,创建动态链接库的release版本,需要选择。
/MT: 在exe里使用多线程,创建exe的release版本,需要选择。
/MTd:同/MT一样,不过是在Debug版本中使用。
/MDL:同/MD一样,不过是在Debug版本中使用。
如果是Debug的“在静态库中使用MFC”,不要使用MDd,改用MTd,然后编译即可通过。
如果是Debug的“在共享DLL中使用MFC”,注意不要使用MTd,改用MDd;
如果是Release版本“在静态库中使用MFC”,不要使用MD,使用MT;
如果是Release版本的“在共享DLL中使用MFC”,不要使用MT,使用MD。