前置声明HINSTANCE及其相关内容

15

有没有一种方法可以在不包括完整(且庞大)windows.h头文件的情况下,从WinAPI中前向声明HINSTANCE类型?

例如,如果我有一个拥有HINSTANCE mInstance的类RenderWindow,我将不得不在RenderWindow.h中包含windows.h。所以需要RenderWindow的所有内容也必须包括windows.h

我尝试包括windef.h,但是这似乎需要一些来自windows.h的东西。 :-( 如果我无法前向声明它,那么在RenderWindow中是否至少有一种可移植的方式可以使用像long mInstance这样的东西替代HINSTANCE


包含windows.h头文件是否真的给你带来了任何问题? - anon
1
但我不喜欢包含它,因为有时必须取消定义“min”和“max”宏,我认为这会增加编译时间/查找等。 - abenthy
3
在包含 <windows.h> 之前,加上 #define NOMINMAX - James McNellis
4
我可以想到六个很好的理由来避免包含它。其中包括最小/最大值、常用名称的宏(例如CreateWindow),以及它不能编译为C++。你必须启用微软的语言扩展。windows.h在各种方面的行为都很糟糕。 - jalf
对于那些寻找使用C指针类型void *替换HINSTANCE的人(我现在放弃了),这里有一场关于其不透明性的激烈讨论 - Salvador
@abenthy 你不应该使用 min\max 宏。更安全、甚至更快的方法是使用 std::min \ std::max - Swift - Friday Pie
5个回答

9

HINSTANCE在WinDef.h中声明为typedef HINSTANCE__* HINSTANCE;

您可以在您的头文件中编写:

#ifndef _WINDEF_
class HINSTANCE__; // Forward or never
typedef HINSTANCE__* HINSTANCE;
#endif

当未包含WinDef.h时,您将获得引用HINSTANCE的编译错误。

3
这正是我正在寻找的窍门,非常聪明!(HINSTANCE__ 在 MSVC2005 中似乎是一个 struct 结构)。 - abenthy
3
没错,这不是黑客技巧,Windef.h 文件本来就支持这样做 :-) 如果使用类(class)而不是结构体(struct)声明,就可以确保如果之后包含 Windef.h ,编译器会报错,这表明文件结构设计有问题。请注意,此处无法提供解释或额外的内容。 - Alain Rist
1
我明白了,但是如果我在类中使用typedef,在我的实现文件中稍后包含windows.h,就会出现编译器错误,而我需要windows.h。在头文件中使用您建议的typedef并在相应的源文件中包含windows.h是否会导致不良的文件结构? - abenthy
2
如果您在编译单元中需要Windows.h,请将其作为其他库头文件之前的第一个包含。 - Alain Rist
抱歉让您久等了,但我在使用它时遇到了问题(而且需要它!)- 我正在尝试在*nix上编译一些C代码。使用这个优秀的解决方案会导致“error: unknown type name 'class'”错误。我的C语言水平很差:\ @AlainRist - jtlz2
显示剩余2条评论

5
你可以将其声明为void*并转换错误。虽然这种做法接近于无限循环,但迟早会遇到问题。使用预编译头文件可使您不关心windows.h的大小。
stdafx.h:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

3
例如,如果我有一个拥有HINSTANCE mInstance的类RenderWindow,那么我必须在RenderWindow.h中包含windows.h。因此,需要RenderWindow的所有内容也必须包含windows.h
你看过Pimpl idiom吗?这使您可以隐藏私有成员。副作用是您不必在类头文件中包含它们的头文件。

是的,Pimpl是我通常这样做的方式。 - jalf
谢谢您的建议。尽管如此,我还是更喜欢Alain Rist的解决方案。 - abenthy

1

嘿,@NoSenseEtAl,我想我们还在这里。

在2021年,HINSTANCE被定义在<minwindef.h>中。直接包含<minwindef.h>会导致错误:"无目标架构"

为了解决这个错误,请按照以下步骤操作(假设正在构建x64):

#define _AMD64_
#include <minwindef.h>

int main() {
    HINSTANCE h;
}

请注意,宏_AMD64_没有记录,它以下划线开头,因此不应该由用户定义。
而且它只由<Windows.h>定义,因此没有更小的头文件可以包含来定义它。
显然,Windows SDK与模块一起使用的希望更大,因此可以通过模块修复构建速度。

1
处理不包含头文件的句柄的最佳便携式方法是将它们重新解释为具有完全相同大小的类型。大多数句柄具有指针大小1,因此使用void*uintptr_t即可。例如:
  • _beginthreadex返回uintptr_t而不是线程的HANDLE
  • MSVC thread::native_handle 返回 void*
请确保在看到类型时对类型大小进行static_assert

1极少数句柄没有指针大小,我只能想起由AcquireCredentialsHandle返回的那个。


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