摘要:本文介绍了一种有别于通常的Windows外壳编程方法。采用COM技术,通过Windows提供的外壳接口实现对其的编程。
一、 引言
在Windows环境下,不论是使用Visual C++还是Delphi或是其他一些软件开发工具,尽管存在着差别,但有一点是相同的:都是运行于Windows操作系统之下的。在程序开发过程中也经常 要在自己的应用程序中加入一些Windows系统本身就有的功能,比如文件的拷贝、删除、查找以及运行程序等等。而这些功能在Windows操作系统下都 是具备的,显然如果能直接从系统中调用这些功能将不仅仅减少程序的大小和开发人员的工作量,而且由于是直接通过操作系统来完成这些功能,将会大大减小这部 分程序出现异常错误的概率。Windows系统虽说也存在不少错误,但常用功能的错误还是比较少的,而且通过补丁程序可以更低限度减少系统错误,因此程序 员可以将调试检错的注意力放在应用程序的其他地方,对于调用系统功能这部分代码则可以不必投入太大的精力去调试,因为这部分调试的工作在操作系统发布的时 候就已经由微软做好了。
二、 Windows外壳编程
前面所说的直接使用Windows操作系统部分功能的编程方法就是针对Windows操作系统外壳的编程,可以通过对操作系统提供的几个编程接口对操作 系统的部分功能进行调用,甚至可以按照自己的意图在应用程序中对部分功能进行修改、扩展。但这方面的资料介绍不是特别多,讲的也大都语焉不详,而且用通常 的编程方法去进行外壳编程是非常麻烦的,动辄就要对相关的结构对象进行设置,而这样的结构里的数据成员少则十来个多则几十个,因此配置起来非常烦琐,下面 就以一个比较简单的外壳操作–拷贝文件进行举例说明:
…… SHFILEOPSTRUCT FileOp; //外壳的文件操作结构 FileOp.hwnd=m_hWnd; //设置句柄 //设置操作方式,拷贝用FO_COPY,删除用 FO_DELETE FileOp.wFunc=FO_COPY; FileOp.pFrom=m_source; //源文件路径 FileOp.pTo=m_detect; //目标文件路径 FileOp.fFlags=FOF_ALLOWUNDO; //允许恢复 FileOp.hNameMappings=NULL; FileOp.lpszProgressTitle=strTitle; //设置标题 SHFileOperation(&FileOp); //执行外壳拷贝 if(FileOp.fAnyOperationsAborted) //监测有无中止 TRACE("An Operation was aborted!!!n"); …… |
上述代码实现起来虽然效果还是不错的,但然实现起来却是比较麻烦的,这仅仅是一个比较简单的外壳操作,对于一些比较复杂的外壳操作比如系统托盘、任务条 等等的编程,更是尤为严重,而且象此类编程,MFC里并没有提供封装好的程序类库,提供的只有系统的WinAPI 应用程序接口,因此在程序开发过程中往往会有一种在进行SDK编程的感觉。
三、 COM技术在Windows外壳编程中的应用
COM (Component Object Model,组件对象模型)是Microsoft创建的一种二进制和网络标准,也是Microsoft大力推广并已取得广泛认可的一种组件标准。在COM 标准中,COM对象被很好的封装起来,客户无法访问对象的实现细节,提供给用户的唯一的访问途径是通过COM接口来访问。对于COM接口有两方面的含义: 首先它是一组可供调用的函数,由此客户可以让该对象做某些事情;其次,也是更为重要的,接口是组件及其客户程序之间的协议。也就是说接口不但定义了可用什 么函数,也定义了当调用这些函数时对象要做什么。Windows操作系统本身作为一个大的COM组件对象,也提供了一些必要的COM接口给客户程序,因此 我们可以通过这些COM接口来直接对Windows外壳进行编程。
在程序进行正式编写设计之前有一点是肯定的:程序里需要用到COM接口,要对COM对象进行操作。因此首先要加入初始化COM和终止COM的代码。一般是在应用程序类的InitInstance()函数的开始处和返回前添加初始化COM和终止COM代码的:
…… CoInitialize(NULL); //初始化COM …… CoUninitialize(); //终止COM代码 …… |
以上两个函数在MFC程序和非MFC程序中都可以很好的使用。另外,如果程序框架是以MFC为基础的,那么只需简单的调用AfxOleInit()函数 就可以达到同样的目的。而且不必显式调用终止COM的代码。在COM标准中,访问COM对象的唯一途径是COM接口,因此在编写操纵Windows 系统外壳程序首先要得到其提供的COM接口。所用的COM接口是IShellDispatch,它是从IDispatch接口派生来的,在VC安装目录的 VC98IncludeExdisp.h头文件中有定义,下面节选了一些将要用到的接口定义:
…… EXTERN_C const IID IID_IShellDispatch; #if defined(__cplusplus) && !defined(CINTERFACE) interface DECLSPEC_UUID("D8F015C0-C278-11CE-A49E-444553540000") IShellDispatch : public IDispatch { public: …… virtual HRESULT STDMETHODCALLTYPE MinimizeAll( void) = 0; virtual HRESULT STDMETHODCALLTYPE UndoMinimizeALL( void) = 0; virtual HRESULT STDMETHODCALLTYPE FileRun( void) = 0; virtual HRESULT STDMETHODCALLTYPE CascadeWindows( void) = 0; virtual HRESULT STDMETHODCALLTYPE TileVertically( void) = 0; virtual HRESULT STDMETHODCALLTYPE TileHorizontally( void) = 0; virtual HRESULT STDMETHODCALLTYPE ShutdownWindows( void) = 0; virtual HRESULT STDMETHODCALLTYPE Suspend( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetTime( void) = 0; virtual HRESULT STDMETHODCALLTYPE TrayProperties( void) = 0; virtual HRESULT STDMETHODCALLTYPE Help( void) = 0; virtual HRESULT STDMETHODCALLTYPE FindFiles( void) = 0; virtual HRESULT STDMETHODCALLTYPE FindComputer( void) = 0; }; …… |
该接口在CoCreateInstance()函数创建COM对象时将会得到指向其的指针,通过这个函数客户程序可以避免显式同类厂打交道,其实该函数 内部也调用了CoGetClassObject()函数来获取COM对象的类厂,只不过它把通过类厂创建对象的过程封装起来了,只需用户指定对象类的 CLSID和待输出的接口指针及接口ID,显然这样直接创建COM对象是非常便捷的,在获取到COM对象指针之后就可以通过这个指针去访问调用COM对象 里的方法来实现Windows 外壳的种种功能调用了,下面是实现该功能的部分关键代码:
…… HRESULT sc;//返回结果 IShellDispatch *pShellDisp = NULL; //初始化接口指针 //直接创建COM对象 sc = CoCreateInstance( CLSID_Shell,//指定待创建的COM对象标识符 NULL, //指定被聚合时的外部对象的接口指针 CLSCTX_SERVER, //指定组件类别,可以指定进程内组件进程外组件或者进程内控制对象。 IID_IDispatch, //指定接口ID,需要注意的是这里指的是待 //创建的COM对象的接口ID,而非类厂对象的接口标识符 (LPVOID *) &pShellDisp );//存放函数返回的对象的接口指针 /* 在上述代码中,CoCreateInstance首先调用CoGetClassObject函数创建类厂对象,然后用得到的类厂对象的接口指针创建真正的COM对象,最后把类厂对象释放并返回,这样就很好的把类厂屏蔽起来,使用户用起来更为简单。*/ if( FAILED(sc) )//必须用FAILED 或SUCCECCED来判断COM对象是否创建成功 |
在这里通过pShellDisp接口指针调用了COM对象的FindFiles()方法去进行查找文件的系统外壳操作。同样,可以根据实际需要灵活调用响应的方法来执行相应的外壳操作,主要有以下几个方法:
MinimizeAll 所有窗口最小化
UndoMinimizeALL 恢复窗口最小化
FileRun 开始菜单的"运行…"
CascadeWindows 层叠窗口
TileVertically 垂直平铺
TileHorizontally 水平平铺
ShutdownWindows 关闭Windows
Suspend 挂起计算机
SetTime 设定时间
TrayProperties 任务栏属性
Help Windows帮助
FindFiles 查找文件
FindComputer 查找计算机
……
这些接口均在VC安装目录的VC98IncludeExdisp.h头文件中有定义,可以通过对该文件的查看来编写响应的外壳操作代码。
小结:本 文介绍了一种利用COM技术实现Windows系统外壳程序的简便实用的方法,对Windows系统外壳的程序设计和COM程序设计的方法和思想做了阐 述。在掌握了本文编程的中心思想前提下,不仅可以对Windows系统外壳进行程序设计,而且对于其他一些提供COM接口的应用程序进行编程,比如可以在 自己的应用程序中用类似的方法加入对Office办公套件的支持等等。因此重点不应放在具体的程序代码中,而是在于程序的设计思想与方法。本文所述程序在 Windows 98下,由Microsoft Visual C++ 6.0编译通过。
Read: 681