当前位置: 首页 > 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

http://www.xdnf.cn/news/360631.html

相关文章:

  • C#学习——继承、封装、多态
  • 安科瑞DJSF1352-RN直流电能表的技术特点与应用
  • ZYNQ笔记(十九):VDMA VGA 输出分辨率可调
  • 各类音频放大器电路原理简析
  • MSF 生成不同的木马 msfvenom 框架命令
  • html object标签介绍(用于嵌入外部资源通用标签)(已不推荐使用deprecated,建议使用img、video、audio标签)
  • Nx与Monorepo
  • 【软件测试】测试用例的概念与常见测试的模型
  • Django ORM: values() 和 annotate() 方法详解
  • 2025-05-09 提示学习概念
  • Edu教育邮箱申请2025年5月
  • 【Lattice FPGA 开发】Diamond在线调试Reveal逻辑乱跳的解决
  • lambda 表达式
  • 摄像头模组高像素模组
  • AI模型蒸馏技术在微控制器上的内存占用与精度平衡实践
  • Java中的反射
  • C++23 中的 views::chunk:深入探索与应用
  • shopping mall(document)
  • 虚拟机ubantu20.04系统桥接模式下无法ping通外网,但可以ping通本机的解决方案
  • 云原生架构下的微服务通信机制演进与实践
  • 每天批次导入 100 万对账数据到 MySQL 时出现死锁
  • TCP套接字通信核心要点
  • AI内容检测如何助力企业应对内容治理挑战
  • MySQL数据库操作
  • 纯Java实现反向传播算法:零依赖神经网络实战
  • 个人项目总结
  • TDengine 在智慧油田领域的应用
  • window 显示驱动开发-线性内存空间段
  • 【高并发内存池】从零到一的项目之centralcache整体结构设计及核心实现
  • JVM、JRE、JDK的区别