使用C语言编写Windows API程序:OpenJobObject的未定义引用问题

5

我正在尝试编写一个简短的程序,通过名称终止Windows作业对象。这是文件TerminateJobObject.c的(缩短后的)代码:

#ifndef _WIN32_WINNT
    #define _WIN32_WINNT 0x600
#endif

#define JOB_OBJECT_TERMINATE 0x0008

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



LPTSTR jobObjectName; 
HANDLE jobObj; 

int main(int argc, TCHAR *argv[]){
    jobObjectName = argv[0];    
    jobObj = OpenJobObject(JOB_OBJECT_TERMINATE,FALSE,jobObjectName);
    TerminateJobObject(jobObj,0);

}

使用“gcc TerminateJobObject.c -o TerminateJobObject”编译时,我遇到了以下错误:

TerminateJobObject.c: In function 'main'
C:/<...>:TerminateJobObject.c:(.text+0x62):undefined reference to 'OpenJobObject'
collect2: ld returned 1 exit status

我不明白为什么连接器无法解析OpenJobObject。TerminateJobObject已正确链接,也来自Windows API。
我尝试过:
- 编译器:gcc、clang - 不同版本的_WIN32_WINNT(0x500、0x600、0x601) - 不同的操作系统:Windows 7和Windows Server 2008 - "OpenJobObjectW"和"OpenJobObjectA" - 定义WINVER
我对C和Windows API经验不是很丰富,找不到有关此问题的任何信息,因此如果有人能指点一下方向,那就太好了。
API参考:OpenJobObject

2
在来到这里之前已经尝试过了。是的,今天在SO上很糟糕。祝你好运。听起来有些奇怪,打开verbose-linking并确保实际引入了Kernel32.lib。最后,虽然应该没有任何区别,但使用0x0600而不是0x600 - WhozCraig
由于这是一个链接错误,你需要集中精力确保也链接了Kernel32.lib,正如WhozCraig所提到的。 - enhzflep
首先:感谢您的输入!我尝试了0x0600,但没有效果。实际上,我不确定如何确保kernel32.lib已加载,但是快速的谷歌研究告诉我它总是被包含并且对于gcc来说是必要的。我尝试使用-v编译,输出最令人困惑。现有目录被忽略,不存在的目录被搜索。但我发现了一些有趣的东西:c:/mingw/include中的winbase.h(通过windows.h包含)缺少OpenJobObject函数,而例如TerminateJobObject则存在。我非常确定这就是问题所在。我将专注于解决这个问题。 - F. K.
1
与你的问题无关:如果你对C语言/Windows API不是很熟悉,建议选择更加合适的工具:Visual Studio Express 2013 for Windows Desktop是免费提供的,且可以直接兼容Windows SDK。 - IInspectable
1
搜索所有的包含文件,看看是否能找到OpenJobObject。它可能只是被遗漏了。如果是这样,你可以自己编写定义:从微软下载Windows平台SDK,并找到OpenJobObject的定义。将Microsoft头文件中几个其他函数的定义与MinGW头文件中的定义进行比较,看看它们如何改变,然后对OpenJobObject做同样的事情。一旦你让它工作起来,甚至可以将其发布为自己问题的答案。 :-) - Harry Johnston
1个回答

1
我解决了它。问题是mingw32的头文件winbase.h(通过windows.h包含)缺少OpenJobObject函数定义,正如Harry Johnston所怀疑的那样。
我将以下行添加到.../mingw/include/winbase.h中。
#define OpenJobObject __MINGW_NAME_AW(OpenJobObject)
WINBASEAPI HANDLE WINAPI OpenJobObjectA (DWORD dwDesiredAccess, WINBOOL bInheritHandle, LPCSTR lpName);
WINBASEAPI HANDLE WINAPI OpenJobObjectW (DWORD dwDesiredAccess, WINBOOL bInheritHandle, LPCWSTR lpName);

我在mingw-w64的winbase.h中找到了它。

接下来,我更改了对“OpenJobObjectA”的调用,现在它可以工作了。:) 感谢您的帮助!

编辑:正如Hans Passant所指出的那样,更清晰的方法可能是迁移到mingw-64或其他东西。


3
希望你意识到这是你将来会后悔的事情。像这样篡改标头文件,很容易导致“只能在我的电脑上编译”的项目。最好将其放入源代码中,并用#ifndef OpenJobObject进行包装。转换到mingw-w64是可持续的解决方案。 - Hans Passant
我不同意。程序的 C 代码实际上是好的,并不仅仅只是因为我的机器支持 OpenJobObject,而且任何实现它的头文件都应该支持。这就是为什么我决定使用 API 更改的原因。事实上,可以将其视为修复(即使只是本地)。如果我使用 OpenJobObject 写另一个程序,它将按预期工作,而不是再添加额外的定义。我同意切换到 mingw 64 的部分,但由于它在专用虚拟机上运行,所以并不需要。我将添加有关迁移以进行清理解决方案的部分。 - F. K.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接