首页 > 解决方案 > 未定义对“WinMain@16”mingw 的引用转换为 DLL

问题描述

我正在尝试将给定的 C 代码转换为 DLL 文件我尝试编译给定的代码但它不起作用它给了我一个错误

.\sample.cpp:16:66: warning: passing NULL to non-pointer argument 5 of 'void* CreateThread(LPSECURITY_ATTRIBUTES, DWORD, LPTHREAD_START_ROUTINE, PVOID, DWORD, PDWORD)' [-Wconversion-null]
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../libmingw32.a(main.o):(.text.startup+0xb0): undefined reference to `WinMain@16'
collect2.exe: error: ld returned 1 exit status

我已经尝试在网上查找可用的答案,以及查看似乎没问题的语法。

我的代码

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

extern "C" __declspec(dllexport)
DWORD WINAPI MessageBoxThread(LPVOID lpParam) {
  MessageBox(NULL, "Hello world!", "Hello World!", NULL);
  return 0;
}

extern "C" __declspec(dllexport)
BOOL APIENTRY DllMain(HMODULE hModule,
                      DWORD ul_reason_for_call,
                      LPVOID lpReserved) {
  switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
      CreateThread(NULL, NULL, MessageBoxThread, NULL, NULL, NULL);
      break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
      break;
  }
  return TRUE;
}

标签: cvisual-studio

解决方案


我正在使用 Visual Studio 2017 社区版 15.8.1 版作为参考。我创建了一个简单的 DLL 项目(使用 File | New | Project)并删除了所有文件,除了dllmain.cpp我必须修改项目属性以禁用预编译头文件。中的代码dllmain.cpp是:

#define WIN32_LEAN_AND_MEAN   
#include <windows.h>

extern "C" __declspec(dllexport)
DWORD WINAPI MessageBoxThread(LPVOID lpParam)
{
    MessageBoxA(NULL, "Hello World", "Hello World", MB_YESNO);
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  dwReason, LPVOID lpReserved)
{
    switch (dwReason)
    {
        case DLL_PROCESS_ATTACH:
            DWORD   dwTID;
            CreateThread(nullptr, 0, MessageBoxThread, nullptr, 0, &dwTID);
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}  

我对你的代码做了一些修改,

  1. MB_YESNO作为最后一个参数传递给 MessageBox 而不是空指针。这将为您的消息框提供“是”和“否”按钮,这与第四个参数的预期类型(uint)相匹配。
  2. 我使用 MessageBoxA 来强制使用 ASCII 参数而不是 MessageBox,它是一种解析为 MessageBoxW 的 typedef。这会影响预期的字符串类型,并且取决于您是否使用 Unicode。
  3. 我为第二个参数 (dwStackSize) 和第五个参数 (dwCreationFlags) 传递了一个零值,CreateThread而不是 NULL。这两个参数都具有 DWORD 类型。请注意,这修复了错误消息的第一行“.\sample.cpp:16:66: 警告:将 NULL 传递给非指针参数 5”
  4. 我声明了一个变量dwTID并将一个指向它的指针作为CreateThread.
  5. 我在第一个案例中添加了一个 break 语句。这不应该在代码中产生任何后果。我只是觉得这是个好主意。

上面的代码编译没有警告或错误。因此,我相信您的代码也应该编译。因此,我强烈怀疑您看到的错误是由于您使用的编译器和链接器标志造成的。正在使用的命令行是

编译:

/JMC /permissive- /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm- /Od /sdl /Fd"Debug\vc141.pdb" /Zc:inline /fp:precise /D "WIN32" /D "_DEBUG" /D "TESTDLL_EXPORTS" /D "_WINDOWS" /D "_USRDLL" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /FC /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\testDll.pch" /diagnostics:classic 

用于链接:

/OUT:"D:\GNUHome\Projects\testDll\Debug\testDll.dll" /MANIFEST /NXCOMPAT /PDB:"D:\GNUHome\Projects\testDll\Debug\testDll.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib"/IMPLIB:"D:\GNUHome\Projects\testDll\Debug\testDll.lib" /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:"D:\GNUHome\Projects\testDll\Debug\testDll.pgd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"Debug\testDll.dll.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1 

因为您没有使用本机 Microsoft 工具(CL 和 LINK),所以您将需要找到或准备您正在使用的工具链之间的映射(您没有提到,但它似乎是从错误消息中发现的)和微软的工具链。

如果我不得不猜测,我会怀疑问题是由于/DLL链接命令行中的标志引起的。您可能必须使用-shared与 mingw 一致的东西。然而,这只是一个猜测。


推荐阅读