• DLL笔记


    1.Windows API动态链接库:Kernel32.dll  User32.dll  GDI32.dll

    2.静态库:扩展名为.lib
      动态库: 包括:(1) 引入库:扩展名为.lib,引入库包含被DLL导出的函数和变量的符号名
                         (2) 动态链接库:扩展名为.dll,DLL包含实际的函数和数据,DLL中的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载DLL访问DLL中导出的函数

    3.使用动态链接库的好处:
    (1)可以采用多种编程语言来编写
    (2)增强产品的功能
    (3)提供二次开发的平台
    (4)简化项目管理
    (5)可以节省磁盘空间的内存
    (6)有助于资源的共享
    (7)有助于实现应用程序的本地化

    4.动态链接库的加载的两种方式:
    (1)隐式链接
    (2)显示加载

    5.隐式链接:
    (1)查看导出函数:

     E:\>cd E:\TDDOWNLOAD\孙鑫c++教程\c++练习\DLL\myDLL\Debug
    E:\TDDOWNLOAD\孙鑫c++教程\c++练习\DLL\myDLL\Debug>dumpbin
    提示:如果找不到dumpbin 找到D:\软件\VC98\Bin下的批处理文件VCVARS32.BAT 直接拖到到dos运行即可
    E:\TDDOWNLOAD\孙鑫c++教程\c++练习\DLL\myDLL\Debug>dumpbin -exports myDLL.dll
    注:
    基本dos操作:cd.. cd\ cd



     (2)编写DLL文件:

    /***two kinds of ways to import DLL***/
    //extern int add(int a,int b);
    //extern int subtract(int a,int b);

    //_declspec(dllimport)int add(int a,int b);
    //_declspec(dllimport)int subtract(int a,int b);

    头文件:myDLL.h
    #ifdef MYDLL_API
    #else
    #define MYDLL_API _declspec(dllimport)
    #endif

    MYDLL_API int add(int a,int b);
    MYDLL_API int subtract(int a,int b);

    源文件:myDLL.cpp
    #define MYDLL_API _declspec(dllexport)
    #include "myDLL.h"
    int add(int a,int b)
    {
    return a+b;
    }
    int subtract(int a,int b)
    {
    return a-b;
    }
    注:编译时,头文件不参与编译,源文件单独编译

    (3)编写测试工程TextmyDLL

    #include "myDLL.h"
    将 myDLL.h myDLL.lib myDLL.dll 拷贝到测试工程中
    还需在project-settings下的Link添加myDLL.lib 或者增加#pragma comment(lib,"myDLL.h")
    注:查看导入函数:dumpbin -imports TestmyDLL.exe
    E:\TDDOWNLOAD\孙鑫c++教程\c++练习\DLL\TestmyDLL\Debug>dumpbin -imports TestmyDll.exe

    (4)导出类

    头文件:myDLL.h
    #ifdef MYDLL_API
    #else
    #define MYDLL_API _declspec(dllimport)
    #endif

    MYDLL_API int add(int a,int b);
    MYDLL_API int subtract(int a,int b);
    class MYDLL_API Point
    {
    public:
    void output(int x,int y);
    };

    源文件:myDLL.cpp
    #define MYDLL_API _declspec(dllexport)
    #include "myDLL.h"
    #include<windows.h>
    #include<stdio.h>
    int add(int a,int b)
    {
    return a+b;
    }
    int subtract(int a,int b)
    {
    return a-b;
    }
    void Point::output(int x,int y)
    {
    HWND hwnd=GetForegroundWindow();
    HDC hdc=GetDC(hwnd);
    char buf[20];
    memset(buf,0,20);
    sprintf(buf,"x=%d,y=%d",x,y);
    TextOut(hdc,0,0,buf,strlen(buf));
    ReleaseDC(hwnd,hdc);
    }
    注:如果只想导出类中的一个函数,则在myDLL.h中改为:
    class Point
    {
    public:
    MYDLL_API void output(int x,int y);
    void test();//test函数没有被导出
    };

    测试工程文件中:
    void CTestmyDLLDlg::OnAdd()
    {
    CString str;
    str.Format("5+3=%d",add(5,3));
    MessageBox(str);

    }

    void CTestmyDLLDlg::OnCsubtract()
    {
    CString str;
    str.Format("5-3=%d",subtract(5,3));
    MessageBox(str);

    }

    void CTestmyDLLDlg::OnOutput()
    {
    Point pt;
    pt.output(5,3);
    }
    注意:如果DLL改变 myDLL.h myDLL.lib myDLL.dll 必须重新拷贝到测试工程中


    (5)防止c++名字改编:

    头文件:myDLL.h
    #ifdef MYDLL_API
    #else
    #define MYDLL_API extern "C" _declspec(dllimport)//加入extern "C"防止导出名字改编
    #endif

    MYDLL_API int add(int a,int b);
    MYDLL_API int subtract(int a,int b);

    源文件:myDLL.cpp
    #define MYDLL_API extern "C" _declspec(dllexport) //"C"为大写
    #include "myDLL.h"
    int add(int a,int b)
    {
    return a+b;
    }
    int subtract(int a,int b)
    {
    return a-b;
    }

    注:加入 extern "C"不能导出一个类的成员函数,只能导出全局函数,让全局函数不发生名字改编,但如果调用编写改变,即使加入了extern "C",导出名字仍然会改编


    (6)调用约定

    _stdcall 标准调用约定,就是winAPI调用约定,也是pascal调用约定
    没有加_stdcall,为c调用约定

    头文件:myDLL.h
    #ifdef MYDLL_API
    #else
    #define MYDLL_API extern "C" _declspec(dllimport)//加入extern "C"防止导出名字改编
    #endif

    MYDLL_API int _stdcall add(int a,int b);
    MYDLL_API int _stdcall subtract(int a,int b);

    源文件:myDLL.cpp
    #define MYDLL_API extern "C" _declspec(dllexport) //"C"为大写
    #include "myDLL.h"
    int _stdcall add(int a,int b)
    {
    return a+b;
    }
    int _stdcall subtract(int a,int b)
    {
    return a-b;
    }


    (7)模块定义文件:防止调用约定名字改编

    模块定义文件 myDLL.def
    LIBRARY myDLL

    EXPORTS
    add
    subtract
    注:如果要导出改编的名字:
    模块定义文件 myDLL.def
    LIBRARY myDLL

    EXPORTS
    myadd=add //导出为myadd
    mysubtract=subtract //导出为mysubtract

    6.动态加载
    去掉 project-settings下的Link添加的myDLL.lib
    只需拷贝myDLL.dll到测试工程,不需要myDLL.h和myDLL.lib

    测试工程文件中:
    void CTestmyDLLDlg::OnAdd()
    {
    HINSTANCE hInst;
    hInst=LoadLibrary("myDLL.dll");
    typedef int (/*_stdcall*/ *ADDPROC)(int a,int b);
    ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add");
    //ADDPROC Add=(ADDPROC)GetProcAddress (hInst,MAKEINTERSOURCE(1));//利用序号访问
    if(!Add)
    {
    MessageBox("获取函数地址失败!");
    }
    CString str;
    str.Format("5+3=%d",Add(5,3));
    MessageBox(str);
    FreeLibrary(hInst);//释放DLL
    }



     

  • 相关阅读:
    跳表(SkipList)及ConcurrentSkipListMap源码解析
    动态主机配置协议DHCP
    电子邮件
    万维网WWW
    运维技巧(4):管理邮箱收发限制
    运维技巧(3):管理邮箱配额限制:重点是powershell命令操作
    运维技巧(2):创建邮箱方法详解
    运维技巧(1):如何通过邮件头和传输跟踪日志查看原始客户端IP
    管理客户端连接(6):客户端软件可以连接上邮箱
    配置Exchange 防病毒和反垃圾邮件(9)
  • 原文地址:https://www.cnblogs.com/danshui/p/2297976.html
Copyright © 2020-2023  润新知