zoukankan      html  css  js  c++  java
  • 动态链接库(DLL)NonMFCDLL

    1.Non-MFC的DLL、MFC的DLL和MFC的扩展DLL的定义

    Non-MFCDLL不采用MFC类库结构 ,其导出函数为标准的C接口,能被非MFC或MFC的程序调用;MFC规则的DLL包含继承自CWinApp的类,但无消息循环;MFC扩展DLL采用MFC的动态连接版本创建,他只能被MFC类库所编写的程序使用。


    2.DLL的头文件模板

    DLL的头文件需要的DLL定义的时候以及DLL调用程序中使用,但是在DLL定义的时候,头文件需要声明导出,而在调用的程序中,有需要声明为导入函数,所以头文件有所不同。同时,需要注意的是标准C编译器类型的导出函数和C++类型的编译器导出函数,存在着兼容性的问题,所以在头文件中也需要作出相对应的声明。上面这些常见的问题,都可以使用宏定义的方式来统一成一个头文件,所以有了下面的头文件模板。如下所示:

    #ifndef _NONEMFCDLL_H
    #define _NONEMFCDLL_H
    
    //如果用C编译器文件,用extern "C"声明
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    //宏定义导出函数,DLL定义程序
    #ifdef NONEMFCDLL_EXPORTS
    #define NONEMFCDLL_API __declspec(dllexport)
    #else
    //宏定义导入函数,调用程序
    #define NONEMFCDLL_API __declspec(dllimport)
    #endif
    
    //此处添加导出函数、变量、类的说明
    NONEMFCDLL_API int Add(const int a, const int b);
    NONEMFCDLL_API void Show();
    
    //如果用C编译器文件,用extern "C"声明
    #ifdef __cplusplus
    }
    #endif


    3.示例

    创建工程项目的时候选择Win32应用程序,然后选择DLL即可创建Non-MFCDLL工程项目,VS会自动生成一些东西,不过,我们需要做一些修改,主要把上面的头文件模板搬过去使用。示例的头文件如下NoneMfcDll.h所示:

    // 下列 ifdef 块是创建使从 DLL 导出更简单的
    // 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 NONEMFCDLL_EXPORTS
    // 符号编译的。在使用此 DLL 的
    // 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
    // NONEMFCDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
    // 符号视为是被导出的。
    
    #ifndef _NONEMFCDLL_H
    #define _NONEMFCDLL_H
    
    //如果用C编译器文件,用extern "C"声明
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #ifdef NONEMFCDLL_EXPORTS
    #define NONEMFCDLL_API __declspec(dllexport)
    #else
    #define NONEMFCDLL_API __declspec(dllimport)
    #endif
    
    //此处添加导出函数、变量、类的说明
    NONEMFCDLL_API int Add(const int a, const int b);
    NONEMFCDLL_API void Show();
    
    
    #ifdef __cplusplus
    }
    #endif
    
    //下面的是VS自动生成的,可以不管,也可以删除
    //自动生成
    // 此类是从 NoneMfcDll.dll 导出的
    class NONEMFCDLL_API CNoneMfcDll {
    public:
    	CNoneMfcDll(void);
    	// TODO: 在此添加您的方法。
    };
    
    extern NONEMFCDLL_API int nNoneMfcDll;
    
    NONEMFCDLL_API int fnNoneMfcDll(void);
    //自动生成
    
    #endif
    

    在DLL的头文件中声明了导出函数Add和Show函数(对于DLL而言,导出函数最好都声明在一个头文件中),接下来需要在NoneMfcDll.cpp文件中定义导出函数。如下所示:

    // NoneMfcDll.cpp : 定义 DLL 应用程序的导出函数。
    //
    
    #include "stdafx.h"
    #include "NoneMfcDll.h"
    
    
    // 这是导出变量的一个示例
    NONEMFCDLL_API int nNoneMfcDll=0;
    
    // 这是导出函数的一个示例。
    NONEMFCDLL_API int fnNoneMfcDll(void)
    {
    	return 42;
    }
    
    // 这是已导出类的构造函数。
    // 有关类定义的信息,请参阅 NoneMfcDll.h
    CNoneMfcDll::CNoneMfcDll()
    {
    	return;
    }
    
    //定义导出的函数,只需要在声明的时候声明为导出函数,在定义的时候可以不需要声明了
    int Add(const int a, const int b)
    {
    	return a+b;
    }
    void Show()
    {
    	MessageBox(NULL, TEXT("来自NONEMFCDLL_API的Show函数!"), TEXT("NONEMFCDLL_API消息"), MB_OK | MB_ICONINFORMATION);
    }

    需要注意的是,对于定义导出函数,可以不在声明该函数为导出函数了,只需按照正常的函数定义即可。如此一个Non-MFCDLL工程完成,此时只需要编译即可生成DLL文件。


    4.DLL的调用(隐式调用DLL)

    隐式调用DLL即是把动态链接库生成的时候的lib文件加入到应用程序的工程中,当使用当使用的时候只需要声明一下导出函数即可(引用模板头文件即可),所以比较简单,但是需要注意的是,当DLL重新编译之后,应用程序需要重新编译。

    隐式调用的主要注意的有几点:

    a) 包含头文件,即是导出函数的声明

    b) 使用#pragma comment(lib, "Dll.lib")把lib包含到工程中

    c) 把对应的DLL文件拷贝到应用程序所在目录

    之后,使用导出函数像正常的函数一样使用即可,示例的cpp文件如下所示:

    // LoadNonMfcDll.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    //包含dll的头文件,声明导入函数
    #include "../../NoneMfcDll/NoneMfcDll/NoneMfcDll.h"
    #include <iostream>
    using namespace std;
    //隐式调用把产生的lib文件包含到工程中
    #pragma comment(lib, "../../NoneMfcDll/Debug/NoneMfcDll.lib")
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	cout << "23+4=" << Add(23, 4) << endl;
    	Show();
    	return 0;
    }
    

    5.显示调用

    非MFC程序

    // LoadNonMfcDll.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    //包含dll的头文件,声明导入函数
    #include "../../NoneMfcDll/NoneMfcDll/NoneMfcDll.h"
    
    //LoadLibrary函数需要
    #include <Windows.h>
    
    #include <iostream>
    using namespace std;
    
    
    ////隐式调用把产生的lib文件包含到工程中
    //#pragma comment(lib, "../../NoneMfcDll/Debug/NoneMfcDll.lib")
    
    //定义导出函数类型
    typedef int (*pAdd)(const int a, const int b);
    typedef void (*pShow)();
    
    /*
    *显示调用DLL即在程序中使用LoadLibrary或者MFC提供的AfxLoadLibrary显示地将动态链接库调进来,
    *然后再用GetProcAddress函数获取函数入口,之后程序退出时应用FreeLibrary或者MFC提供
    *的AfxFreeLoadLibrary释放动态链接库。显示调用DLL的优点是程序简洁。快速,
    *缺点是不利于输出太多函数的DLL的使用。
    */
    //显示调用DLL示例
    void Test()
    {
    	HINSTANCE hDll = NULL;
    	
    	//加载DLL
    	hDll = ::LoadLibrary(TEXT("../../NoneMfcDll/Debug/NoneMfcDll.dll"));
    	if(hDll == NULL)
    	{
    		MessageBox(NULL, TEXT("NoneMfcDll.dll加载失败!"), TEXT("错误"), MB_OK | MB_ICONERROR);
    		return;
    	}
    	//声明导出函数指针
    	pAdd pAddProc = NULL;
    	pShow pShowProc = NULL;
    	//通过GetProcAddress获取导出函数地址并赋值给指针
    	pAddProc = (pAdd)::GetProcAddress(hDll, "Add");
    	pShowProc = (pShow)::GetProcAddress(hDll, "Show");
    	//检查获取情况,成功,则调用函数
    	if(pAddProc == NULL)
    	{
    		MessageBox(NULL, TEXT("NoneMfcDll.dll文件内找不到导出函数Add"), TEXT("找不到导出函数"), MB_OK | MB_ICONINFORMATION);
    	}
    	else
    	{
    		cout << "23+4=" << pAddProc(23, 4) << endl;
    	}
    	if(pShowProc == NULL)
    	{
    		MessageBox(NULL, TEXT("NoneMfcDll.dll文件内找不到导出函数Show"), TEXT("找不到导出函数"), MB_OK | MB_ICONINFORMATION);
    	}
    	else
    	{
    		pShowProc();
    	}
    	//释放加载的DLL
    	::FreeLibrary(hDll);
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
    	//cout << "23+4=" << Add(23, 4) << endl;
    	//Show();
    	Test();
    	return 0;
    }
    

    MFC程序

    void CMFCLoadAllDlg::OnBnClickedButton1()
    {
    	// TODO: 在此添加控件通知处理程序代码
    
    	//定义导出函数类型
    	typedef void (*pShow)();
    
    	HINSTANCE hDll = NULL;
    	
    	//加载DLL
    	hDll = ::LoadLibrary(TEXT("../../NoneMfcDll/Debug/NoneMfcDll.dll"));
    	if(hDll == NULL)
    	{
    		MessageBox(TEXT("NoneMfcDll.dll加载失败!"), TEXT("错误"), MB_OK | MB_ICONERROR);
    		return;
    	}
    	//声明导出函数指针
    	pShow pShowProc = NULL;
    	//通过GetProcAddress获取导出函数地址并赋值给指针
    	pShowProc = (pShow)::GetProcAddress(hDll, "Show");
    	//检查获取情况,成功,则调用函数
    	if(pShowProc == NULL)
    	{
    		MessageBox(TEXT("NoneMfcDll.dll文件内找不到导出函数Show"), TEXT("找不到导出函数"), MB_OK | MB_ICONINFORMATION);
    	}
    	else
    	{
    		pShowProc();
    	}
    	//释放加载的DLL
    	::FreeLibrary(hDll);
    }


    运行结果:





  • 相关阅读:
    计算机视觉--语义分割
    对团队成员公开感谢
    韩昊20191031-1 每周例行报告
    韩昊20191024-1 每周例行报告
    韩昊20191017-1 每周例行报告
    TensorFlow在windows 下的安装
    20191010-2 每周例行报告
    韩昊 20190919-1 每周例行报告
    韩昊 20190919-4 单元测试,结对
    2505-springboot使用spring.profiles.active来分区配置
  • 原文地址:https://www.cnblogs.com/arbboter/p/4225215.html
Copyright © 2011-2022 走看看