Raymond Chen 的博客几乎完全致力于讨论今天对我们来说“奇怪”的 Windows API 方面。幸运的是,他有一篇博文回答了这个确切的问题:
在 16 位 Windows 中,有一个名为 GetInstanceData 的函数。该函数接受一个 HINSTANCE、一个指针和一个长度,并将内存从该实例复制到您的当前实例中。(它有点相当于 ReadProcessMemory 的 16 位,但限制是第二个和第三个参数必须相同。)
...
这就是 WinMain 的 hPrevInstance 参数的原因。如果 hPrevInstance 不为 NULL,则它是已在运行的程序副本的实例句柄。您可以使用 GetInstanceData 从中复制数据,让自己更快地起步。例如,您可能希望将主窗口句柄从前一个实例中复制出来,以便与它进行通信。
hPrevInstance 是否为 NULL 会告诉您您是否是该程序的第一个副本。在 16 位 Windows 下,只有程序的第一个实例注册了它的类;第二个和后续实例继续使用第一个实例注册的类。(事实上,如果他们尝试过,注册将会失败,因为类已经存在。)因此,如果 hPrevInstance 为非 NULL,所有 16 位 Windows 程序都会跳过类注册。
设计 Win32 的人发现自己在移植 WinMain 时遇到了一些问题:为 hPrevInstance 传递什么?毕竟,整个模块/实例的东西在 Win32 中并不存在,单独的地址空间意味着在第二个实例中跳过重新初始化的程序将不再工作。所以Win32总是传NULL,让所有程序都认为自己是第一个。
当然,现在这hPrevInstance
与今天的 Windows API 无关,除非出于兼容性原因,MSDN 建议您使用互斥锁来检测应用程序的先前实例。
互斥体代表“互斥”。您可以参考MSDN 文档了解CreateMutex()
. 有很多使用互斥锁来检测以前的应用程序实例的例子,比如这个。基本思想是创建一个具有您想出的唯一名称的互斥体,然后尝试创建该命名的互斥体。如果CreateMutex()
失败ERROR_ALREADY_EXISTS
,您知道您的应用程序的一个实例已经启动。