接口 = 合约
接口也是一种合约,但请记住,合同适用于双方。在大多数情况下,当我们阅读接口文档时,都是从接口客户端的角度来看待接口的,但是如果我们能从接口服务器端来理解,则会有意想不到的收获。
角色扮演开始
让我们举个例子:控制面板接口(Interface for control panel)
通常当你有关于控制面板接口的文档的时候,你会认为自己是客户端,比如,文档是这样写的:
当控制面板管理器首次加载”控制面板”应用程序时,它会检索CPIApplet函数的地址,然后使用该地址来调用该函数并传递消息。
下面我们来看看,分别站在不同的角色是如何看待这段接口描述的。
控制面板应用程序:我需要导出一个名为CPIApplet的函数用来接收管理器传过来的信息。
控制面板管理器:我需要使用GetProcAddress来获取客户提供的CPIApplet地址并向它发送消息。
关于消息处理部分,角色扮演如下:
控制面板应用程序:我需要准备好按文档所说的顺序接收消息。
控制面板管理器:我需要准备好按文档所说的顺序发送消息。
文档里还有这么一句:控制面板管理器需要调用FreeLibrary函数来释放控制面板应用程序。
控制面板应用程序:我最好为即将到来的卸载做好准备。
控制面板管理器:我要开始卸载DLL啦。
实际的例子
让我们来写个简单的小程序来演示一下:
除了上面代码中的创建显示窗口和进入消息循环之外,我们的代码表现的就是一个控制面板管理器。我们使用了access.cpl这个控制面板应用程序来作为测试程序。确定好程序的路径之后,我们调用了如下的RunControlPanel函数来执行大部分的工作,如下图所示:
请先忽略上面标红色的部分,后面我们还讨论它们。
我们所做的实际上就是遵循文档里所说的步骤,但是从服务器端的角度来解读。我们加载了DLL,定位了准备调用的函数,使用CPL_INITL来调用这个函数,然后是CPL_GETCOUNT。如果在这个CPL文件中有任何控制面板程序,则我们查询它们的信息并进行了双击操作,最后停止。
以上这些有意思的工作都走了一遍之后,最后我们按照文档的要求执行了清理工作(通过发送CPL_EXIT消息)。
就是这样了,那么,上面标红色的部分是什么回事?
这些是为了支持那些带有自定义清单的控制面板应用程序,它们是在Windows XP里引入的新东西。
如果在控制面板中使用v6版本的ComCtl32或由RunDll32.exe运行的DLL,则你将看到:该应用程序通过将其清单附加为资源号123将其清单提供给控制面板主机。这就是红色代码的作用:它加载并激活清单,然后调用控制面板应用程序执行其操作(此时清单处于活动状态),然后进行清理。如果没有清单,CreateActCtx将返回INVALID_HANDLE_VALUE。我们并不将这个视为错误,因为许多程还没有提供清单。
课后练习题
在调用SearchPath的时候,我们在第一个参数里传入了NULL,这个会有什么安全方面的影响吗?
最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《You can read a contract from the other side》