zoukankan      html  css  js  c++  java
  • 学习:DLL介绍以及加载DLL的两种方法/.def

    在 Windows 的系统目录中,存在着很多的动态链接库文件(DLL 文件)。这些 DLL 文件中包括了 Windows API 函数可执行程序。
    DLL 将各函数"导出",这样应用程序就可以找到 DLL 中的函数地址,当应用程序调用 Windows API 时,程序会运行到 DLL 中的函数。

    API 函数主要存在于几个核心的动态连接库文件中。

    Kernel32.dll:
    Kernel32.dll 包括了系统基本服务中最基本的 API 函数,如文件系统、进程与线程、内存管理等。Windows XP SP2 系统中,Kernel32.dll 有 949 个导出函数,例如,CreateFileA、CreateProcessA、OpenThread、SetFileTime 等。本书将在后续章节中通过实例介绍这些 API 的使用。

    User32.dll:
    User32.dll 是 Windows 图形用户界面的主要支持。一些重要的图形用户界面函数由 User32.dll 函数导出。Windows XP SP2 系统中,User32.dll 有 732 个导出函数,例如 CreateWindowExW、RegisterClassA 等。

    Gdi32.dll:
    Gdi32.dll 是 Windows GDI 应用程序设计接口,Gdi32.dll 导出了与此相关的若干函数,如 GetTextColor、LineTo、TextOutA 等。


    使用DLL:

    加载DLL分为两种方式:

    静态链接库:启动时加载DLL:需要使用.h头文件和.lib文件

    动态链接库:运行时加载DLL:使用LoadBibrary() GetProcessAddress()


    静态链接库的实现:

    1、先创建了静态链接库的项目

    头文件代码如下:

    #ifdef __cplusplus
    #define EXPORT extern "C" __declspec(dllexport)
    #else
    #define EXPORT __declspec(dllexport)
    #endif
    // 在头文件中根据编译器来进行判断,之后方便源文件处理
    // extern "C" __declspec(dllexport) 以C语言的规则导出函数,并且
    // 如果是C语言来写 就不需要写 extern "C"
    
    
    //头文件中函数的声明
    EXPORT BOOL CALLBACK EdrCenterTextA(HDC hdc,PRECT prc,PCSTR pString);
    EXPORT BOOL CALLBACK EdrCenterTextW(HDC hdc, PRECT prc, PCWSTR pString);
    
    
    //编码判断
    #ifdef UNICODE
    #define editCenterText EdrCenterTextW
    #else
    #define editCenterText EdrCenterTextA
    #endif
    

    源文件代码如下:

    // Dll1.cpp : 定义 DLL 应用程序的导出函数。
    //
    
    #include "stdafx.h"
    #include "Dll1.h"
    
    int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved){  
    	//DLL的入口函数是DllMain
    	return true;
    }
    
    EXPORT BOOL CALLBACK EdrCenterTextA(HDC hdc, PRECT prc, PCSTR pString)
    {
    	int iLength;
    	SIZE size;
    	iLength = lstrlenA(pString);
    	GetTextExtentPoint32A(hdc, pString, iLength, &size);
    	return TextOutA(hdc, (prc->right - prc->left - size.cx) / 2,
    		(prc->bottom - prc->top - size.cy) / 2, pString, iLength);
    }
    
    EXPORT BOOL CALLBACK EdrCenterTextW(HDC hdc, PRECT prc, PCWSTR pString)
    {
    	int iLength;
    	SIZE size;
    	iLength = lstrlenW(pString);
    	GetTextExtentPoint32W(hdc, pString, iLength, &size);
    	return TextOutW(hdc, (prc->right - prc->left - size.cx) / 2,
    		(prc->bottom - prc->top - size.cy) / 2, pString, iLength);
    }
    

    然后进行编译,把生成的.lib.dll文件放到我们写的win32程序的目录中

    在win32中需要包含上方的.h头文件,然后在窗口过程的回调函数WM_PAINT中添加如下代码:

        case WM_PAINT:
            {
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint(hWnd, &ps);
    			RECT rect;
    			editCenterText(hdc, &rect,TEXT("My First Dll")); //在窗口中显示My First Dll
                EndPaint(hWnd, &ps);
            }
    

    还需要在win32项目中添加.lib依赖项,再生成文件运行

    缺点:

    1、生成的可执行文件体积大

    2、当多个程序运行时候需要多次包含相同的公共代码,造成浪费

    关于第二点:大家可能会有疑问,动态链接库难道当多个程序运行加载比如Kernel32.dll的时候就不是多次包含相同的公共代码了吗?

    答:其实不是的,Kernel32.dll在内核中,物理页上只有一份,当一个进程启动调用Kernel32.dll的时候是通过映射的方式进行调用的,从而节省了资源

    具体的大家可以参考: https://www.cnblogs.com/zpchcbd/p/12253713.html


    动态链接库的实现:

    1、DLL项目文件代码如下:

    头文件代码:

    #ifdef __cplusplus
    #define EXPORT extern "C" __declspec (dllexport)
    #else
    #define EXPORT __declspec (dllexport)
    #endif
    	
    EXPORT DWORD DEMOA();
    EXPORT DWORD DEMOW();
    
    #ifdef UNICODE
    #define DEMO DEMOW
    #else
    #define DEMO DEMOA
    #endif
    

    DLLMain文件如下:

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "stdafx.h"
    #include "dll2.h"
    
    BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved){
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
    		// 当DLL文件被加载的时候
    		MessageBox(NULL, TEXT("DLL被加载了"), TEXT("TITLE"), MB_OK);
        
    	case DLL_THREAD_ATTACH:
    		// 新创建的线程中再次调用DllMain
    		MessageBox(NULL, TEXT("新创建的线程中再次调用DllMain"), TEXT("TITLE"), MB_OK);
    
    	case DLL_THREAD_DETACH:
    		// 新创建的线程被结束的时候
    		MessageBox(NULL, TEXT("新创建的线程被结束的时候"), TEXT("TITLE"), MB_OK);
    
        case DLL_PROCESS_DETACH:
    		//当DLL文件被释放的时候
    		MessageBox(NULL, TEXT("DLL被释放了"), TEXT("TITLE"), MB_OK);
    
            break;
        }
        return TRUE;
    }
    
    EXPORT DWORD DEMOA() {
    	MessageBoxA(NULL, "这是函数DEMOA", "DLL", MB_OK);
    	return 0;
    }
    
    EXPORT DWORD DEMOW() {
    	MessageBoxW(NULL, TEXT("这是函数DEMOW"), TEXT("DLL"), MB_OK);
    	return 0;
    }
    
    

    2、创建一个MFC的项目,创建三个按钮,实现代码如下:

    动态链接库调用DLL分为6步走

    1、声明函数指针 typedef DWORD(*MYDEMOW)();
    2、定义函数指针变量 MYDEMOW demo =
    3、动态加载DLL到内存 hmo = LoadLibrary(_T("DLL2.dll"));
    4、函数指针变量接收DLL中加载函数的地址 MYDEMOW demo= (MYDEMOW)GetProcAddress(hmo, "DEMOW")
    5、调用函数指针 demo();
    6、释放动态链接库 FreeLibrary(hmo);

    HMODULE hmo;
    typedef DWORD(*MYDEMOW)();
    
    void CDLLMFCDlg::OnBnClickedButton1()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	
    	hmo = LoadLibrary(_T("DLL2.dll")); //LoadLibrary返回值为一个句柄
    }
    
    void CDLLMFCDlg::OnBnClickedButton2()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	MYDEMOW demo= (MYDEMOW)GetProcAddress(hmo, "DEMOW"); // 获取dll加载到进程中的指定名称的函数的地址,返回值是函数的地址,那么我们也就需要用指针来进行接收
    	//比如 MYDEMOW 为指针函数的类型,所以我们用一个MYDEMOW类型的指针函数demo来进行接收
    	demo();
    
    }
    
    
    void CDLLMFCDlg::OnBnClickedButton3()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	FreeLibrary(hmo);
    }
    

    DLL文件需要和MFC编译的exe文件放在一起

    运行效果


    模块定义文件:

    关于def定义介绍可以查找微软的官方文档:https://docs.microsoft.com/en-us/cpp/build/exporting-from-a-dll-using-def-files?view=vs-2019

    关于.def在动态链接库的时候的应用,可以对dll进行自定义导出的操作,类似导出表中查看的时候查看函数的名称可以只有:

    1、有无函数名称

    2、有无函数编号

    例如跟上面一样定义了4个函数,加减乘除:

    当定义了def文件之后就不需要去声明导出函数了,也就是不需要再加extern "C" _declspec(dllexport) `

    然后定义的dll.def,名称任意但是需要后缀为def,内容如下:

    EXPORTS
    plus @11
    sub @12 
    div @14
    mul @15 NONAME
    

    编译,查看其导出表,内容如下:

    sub函数被隐藏了名称

    好处:有一定的保护程序的作用!

  • 相关阅读:
    获取小程序码
    获取目标地与当前地距离
    小程序图片预览
    地图导航
    Jquery无缝滚动
    短信验证
    根据经纬度获取地址
    微信小程序中使用emoji表情
    小程序图片上传
    地球人类的牢笼
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/11900727.html
Copyright © 2011-2022 走看看