当前位置: 首页 > news >正文

C++ Dll创建与调用 查看dll函数 MFC 单对话框应用程序(EXE 工程)改为 DLL 工程

C++ Dll创建

一、添加 DllMain(必要)

#include <fstream>void Log(const char* msg)
{std::ofstream f("C:\\temp\\dll_log.txt", std::ios::app);f << msg << std::endl;
}BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:Log(">>> DLL_PROCESS_ATTACH");break;case DLL_THREAD_ATTACH:Log(">>> DLL_THREAD_ATTACH");break;case DLL_THREAD_DETACH:Log(">>> DLL_THREAD_DETACH");break;case DLL_PROCESS_DETACH:Log(">>> DLL_PROCESS_DETACH");break;}return TRUE;
}

二、定义导出接口

推荐使用 __declspec(dllexport) 和 extern “C”,不用 .def 文件
推荐你采用的最终写法(只用修饰宏)
// MyDll.h
#pragma once
#define DY __cdecl#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endifextern "C" {MYDLL_API int DY OpenReader();
}

def方式(可选)(不建议用)

在这里插入图片描述

; ReaderF83.def : Declares the module parameters for the DLL.LIBRARY      "ReaderF83.dll"
;DESCRIPTION  'SCPMReader Windows Dynamic Link Library'EXPORTS; Explicit exports can go hereOpenReaderRequestICCCardResetSendAPDUEjectICCCloseReaderGetUID

C++ Dll调用

HMODULE hDll = LoadLibrary("FtSmartPos.dll");
if (hDll)
{{CloseReader pFunc = (CloseReader)GetProcAddress(hDll, "CloseReader");if (pFunc){pFunc(NULL, NULL); // 弹出对话框}else{AfxMessageBox("CloseReader函数未找到");}}FreeLibrary(hDll);
}
else
{AfxMessageBox("FtSmartPos.dll未找到");
}

MFC 单对话框应用程序(EXE 工程)改为 DLL 工程

三步即可。

改为dll

在这里插入图片描述

加dllmain.cpp

// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
DWORD start = 0;
BOOL APIENTRY DllMain( HMODULE hModule,long  ul_reason_for_call,LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH: {logger.INFO_F("#DBG::VDBG:F83 plugin load  VERSION:"+string(VERSION));start = GetTickCount();}break;case DLL_THREAD_ATTACH:logger.INFO_F("#DBG::VREL:F83 plugin unload1 耗时:" + to_string(GetTickCount() - start));break;case DLL_THREAD_DETACH:logger.INFO_F("#DBG::VREL:F83 plugin unload2 耗时:" + to_string(GetTickCount() - start));break;case DLL_PROCESS_DETACH: {logger.INFO_F("#DBG::VREL:F83 plugin unload3 耗时:"+ to_string(GetTickCount()-start));}break;}return TRUE;
}

SCPMReader.cpp

// SCPMReader.cpp : Defines the initialization routines for the DLL.
#include "pch.h"#define EXPORT  __declspec(dllexport)
extern "C" {EXPORT int WINAPIV SendAPDU(HANDLE hCard,	const char* pCmd,	int nCmdLen,	char* pRsp,	int& nRspLen,	const char* pPath)
{return 0;
}
}

两种定义 导致找不到函数名。

#define WINAPI __stdcall
#define WINAPIV __cdecl

改为 extern “C” + __declspec(dllexport) + __cdecl
在这里插入图片描述
在这里插入图片描述

用depandency找不到c语言的,为什么呢?

在这里插入图片描述

用Depandency能看到_GetUID@12

非常好,这个信息 关键


你看到的是:

_GetUID@12

这说明你:

✅ 成功导出了 GetUID 函数
❌ 但它是被 __stdcall 调用约定修饰过的名字


🔥 你的问题的根本原因:

你在 DLL 中写的是:

__declspec(dllexport) int __stdcall GetUID(int a, int b, int c);

那么导出的名字就是:

_GetUID@12

表示:

  • GetUID__stdcall 函数
  • 参数共占 12 字节(3 个 int)

但你在主程序里写:

GetProcAddress(hDll, "GetUID")

这个查找的是未修饰名 "GetUID",当然 找不到


✅ 解决方案:两种选择


✅ 方案一:改为 extern "C" + __declspec(dllexport) + __cdecl

extern "C" __declspec(dllexport)
int __cdecl GetUID(int a, int b, int c);

这样导出的函数名就是 "GetUID",可以直接 GetProcAddress(hDll, "GetUID")

这是一种标准 C 导出方式,推荐用于插件和跨模块 DLL。


✅ 方案二:保持 __stdcall,改用修饰名 "_GetUID@12"

auto pfn = (decltype(&GetUID)) GetProcAddress(hDll, "_GetUID@12");

这当然也能用,但非常不优雅,容易因为参数变更导致名字变掉。


✅ 最佳实践:用头文件 + 宏控制导出名

// DllHeader.h
#ifdef MYDLL_EXPORTS
#define MYAPI extern "C" __declspec(dllexport)
#else
#define MYAPI extern "C" __declspec(dllimport)
#endifMYAPI int __cdecl GetUID(int a, int b, int c);

✅ 验证你的 DLL 导出名

你也可以继续用 dumpbin /exports 查看 DLL 导出名:

dumpbin /exports MyDll.dll

你应该能看到类似:

_GetUID@12

如果你改成了 __cdecl,应该就会看到:

GetUID

是否需要我帮你写一个包含主程序 + DLL 的最小可运行范例?你倾向保留 __stdcall 还是换成 __cdecl

相关文章:

  • Spring Boot快速开发:从零开始搭建一个企业级应用
  • 《工业计算机硬件技术支持手册》适用于哪些人群?
  • STM32GPIO输入实战-key按键easy_button库移植
  • ES6新增Set、Map两种数据结构、WeakMap、WeakSet举例说明详细。(含DeepSeek讲解)
  • Qt开发经验 --- 避坑指南(10)
  • 使用Java实现HTTP协议服务:从自定义服务器到内置工具
  • MySQL 8.0(主从复制)
  • 如何删除豆包本地大模型
  • 操纵杆支架加工工艺及钻3φ11孔夹具设计
  • L48.【LeetCode题解】904. 水果成篮
  • 《P1177 【模板】排序》
  • 高质量老年生活:从主动健康管理到预防医学的社会价值
  • 一种安全不泄漏、高效、免费的自动化脚本平台
  • C++学习-入门到精通-【5】类模板array和vector、异常捕获
  • CMA认证对象?CMA评审依据,CMA认证好处
  • PPI-ID: 德克萨斯大学研究团队最新款蛋白-蛋白互作(PPI)预测工具上线
  • Java中医门诊系统源码 中医诊所系统源码
  • Ascend的aclgraph(2)_npu_backend中还有些什么秘密?
  • 数据类型详解(布尔值、整型、浮点型、字符串等)-《Go语言实战指南》
  • jenkins 启动报错
  • “浦东时刻”在京展出:沉浸式体验海派风情
  • 雇来的“妈妈”:为入狱雇主无偿带娃4年,没做好准备说再见
  • 保证断电、碰撞等事故中车门系统能够开启!隐藏式门把手将迎来强制性国家标准
  • 俄罗斯今日将举行“胜利日”阅兵,有何看点?
  • 现场丨“影像上海”启幕:串联摄影、电影与当代艺术
  • 常州市委原常委、组织部部长陈翔调任江苏省民宗委副主任