MFC 调用静态链接 MFC 的规则 DLL

December 09, 2023
测试
测试
测试
测试
17 分钟阅读
简语:

最近学习了生成静态链接的dll及其调用,写一下笔录和大家分享,有错误的地方欢迎大家指出来

开发环境

VS2015

开发语言

C++

开发步骤

以mfc的dll创建为例,先说明一下win32的dll和mfc的dll在支持C上,win32可能比较好,实现的过程是一样的。

构建MFC的DLL项目
  • 新建MFC DLL项目
  • 这边选择带静态链接MFC的规则DLL
  • 默认生成了,头文件和源文件,右键def文件
  • MyDLL.h 个人是将整个类导出,也可以单独导出某个或者几个函数 导出函数是 :__declspec(dllimport) void(类型) __stdcall 函数名 导出类具体参考msdn
// MyDLL.h : MyDLL DLL 的主头文件
#pragma once
#ifndef __AFXWIN_H__
    #error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif

#include "resource.h"       // 主符号

#define EXPORT __declspec(dllimport)  //这边是导出的宏定义


/**
* 接口测试接口回调
* @param code 初始化成功返回code码
*/
typedef void(*TestCallBack)(int code);

/**
* 测试结果接口回调
* @param result 返回测试结果
*/
typedef void(*TestResultCallBack)(const char* result);

/**
*
*/
typedef struct TestInfo {
    int No;
    const char* name;
    const char* content;
} TestInfo;

// CMyDLLApp
// 有关此类实现的信息,请参阅 MyDLL.cpp
// 对外导出 CMyDllApp类


class EXPORT CMyDLLApp      //将整个类导出,也可以单独导出单个函数
{
// 重写
public:

    TestCallBack testCallBack;
    TestResultCallBack resultCallBack;
    TestInfo info;
    char* id;

    void __stdcall InitTest(TestInfo const& info, char* id);
    void __stdcall SetTestCallBack(TestCallBack testCallBack);
    void __stdcall SetResultCallBack(TestResultCallBack resultCallBack);
    char* __stdcall GetTestInfoCode();

    void OnCalculate();
    void DoTest();
};
  • MyDLL.cpp 这边是逻辑实现
// MyDLL.cpp : 定义 DLL 的初始化例程。
//

#include "stdafx.h"
#include "MyDLL.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

void CMyDLLApp::InitTest(TestInfo const & info, char * id)
{
    this->info = info;
    this->id = id;
}

void CMyDLLApp::SetTestCallBack(TestCallBack testCallBack)
{
    this->testCallBack = testCallBack;
    OnCalculate();
}

void CMyDLLApp::SetResultCallBack(TestResultCallBack resultCallBack)
{
    this->resultCallBack = resultCallBack;
    DoTest();
}

char * CMyDLLApp::GetTestInfoCode()
{
    return "1234";
}

void CMyDLLApp::OnCalculate()
{
    int lastCode = info.No + 111;
    testCallBack(lastCode);
}

void CMyDLLApp::DoTest()
{
    char buf[256] = {0};
    sprintf_s(buf, "the result is %s and %s", info.name, info.content);
    resultCallBack(buf);
}
  • MyDLL.def文件 因为导出整个类,这边可以不用声明
; MyDLL.def : 声明 DLL 的模块参数。

LIBRARY  

EXPORTS
    ; 此处可以是显式导出
  • 最后编译生成lib和dll文件

新建MFC调用客户端项目
  • 这边是新建对话框的项目

  • 在新建项目下,建立一个目录这边是libDll,在改目录下分别建立inc和lib目录

然后将MyDLL.h头文件拷贝到inc目录,将dll项目生成的MyDLL.dll和MyDLL.lib两个文件拷贝到lib下

  • 然后进行配置,项目属性-->链接器 -->常规,配置附加库目录,这边是配置外来库的文件目录(libDLL/lib 将外来库文件放置这)

  • 接着配置lib目录,项目属性-->C++ -->常规,配置附加包含目录,这边是配置外来附加头文件目录

然后再配置库名称,项目属性->链接器-->输入,配置附加依赖项,即把要添加的lib,名称加进去

