dll学习笔记(本地控制台)

1. VS创建DLL项目工程

//framework.h
#pragma once

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>
// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。

#ifndef PCH_H
#define PCH_H

// 添加要在此处预编译的标头
#include "framework.h"

#endif //PCH_H

//pch.cpp
// pch.cpp: 与预编译标头对应的源文件

#include "pch.h"

// 当使用预编译的头时,需要使用此源文件,编译才能成功。

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <iostream>

//下面保存了四个DLL的导出函数
//extern "C"使用C语言风格是因为C不支持函数重载,所以编译后函数名不会变
//__declspec(dllexport)将一个函数声名为导出函数
extern "C" __declspec(dllexport) int add(int a, int b) {
    
    
    return (a + b);
}
extern "C" __declspec(dllexport) int sub(int a, int b) {
    
    
    return (a - b);
}
extern "C" __declspec(dllexport) int mul(int a, int b) {
    
    
    return (a * b);
}

// 当加载一个DLL(ATTACH)或者释放一个DLL(DETACH)等不同状态发生时,所要执行的代码
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     ){
    
    
    switch (ul_reason_for_call)    {
    
    
        case DLL_PROCESS_ATTACH:
            std::cout<<"hello friend---DLL_PROCESS_ATTACH" << std::endl;
            break;
        case DLL_THREAD_ATTACH:
            std::cout << "hello friend---DLL_THREAD_ATTACH" << std::endl;
            break;
        case DLL_THREAD_DETACH:
            std::cout << "welcome back---DLL_THREAD_DETACH" << std::endl;
            break;
        case DLL_PROCESS_DETACH:
            std::cout << "welcome back---DLL_PROCESS_DETACH" << std::endl;
            break;
    }
    return TRUE;
}

/*
hMoudle是动态库被调用时所传递来的一个指向自己的句柄,指向_DGROUP段的一个选择符
ul_reason_for_call是说明动态库被调原因的标志
当进程或线程装入或卸载动态链接库的时候,操作系统调用入口函数
并说明动态链接库被调用的原因,它所有的可能值为:
    DLL_PROCESS_ATTACH: 进程被调用
    DLL_THREAD_ATTACH: 线程被调用
    DLL_PROCESS_DETACH: 进程被停止
    DLL_THREAD_DETACH: 线程被停止
lpReserved为保留参数,就是不用管。
*/

2. 右击Dll1项目名,点击生成

3. VS创建控制台程序ConsoleApplication1

//ConsoleApplication1.cpp
#include <iostream>
#include <windows.h>
using namespace std;
#if 0
/*这是显式调用的写法,应用程序在执行过程中随时可以加载DLL文件,可以看到下面的LoadLibrary是在main函数内的*/
int main(){
    
    
    HMODULE hDll = LoadLibrary(L"Dll1.dll");          //获取dll文件的话柄
    typedef int (*_pAdd)(int a, int b);                 //定义_pAdd是一个传入两个int传出一个int的函数指针
    typedef int (*_pSub)(int a, int b);                 //定义_pAdd是一个传入两个int传出一个int的函数指针
    _pAdd pAdd = (_pAdd)GetProcAddress(hDll, "add");    //根据hDll话柄获取add函数的地址并赋给指针变量pAdd,以后可作为函数名调用,忽略可能为0的警告
    _pSub pSub = (_pSub)GetProcAddress(hDll, "sub");    //根据hDll话柄获取sub函数的地址并赋给指针变量pSub,以后可作为函数名调用
    cout << pAdd(9, 3) << " " << pSub(9, 3) << endl;    //测试输出,无误
    FreeLibrary(hDll);                                  //释放话柄
    return 0;
}
#endif
#if 1
/*这是隐式调用的写法,在程序开始执行时就将DLL文件加载到应用程序当中,可以看到#pragma是在main函数前的*/
#pragma comment(lib,"Dll1.lib")
extern "C" _declspec(dllimport) int add(int a, int b);//忽略找不到函数的警告
extern "C" _declspec(dllimport) int sub(int a, int b);
int main(){
    
    
    cout << add(9, 3) << " " << sub(9, 3) << endl;
    return 0;
}
#endif 

4. 到Dll1工程目录下的Debug文件夹中复制Dll1.dll与Dll1.lib文件

5. 到ConsoleApplication1工程目录粘贴Dll1.dll与Dll1.lib文件(lib在隐式调用编译时用,dll在执行时用)

6. 编译链接执行ConsoleApplication1.cpp

hello friend
12 6
welcome back

F:\Desktop\ConsoleApplication1\Debug\ConsoleApplication1.exe (进程 10940)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .


7.查看dll文件接口

  1. 打开VS2019-工具-Visual Studio 命令提示
  2. 输入dumpbin /exports “C:\Windows\System32\user32.dll”,回车,可查看user32.dll文件的接口
  3. 其余同理

猜你喜欢

转载自blog.csdn.net/cj1064789374/article/details/113805577
今日推荐