Windows 编译 DLL:MSVC cl.exe 与 MinGW g++ 对比

最小示例

dllmain.cpp

#include <windows.h>
#include <stdio.h>

extern "C" __declspec(dllexport)
void HelloFromDll() {
    MessageBoxA(NULL, "Hello from DLL", "DLL", MB_OK);
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) {
    return TRUE;
}

MSVC cl.exe 编译

cl /LD /EHsc /Y- dllmain.cpp user32.lib

参数说明:

参数含义
/LD编译为 DLL(输出 .dll + .lib)
/LDdDebug 版 DLL
/EHsc启用 C++ 标准异常处理
/Y-禁用预编译头(避免找不到 pch.h
user32.lib链接 user32(MessageBox 所在库)

必须在正确的命令提示符里运行

普通 cmd 里没有 cl 命令,必须用:

开始菜单 → Visual Studio 20xx → x64 Native Tools Command Prompt for VS 20xx

或在普通 cmd 里手动初始化:

call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
cl /LD /EHsc /Y- dllmain.cpp user32.lib

vcvars64.bat 路径随 VS 版本和安装目录变化,注意替换。

输出文件

成功后生成:

  • dllmain.dll — 动态链接库
  • dllmain.lib — 导入库(供其他项目链接用)
  • dllmain.exp — 导出表

MinGW g++ 编译(不需要 VS)

安装 MinGW 后:

g++ -shared -o test.dll dllmain.cpp -luser32

或指定目标架构:

x86_64-w64-mingw32-g++ -shared -o test.dll dllmain.cpp -luser32

MinGW 编译的 DLL 默认导出所有 extern "C" 函数,不需要 .def 文件。

预编译头问题(/Y-)

VS 新建项目默认启用预编译头,会生成 pch.hpch.cpp。手写 .cpp 文件如果没有包含 pch.h,编译时报:

fatal error C1010: unexpected end of file while looking for precompiled header

解决方法:

  1. /Y- 禁用预编译头(适合独立小文件)
  2. 在每个 .cpp 第一行加 #include "pch.h"
  3. 在文件属性里设置「不使用预编译头」

导出函数声明

C++ 有 name mangling,跨语言调用需要 extern "C" 防止符号被修饰:

// 头文件
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif

extern "C" MYDLL_API int Add(int a, int b);

.def 文件显式指定导出名(不受 extern “C” 影响):

LIBRARY   mydll
EXPORTS
    Add   @1
    Hello @2

编译时加 /DEF:mydll.def

验证导出

dumpbin /exports dllmain.dll

或用 Dependency Walkerx64dbg 查看导出表。