美文网首页C++C++/MFC
MFC 调用静态链接 MFC 的规则 DLL

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

作者: JasonChen8888 | 来源:发表于2018-03-01 18:08 被阅读42次

    简语:

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

    开发环境

    VS2015

    开发语言

    C++

    开发步骤

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

    构建MFC的DLL项目

    • 新建MFC DLL项目


      image.png
    • 这边选择带静态链接MFC的规则DLL


      image.png
    • 默认生成了,头文件和源文件,右键def文件


      image.png
    • 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文件


      image.png

    新建MFC调用客户端项目

    • 这边是新建对话框的项目


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


      image.png

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

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


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


      image.png

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


      image.png
      到此依赖的静态链接库都配置好了。
    • 引用
      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

    相关文章

      网友评论

        本文标题:MFC 调用静态链接 MFC 的规则 DLL

        本文链接:https://www.haomeiwen.com/subject/nmpgxftx.html