关于WinMain函数的第二个参数解释

关于WinMain函数的第二个参数解释

作者:BlogUpdater |  时间:2021-04-08 |  浏览:24 |  评论已关闭 条评论

请牢记:hPrevInstance始终为空
当一个GUI应用程序开始运行时,控制流会从WinMain函数开始。它的第二个参数,hPrevInstance,在Win32应用程序中永远为0。这个参数有什么特殊之处吗?

当然有。

在早期的16位Windows时代,曾经有一个名叫GetInstanceData的API函数。这个函数有一个HINSTANCE参数,一个指针,一个长度参数,以及一块用于拷贝实例到当前实例的内存块。(它有点类似16位版本的ReadProcessMemory,只是会有个第二个和第三个参数必须相同的限制)

因为16位Windows有一个共享的地址空间,GetInstanceData实际上就相当于hmemcpy的操作,许多程序会依赖这个原理,并使用原始的hmemcpy,而不是文档化的API。

Win16实际上被设计为可以在将来使用独立的地址空间,你会发现有类似GMEM_SHARED这样的标志,但是类似使用hmemcpy拷贝之前的实例这种方法被大量使用,使这种潜力变成了无法实现的梦想。

这就是为什么在设计WinMain函数时会添加一个hPrevInstance参数的原因。如果hPrevInstancehPrevInstance非空,则它表明当前实例是从一个已经运行的实例中拷贝过来的。
你可以使用GetInstanceData来从中拷贝数据,然后进行快速的启动。

举个例子,你可能向从前一个实例中拷贝主窗口句柄,这样就可以和它进行通信了。通过判断hPrevInstance是否为空,可以知道当前是否运行的是程序的第一个实例。在16位Windows中,只有应用程序的第一个实例会注册窗口类,而后续的实例仅仅会使用在第一个实例中注册的窗口类,而不会重新注册。(当然了,如果后续实例还是尝试注册,也会失败,因为目标窗口类已经存在于系统中了)

因此,当hPrevInstance为非空的时候,所有16位Windows应用程序会跳过窗口类的注册过程。
Win32的设计者在尝试移植WinMain的时候,碰到这样一个问题:应该向hPrevInstance参数传递什么值?毕竟,Win32中不存在16位系统中的那些有关模块,实例的概念。而32位系统中,每个应用程序都有独立的地址空间,所以那些跳过初始化的后续实例不会正常工作。

所以,在Win32中,系统始终向hPrevInstance传递NULL值,这样,所有应用程序都会相信自己是第一个实例,这样,所有的初始化操作就不会被跳过了。

总结
奇迹般地,这个小技巧确实行得通。

最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《What was the purpose of the hPrevInstance parameter to WinMain?》

评论已关闭。