13

定义WinMain是:

int CALLBACK WinMain(
    _In_ HINSTANCE hInstance,
    _In_ HINSTANCE hPrevInstance,
    _In_ LPSTR     lpCmdLine,
    _In_ int       nCmdShow
);

我的理解是:

但是,我从来没有遇到过 的任何用法,即使是在1990 年代hPrevInstance后期的书中。那么,如果有的话,它的用途是什么,它到底什么?hPrevInstance

4

1 回答 1

19

那是遗留的东西。Raymond Chen 对The Old New Thing(2004 年 6 月 15 日)提供了很好的解释。这是(带有更正链接):

一旦您的普通 GUI 程序启动,控制就从您的WinMain 函数开始。第二个参数 hPrevInstance 在 Win32 程序中始终为零。当然它在某些时候有意义吗?

当然是的。

在 16 位 Windows 中,有一个名为 GetInstanceData 的函数。该函数接受一个 HINSTANCE、一个指针和一个长度,并将内存从该实例复制到您的当前实例中。(它有点相当于ReadProcessMemory的 16 位,但限制是第二个和第三个参数必须相同。)

(由于 16 位 Windows 有一个公共的地址空间,GetInstanceData 函数实际上只不过是一个 hmemcpy,许多程序都依赖于此,只是使用原始 hmemcpy 而不是使用文档化的 API。Win16 实际上是设计有可能强加在未来的版本中单独的地址空间 - 观察像 GMEM_SHARED 这样的标志 - 但是像 hmemcpy'ing 你以前的实例这样的技巧的流行将这种可能性降低到一个未实现的梦想。)

这就是 WinMain 的 hPrevInstance 参数的原因。如果 hPrevInstance 不为 NULL,则它是已在运行的程序副本的实例句柄。您可以使用 GetInstanceData 从中复制数据,让自己更快地起步。例如,您可能希望将主窗口句柄从前一个实例中复制出来,以便与它进行通信。

hPrevInstance 是否为 NULL 会告诉您您是否是该程序的第一个副本。在 16 位 Windows 下,只有程序的第一个实例注册了它的类;第二个和后续实例继续使用第一个实例注册的类。(事实上​​,如果他们尝试过,注册将会失败,因为类已经存在。)因此,如果 hPrevInstance 为非 NULL,所有 16 位 Windows 程序都会跳过类注册。

设计 Win32 的人发现自己在移植 WinMain 时遇到了一些问题:为 hPrevInstance 传递什么?毕竟,整个模块/实例的东西在 Win32 中并不存在,单独的地址空间意味着在第二个实例中跳过重新初始化的程序将不再工作。所以Win32总是传NULL,让所有程序都认为自己是第一个。

令人惊讶的是,它确实奏效了。

于 2012-04-25T11:23:34.303 回答