从上一篇我转载如何进行Windows SDK编程开始,我希望可以借此补充一下Windows编程的一些背景知识。之所以这样,是因为在我前面介绍“SW系统的窗口类”时,假设了读者对Windows界面编程已经有一定的了解。
上一篇主要从介绍“如何用”的角度阐述Windows编程。但是我个人习惯“打破沙锅问到底”,很多东西是靠“悟”,而不是“记”。所以这一篇我们聊聊Windows SDK为何会是如今这个样子的。
对于一个经典的WinMain函数,通常包含三步:
- 注册窗口类(RegisterClass)。
- 创建并显示窗口(CreateWindow and ShowWindow)。
- 消息循环(MessageLoop)。即:取得消息 -> 分派消息 -> 处理消息。
窗口程序需要“创建并显示窗口”,这显而易见。关于“消息循环”也容易理解,并且我们在“SW系统简介”中描述已经得非常详细。
我相信最令人迷惑的是:“窗口类”是什么概念?为什么需要RegisterClass?
有人回答:“窗口类”是同类窗口的公共属性,是这一类窗口的共享数据。
有人回答:“窗口类”是同类窗口的默认数据(属性)。
回答窗口类数据是共享数据的,错误。因为我们知道每一个窗口都有自己独立的菜单、图标、窗口过程(WindowProc,这个最重要了)等等。它们并不存在共享关系。回答是默认数据(属性)的,正确,但没有回答为什么需要默认属性,更没涉及到更为重要的原因。
我们先来看看CreateWindow与CreateDialog的原型:
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
HINSTANCE hInstance,
LPCTSTR lpTemplate,
HWND hWndParent,
DLGPROC lpDialogFunc
);
为什么普通窗口(Window)的创建不是象对话框(Dialog)一样,直接把窗口过程(WindowProc)传进去,甚至把其他窗口类相关的数据全部直接在CreateWindow时传入?也许有人回答说,这是为了减少CreateWindow的参数个数。——呵呵,我还真不知道怎么去证明这种说法是错的。但是我固执的认为我下面给出的理由要充分些。
听说过序列化(Searialize)技术吗?有读者马上回答:知道,这是MFC中把对象写入磁盘和从磁盘中读入并还原出这些对象的技术。这个回答我给它4分(满分5分)。是的,序列化(Searialize)是对象持久化和还原的技术。但这不是MFC才开始有,而是DOS下Turbo Vision就已经有的一个技术。
对话框是什么?对话框其实是支持了序列化(Searialize)技术的特殊窗口,它在初始化的时候,从资源中还原(创建)出它的各个子窗口。只是,与普通序列化(Searialize)不太一样的是,对象持久化过程不是对话框做,而是对话框编辑器负责的。
无疑,基于对话框进行可视化编程是相当友好的。那么,从支持这种可视化编程的角度来看,我们需要支持序列化(Searialize),需要从磁盘中创建窗口。我们再回头看看CreateWindow函数的原型,你将发现,这些参数是“可序列化(可存盘)”的。而且,你立刻意识到,窗口过程(WindowProc)是不可序列化的。
我们知道,序列化技术需要RuntimeClass技术进行对象的动态创建。而所谓的RuntimeClass技术,无非是建立了类唯一标识(如类名、GUID等)到类创建函数(其他的附属数据是比较次要的)的映射而已。
现在到了关键:为了支持从磁盘还原窗口对象,Windows需要引入窗口类名,并建立它与窗口过程(WindowProc)的映射。——这正是RegisterClass存在的意义。而RegisterClass中其他的窗口类属性是次要的,并且也许前面说得没错,这些属性的存在,只是为了减少CreateWindow函数的参数个数。
补充:点击这里了解RuntimeClass与Searialize的实现机理。
补充:“绅士亦花心”提到了GDI资源的共享问题。应当承认,我前面说“窗口类数据是共享数据”这种说法错误,是比较武断的说法。是的,Windows必须面对GDI资源的共享问题,不同窗口亦存在资源共享的事实。更为合理的说法是:每一个窗口可以独立设置自己的菜单、图标、窗口过程,但菜单/图标等GDI资源是可以共享的。因为我们知道,Windows对GDI资源的共享策略是,窗口不拥有GDI资源(菜单/图标等)的所有权,用户必须为GDI资源的生命周期负责。换句话说,窗口只拥有菜单/图标句柄。