C++ 为什么CreateWindow()函数需要WindowClass';s name成员而不是指向类本身的指针?

C++ 为什么CreateWindow()函数需要WindowClass';s name成员而不是指向类本身的指针?,c++,winapi,C++,Winapi,我正在读Luna关于DirectX 11 3D游戏编程的介绍。由于一直在为Linux命令行编程,我决定从阅读附录A开始,这是一本win32编程入门,但我不理解CreateWindow()函数的某些行为。它的第一个参数是要创建的窗口类的名称-因此首先必须声明一个窗口类,然后“注册”它(我假设这意味着将该类添加到神秘的win32 API中的某个类堆栈中),然后将窗口类的lpszClassName成员传递给函数,如下所示: WNDCLASS wc; //set all the various memb

我正在读Luna关于DirectX 11 3D游戏编程的介绍。由于一直在为Linux命令行编程,我决定从阅读附录A开始,这是一本win32编程入门,但我不理解CreateWindow()函数的某些行为。它的第一个参数是要创建的窗口类的名称-因此首先必须声明一个窗口类,然后“注册”它(我假设这意味着将该类添加到神秘的win32 API中的某个类堆栈中),然后将窗口类的lpszClassName成员传递给函数,如下所示:

WNDCLASS wc;
//set all the various members of wc
wc.lpszClassName = L"BasicWndClass";
RegisterClass(&wc);
ghMainWindow = CreateWindow(L"BasicWndClass", L"LOL", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, instanceHandle, 0);
我不明白为什么最后一行不符合

ghMainWindow = CreateWindow(&wc, L"LOL", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, instanceHandle, 0);
是否有我不知道的历史或现实原因?

编辑:还有,像这样做是不是不好的做法

ghMainWindow = CreateWindow(wc.lpszClassName, L"LOL", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, instanceHandle, 0);

因为CreateWindow和RegisterClass调用通常不在同一个模块中。CreateWindow是应用程序级调用,RegisterClass是库级调用。典型的例子是埋在操作系统中的“编辑”和“列表框”类。使用字符串或原子是避免依赖于实现的结构的一种非常简单的方法


比较WNDCLASS和WNDCLASS,看看为什么这是个好主意。

RegisterClass或RegisterClass返回窗口内部使用的原子。因此,您要传递的是名称中对该ATOM的内部引用,您还可以创建多个类似的窗口,而无需重新执行RegisterClass部分。有时,人们也在代码的不同部分执行RegisterClass和CreateWindow(Ex)调用

您编辑的关于使用wc.lpszClassName的问题在技术上是正确的,如果您在WNDCLASS部分更改名称,您将不会有问题,尽管我使用std::string,并将其分配给wc.lpszClassName=string.c_str();然后创建窗口(string.c_str(),…)


希望这能有所帮助:)

我不知道答案,但如果您不真正关心如何解决操作系统特定的窗口创建问题,我建议您使用类似SDL2的跨平台基础知识。。这样你就可以进入有趣的部分了。当你注册你的类时,你会得到一个
ATOM
。如果你愿意,你可以用它。内置类已为您注册。你用名字称呼他们。您不注册它们。关于编辑:如果您同时注册一个窗口类并创建该类的窗口(与应用程序的主窗口相同),则可以重用
WNDCLASS
s lpszClassName成员。另一种常见模式是定义一个命名常量(例如,
const TCHAR g_BasicWnd[]=\u T(“BasicWnd类”);
),并将该常量用于注册窗口类和创建窗口。“将窗口类的lpszClassName成员传递给函数”-不,传递的是成员的值,而不是成员本身。有时人们会将
WNDCLASS
实例存储在全局内存中,在这种情况下,
lpszClassName
可以按原样传递。但是
CreateWindow/Ex()
不知道,也不在乎。它只关心传递给它的字符串的值,然后在已注册类的表中查找该值。为该值分配的内存可以来自任何地方,只要其字符的内容匹配。更好的问题是:“为什么你要费劲注册一个窗口类来获得一个
ATOM
,然后
CreateWindow
想要原始字符串而不是原来的
ATOM
?使用
std::string
与常量字符数组相比没有优势,因为你对它调用的唯一操作是
c_str()
。在这个更好的方法的时代,我不喜欢传递char*或任何其他裸指针。正如汉斯·帕桑所指出的,很多时候这两个词都不是在同一个地方使用的,所以它必须通过。YMMV,但我更喜欢总是显示安全代码。我不是为了传递指针。我明确地说的是数组。盲目地使用
std::string
并称之为安全的,仅仅因为它可能是安全的,是没有帮助的。例如,打电话时,它突然变得完全不安全。谢谢!这意味着如果CreateWindow()使用指向WNDCLASS的指针,它会产生问题,因为WNDCLASS在应用程序和API中可能有不同的实现?