C++C++/MFC

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

2018-03-01  本文已影响42人  JasonChen8888

简语:

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

开发环境

VS2015

开发语言

C++

开发步骤

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

构建MFC的DLL项目

// 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 : 定义 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 : 声明 DLL 的模块参数。

LIBRARY  

EXPORTS
    ; 此处可以是显式导出

新建MFC调用客户端项目

// 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

上一篇下一篇

猜你喜欢

热点阅读