到此依赖的静态链接库都配置好了。

  • 引用 MFCTestDLLDlg.h 引入依赖的库和对应的头文件#include "MyDLL.h" #pragma comment(lib, "MyDLL.lib")
// MFCTestDLLDlg.h : 头文件
#pragma once
#include "MyDLL.h"
#pragma comment(lib, "MyDLL.lib")

// CMFCTestDLLDlg 对话框
class CMFCTestDLLDlg : public CDialogEx
{
// 构造
public:
    CMFCTestDLLDlg(CWnd* pParent = NULL);   // 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_MFCTESTDLL_DIALOG };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持


// 实现
protected:
    HICON m_hIcon;

    // 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedButton1();
    CMyDLLApp MyDllApp;
    afx_msg void OnBnClickedButton2();
        //因为静态的方法无法使用非静态的成员,所以更新UI,采用消息发送的形式
    afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
        //两个回调传递的方法必须是静态的,否则会报错
    static void TestCallback(int code);
    static void ResultCallBack(const char* result);
        CStatic m_static1;
       CStatic m_static2;
};

MFCTestDLLDlg.cpp

// MFCTestDLLDlg.cpp : 实现文件
#include "stdafx.h"
#include "MFCTestDLL.h"
#include "MFCTestDLLDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define WM_UI_MESSAGE WM_USER + 105


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_ABOUTBOX };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMFCTestDLLDlg 对话框


CMFCTestDLLDlg::CMFCTestDLLDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_MFCTESTDLL_DIALOG, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCTestDLLDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMFCTestDLLDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON1, &CMFCTestDLLDlg::OnBnClickedButton1)
    ON_BN_CLICKED(IDC_BUTTON2, &CMFCTestDLLDlg::OnBnClickedButton2)
    ON_MESSAGE(WM_UI_MESSAGE, OnMyMessage)
END_MESSAGE_MAP()

//消息接收方法
LRESULT CMFCTestDLLDlg::OnMyMessage(WPARAM wParam, LPARAM lParam) {
    if (wParam == 0)
    {
        CString* result = (CString*)lParam;
        MessageBox(result->GetBuffer(), MB_OK);
    }
    return 0;
}


// CMFCTestDLLDlg 消息处理程序

BOOL CMFCTestDLLDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);         // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO: 在此添加额外的初始化代码
    TestInfo info;
    info.No = 100;
    info.name ="jack";
    info.content = "this is test dll";
    MyDllApp.InitTest(info, "8888");

    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CMFCTestDLLDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CMFCTestDLLDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCTestDLLDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}

void CMFCTestDLLDlg::OnBnClickedButton1()
{
    MyDllApp.SetTestCallBack(TestCallback);

}

void CMFCTestDLLDlg::OnBnClickedButton2()
{
    MyDllApp.SetResultCallBack(ResultCallBack);
}

void CMFCTestDLLDlg::TestCallback(int code)
{
    CString *codeCs = new CString();
    codeCs->Format(L"get the code is %d",code);
    ::PostMessage(AfxGetApp()->m_pMainWnd->m_hWnd, WM_UI_MESSAGE, NULL, (LPARAM)(codeCs));
}
void CMFCTestDLLDlg::ResultCallBack(const char * result)
{
    CString *codeCs = new CString();
    codeCs->Format(L"get the code is %s", result);
    ::PostMessage(AfxGetApp()->m_pMainWnd->m_hWnd, WM_UI_MESSAGE, NULL, (LPARAM)(codeCs));
}

到此整个项目over了,但是还存在几个问题,一个是字符串回传的时候,会出现乱码;一个是编译会提示警告出现宏重定义。

参考: https://www.cnblogs.com/19910101zj/p/4611695.html http://www.jb51.net/article/56602.htm http://blog.csdn.net/tajon1226/article/details/55190247

继续阅读

更多来自我们博客的帖子

如何安装 BuddyPress
由 测试 December 17, 2023
经过差不多一年的开发,BuddyPress 这个基于 WordPress Mu 的 SNS 插件正式版终于发布了。BuddyPress...
阅读更多
Filter如何工作
由 测试 December 17, 2023
在 web.xml...
阅读更多
如何理解CGAffineTransform
由 测试 December 17, 2023
CGAffineTransform A structure for holding an affine transformation matrix. ...
阅读更多