【问题标题】:Link error for Windows functionsWindows 函数的链接错误
【发布时间】:2010-01-31 13:08:31
【问题描述】:

我正在尝试测试标准库 (kernel32.dll) 是否具有该功能之一。

用于测试的代码 sn-p:

extern void CreateProcessA (void);
int
main (void)
{
  CreateProcessA ();
  return 0;
}

代码编译链接如下:

cl /c test.c
link test.obj kernel32.lib

这段代码可以用Visual C++很好地编译,但不能链接:

test.obj : error LNK2019: unresolved external symbol _CreateProcessA referenced in function _main

但是函数 CreateProcessA 确实存在于 kernel32.dll 中,你没有吗?

如何正确链接?

附:我不想运行这段代码,只需检查函数是否存在(如果代码编译和链接 - 函数存在)。

【问题讨论】:

  • 但是你想检查函数是在编译时存在还是在运行时存在?我在第一个中看不到任何用处(哎呀,要阅读文档,无论如何,如果您包含 windows.h 如果函数不存在,则会以编译错误结束),而在第二种情况下可能很有用,因为某些功能并非在每个 Windows 版本上都可用。

标签: c windows linker name-decoration


【解决方案1】:

要查看函数是否存在,请使用

dumpbin /exports kernel32.dll | findstr CreateProcess

你甚至没有使用正确的原型,所以链接器当然找不到正确的函数。命名约定已完全取消,CreateProcess 确实是一个宏(根据UNICODE 扩展为CreateProcessAW)。

(您不需要显式链接kernel32.lib,因为cl.exe 默认情况下已经这样做了)

不要自己声明原型,#include <windows.h>

【讨论】:

    【解决方案2】:

    Kernel32.dll 将函数导出为“CreateProcessA”,请注意缺少前导下划线。说服链接器使用该导出的唯一方法是链接 kernel32.lib,这是一个由 Windows SDK 提供的导入库。

    然后你会遇到下一个问题,导入库将导出声明为_CreateProcess@40。这是__stdcall calling convention 应用的名称修饰。该调用约定被明确设计为捕捉您的错误,您没有正确声明该函数。名称的@40 部分表示堆栈帧中传递参数所需的字节数。

    因此,要使其正常工作,您应该 #include <windows.h> 获取正确的函数声明并链接 kernel32.lib 以获取正确的导出名称。

    【讨论】:

    • 不仅如此,符号还被进一步修饰,前缀为__imp_。所以你还需要一个__declspec(dllimport) 来获得正确的命名。但当然,这是由 <windows.h> 完成的。
    【解决方案3】:

    现在您正在声明自己的 CreateProcess() 版本。由于您没有提供正文(代码),因此链接器不知道在哪里查找要执行的函数。

    为了从 kernel32.lib 调用 CreateProcess,您需要包含正确的头文件

    #include <windows.h>
    

    如果编译器不知道 windows.h,那么可能是 Platform SDK for windows 没有正确安装。

    您还需要链接到正确的库

    #pragma comment(lib, "kernel32.lib")
    

    您还应该阅读有关 createprocess 的文档,因为它需要大量的参数

    BOOL WINAPI CreateProcess(
      __in_opt     LPCTSTR lpApplicationName,
      __inout_opt  LPTSTR lpCommandLine,
      __in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
      __in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
      __in         BOOL bInheritHandles,
      __in         DWORD dwCreationFlags,
      __in_opt     LPVOID lpEnvironment,
      __in_opt     LPCTSTR lpCurrentDirectory,
      __in         LPSTARTUPINFO lpStartupInfo,
      __out        LPPROCESS_INFORMATION lpProcessInformation
    );
    

    您应该在互联网上搜索 CreateProcess 示例,并且可能考虑切换到 c++,因为您在 Windows 上

    【讨论】:

      【解决方案4】:

      对于初学者,为原型放入一个适当的头文件&lt;windows.h&gt;,因为这是一个 Windows 源代码,为您的链接器添加 kernel32.lib,删除该原型,因为它不正确.您的 main 函数对于您是在创建命令行程序还是 Windows 程序存在争议 - 如果是后者,则应为“WinMain”。

      如果您在 MSDN 中查找函数“CreateProcess”,向下滚动,您将看到“库”,这是告诉您需要链接哪个库才能使其正常工作的提示。

      希望这会有所帮助, 最好的祝福, 汤姆。

      【讨论】:

      • 一直想知道您应该如何知道要包含和链接哪些头文件和库文件。嗯,那些 MSDN 页面又长又枯燥,我很少读到底。谢谢!
      【解决方案5】:

      我认为这是一个坏主意,但如果你想这样做,你需要与 kernel32.lib 导出库链接。

      【讨论】:

        【解决方案6】:

        您必须包含windows.h 才能获得正确的原型:

        #include <windows.h>
        int
        main (void)
        {
          CreateProcess(); // will cause warning due to incorrect parameter list
          return 0;
        }
        

        您是否有什么特别的原因不想加入windows.h

        【讨论】:

        • 但在这种情况下它不是 C 链接 - CreateProcess 使用 stdcall 这意味着名称用用于参数的堆栈字节数装饰 - 他的声明不包括它。
        • 哇! Larry 在 Stack Overflow 上!嗨拉里!
        【解决方案7】:

        使用 MinGW 可以使用“-mwindows”标志。示例:

        gcc.exe -c -g -MMD -MP -MF build/Debug/MinGW-Windows/newmain.o.d -o build/Debug/MinGW-Windows/newmain.o newmain.c
        gcc.exe -o dist/Debug/MinGW-Windows/hwprint_dll build/Debug/MinGW-Windows/newmain.o -mwindows 
        

        这将包括 gdi32.a、kernel32.a、user32.a 和 ws2_32.a 等内容。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-10-02
          • 2012-06-13
          • 1970-01-01
          • 1970-01-01
          • 2018-02-05
          • 1970-01-01
          • 2010-10-31
          • 1970-01-01
          相关资源
          最近更新 更多