OLE技术

第一讲:OLE概述

OLE/ActiveX/COM技术是MS的核心应用技术,只有彻底洞察其理论精髓,才能以不变应万变。

我们首先从OLE谈起。   


一、过去的OLE和今天的OLE

    作为COM技术前身的OLE,其最初含义是指在程序之间链接和嵌入对象数据(Object Link Embeded)。它提供了建立混合文档的手段(资深Windows 3.X 用户可能记得当初在Word6.0中插入一个图形的新奇和喜悦,有关复合文档,后面文章详细讲述),使得那些没有太多专业知识的用户能够很容易地协调多个应用程序完成混合文档的建立。1991年制定的OLE1.0规范主要解决多个应用程序之间的通信和消息传递问题,微软希望第三方开发商能够遵守这个规范,以使在当时的Windows平台上的应用程序能够相互协调工作,更大的提高工作效率。然而事与愿违,只有很少的软件开发商支持它。为此,微软于1993年发布了新的规范——OLE2.0,它在原有的基础上完善并增强了以下各方面的性能: 

1.OLE自动化:一个程序有计划地控制另一个程序的能力。
2.OLE控件:小型的组件程序,可嵌入到另外的程序,提供自己的专有功能。
3.OLE文档:完善了早期的混合文档功能,不仅支持简单链接和嵌入,还支持在位激活、拖放等功能。

     强大的功能使得很多的开发商开始支持新的OLE技术,因为微软在OLE2.0中建立了一个称为COM(Component Object Model,即组件对象模式)的新规范


二、OLE应用及相关名词


    器:容器是一个客户程序,它具有申请并使用其它COM组件通过接口为其它程序实现的功能;

    服务器: 服务器通过特定的接口将自己完成的一些功能,提供给使用自己的应用程序(例如画笔程序是一个文档服务器,它提供创建并编辑BMP 图像的功能)。当打开Word,选择“插入”菜单下的“对象...”项,您可以看到在您的系统中存在哪些文档服务器,此时的Word以文档容器的身份出现

    在位激活:当您双击插入的对象后发现Word的菜单有些改变成文档服务器程序的菜单,可以在当前的环境下编辑对象,这称为在位激活。 
   
    自动化: 和OLE文档技术类似,允许一个应用程序通过编程控制另一个应用程序“自愿”提供的功能的技术称为OLE自动化。自身暴露一些可编程对象给其它程序的应用程序叫自动化服务器,利用并操纵自动化服务器提供的功能的应用程序叫自动化客户或自动化控制器,有些程序既是自动化服务器又是自动化控制器。例如在VC中我们可以通过编程创建并编辑一个Excel工作表(很多参考书都以此为例),这里的VC就是自动化控制器,而创建工作表的Excel程序则是自动化服务器,但在Excel中我们又可以利用VBA语言创建PowerPoint的幻灯片,它又成了自动化控制器。

     利用OLE自动化技术可以实现软件的一次开发和多次利用,这也是集成组件的关键技术。无论是操作系统还是应用软件,微软都有意识朝着这个方向发展,例如从Windows95开始,包括WindowsNT4.0以后的操作系统的Shell就实现了OLE自动化技术。 那么什么是ActiveX?它和OLE有什么联系?


三、ActiveX战略

    同早期的功能薄弱的OLE1.0相比,OLE2.0得到了很多软件厂商的支持。许多程序设计人员编写了大量的实现OLE自动化服务器功能的组件(不一定是EXE文件),这些组件一般不求功能齐全、强大,而是实现专门的功能,可以被其它程序编程控制,由此承袭OLE的名字称为OLE控件。

它们在文件名中的扩展名一般为OCX(OLE Control Extension) 微软刚刚赢得广大软件厂商的支持,使OLE技术深入人心,然而“人算不如天算”,国际互联网的超速发展让比尔·盖茨始料未及。加上早期的OLE1.0不得人心,导致后来的人们总把在Word中插入一个图形当作OLE技术的全部,各类资料在介绍新OLE技术时命名也不统一,造成很大的混乱。针对这些情况,微软在1996年重新制订了一个关于OLE的规范——OLE 96规范。这个规范扩展了 OLE控件的能力,并贯彻微软的Internet战略使它更易于在网络环境中使用,还考虑命名混淆的问题,重新给OLE控件贴上一个标签——ActiveX控件。不仅如此,以前的什么OLE文档也相应称为ActiveX 文档了。总之,为了满足Internet战略,微软把OLE换成了ActiveX,企图使人们重新看待新的OLE——ActiveX,把它看做网络上的解决软件组件问题的标准。许多在Windows上同微软合作得很好的厂商在开发新版本软件时都开始支持ActiveX技术,例如Delphi、PowerBuild等开发工具。原来同Windows竞争的操作系统也开始支持ActiveX,例如Macintosh,甚至老对手OS/2上也可以使用ActiveX控件。ActiveX技术也许真的会成为

 

第二讲:复合文件

复合文件,是微软COM组件思想的起源。

 

 

 

 

 

 

 

 

 

一、其产生背景

 

 

 

 

文件的存储结构通常有三种格式:

 

 

 

 

    1。非结构化文件:

     如:打开记事本程序,输入了一篇文章后,保存所得的文件。

 

 

 

 

 2。标准结构化文件:

     如:打开电子表格程序,输入一个班的学生姓名和考试成绩,保存所得的文件。

 

 

 

 

    3。自定义结构化文件

     在我们写的程序中,需要把特定的数据按照一定的结构和顺序写到文件中保存。比如 *.bmp 文件

 

 

 

 

      以上三种类型的文件,大家都见的多了。那么文件存储就依靠上述的方式能满足所有的应用需求吗?恩~~~,至少从计算机发明后的50多年来,一直是够用的了。

 

 

 

 

      下面看看商业利益的推动作用,对文件 的存储形式产生了什么变化吧。我估计以前都使用过以下几个著名的软件:WordStar(独霸DOS下的英文编辑软件),WPS(裘伯君写的中文编辑软件,据说当年的市场占有率高达90%,各种计算机培训班的必修课程),LOTUS-123(莲花公司出品的电子表格软件)......

 

 

 

 

    微软在成功地推出 Windows 3.1 后,开始垂涎桌面办公自动化软件领域。微软的 OFFICE 开发部门,各小组分别独立地开发了 WORD 和 EXCEL 等软件,并采用“自定义结构”方式,对文件进行存储。在激烈的市场竞争下,为了打败竞争对手,微软自然地产生了一个念头------如果我能在 WORD 程序中嵌入 EXCEL,那么用户在购买了我 WORD 软件的情况下,不就没有必要再买 LOTUS-123 了吗?计划产生后,他们开始了实施工作,这就是 COM 的前身 OLE 的起源(注3)。但立刻就遇到了一个严重的技术问题:需要把 WORD 产生的 DOC 文件和 EXCEL 产生的 XLS 文件保存在一起。

 

 

 

 

 

   以上两个方案,都有严重的缺陷,怎么解决那?如果能有一个新方案,能够合并前两个方案的优点,消灭缺点,该多好呀......微软是作磁盘操作系统起家的,于是很自然地他们提出了一个非常完美的设计方案,那就是把磁盘文件的管理方式移植到文件中了------复合文件,俗称“文件中的文件系统”。连微软当年都没有想到,就这么一个简单的想法,居然最后就演变出了 COM 组件程序设计的方法。可以说,复合文件是 COM 的基石。下图是磁盘文件组织方式与复合文件组织方式的类比图:

  

图一、左侧表示一个磁盘下的文件组织方式,右侧表示一个复合文件内部的数据组织方式。

 

 

 

 

二、复合文件的特点

 

 

 

 

复合文件的内部是使用指针构造的一棵树进行管理的。

复合文件中的“流对象”,是真正保存数据的空间。

不同的进程,或同一个进程的不同线程可以同时访问一个复合文件的不同部分而互不干扰;  

三、复合文件的编码实现

 

 

 

 

     为了更好理解复合文档结构,下面程序片段,演示了建立一个复合文件,并在其下建立一个子存储,在该子存储中再建立一个流,写入数据。

 

 

 

 

void SampleCreateDoc()
{       ::CoInitialize(NULL); // COM 初始化

                           // 如果是MFC程序,可以使用AfxOleInit()替代
       HRESULT hr;            // 函数执行返回值

        IStorage *pStg = NULL; // 根存储接口指针
        IStorage *pSub = NULL; // 子存储接口指针
        IStream *pStm = NULL; // 流接口指针

        hr = ::StgCreateDocfile(       // 建立复合文件
               L"c://a.stg", // 文件名称
               STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,      // 打开方式
               0,             // 保留参数
               &pStg);        // 取得根存储接口指针
        ASSERT( SUCCEEDED(hr) );       // 为了突出重点,简化程序结构,所以使用了断言。
                               // 在实际的程序中则要使用条件判断和异常处理

        hr = pStg->CreateStorage(      // 建立子存储
               L"SubStg",     // 子存储名称
               STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,
               0,0,
               &pSub);        // 取得子存储接口指针
        ASSERT( SUCCEEDED(hr) );

        hr = pSub->CreateStream(       // 建立流
               L"Stm",        // 流名称
               STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,
               0,0,
               &pStm);        // 取得流接口指针
        ASSERT( SUCCEEDED(hr) );

        hr = pStm->Write(              // 向流中写入数据
               "Hello",               // 数据地址
               5,             // 字节长度(注意,没有写入字符串结尾的/0)
               NULL);         // 不需要得到实际写入的字节长度
        ASSERT( SUCCEEDED(hr) );

        if( pStm )     pStm->Release();// 释放流指针
        if( pSub )     pSub->Release();// 释放子存储指针
        if( pStg )     pStg->Release();// 释放根存储指针

        ::CoUninitialize()             // COM 释放
                               // 如果使用 AfxOleInit(),则不调用该函数
}

图二、运行示例程序一后,使用 DFView.exe 打开观察复合文件的效果图

示例二:打开一个复合文件,枚举其根存储下的所有对象。

 

 

 

 

#include <atlconv.h>   // ANSI、MBCS、UNICODE 转换

void SampleEnum() 
{       // 假设你已经做过 COM 初始化了

        LPCTSTR lpFileName = _T( "c://a.stg" );
        HRESULT hr;
        IStorage *pStg = NULL;
        
        USES_CONVERSION;                              // (注6)
        LPCOLESTR lpwFileName = T2COLE( lpFileName ); // 转换T类型为宽字符
        hr = ::StgIsStorageFile( lpwFileName );       // 是复合文件吗?
        if( FAILED(hr) )       return;

        hr = ::StgOpenStorage(                // 打开复合文件
               lpwFileName,                   // 文件名称
               NULL,
               STGM_READ | STGM_SHARE_DENY_WRITE,
               0,
               0,
               &pStg);                        // 得到根存储接口指针

        IEnumSTATSTG *pEnum=NULL;      // 枚举器
        hr = pStg->EnumElements( 0, NULL, 0, &pEnum );
        ASSERT( SUCCEEDED(hr) );

        STATSTG statstg;
        while( NOERROR == pEnum->Next( 1, &statstg, NULL) )
        {
               // statstg.type 保存着对象类型 STGTY_STREAM 或 STGTY_STORAGE
               // statstg.pwcsName 保存着对象名称
               // ...... 还有时间,长度等很多信息。请查看 MSDN

               ::CoTaskMemFree( statstg.pwcsName ); // 释放名称所使用的内存(注6)
        }
        
        if( pEnum )    pEnum->Release();
        if( pStg )     pStg->Release();
}

四、小结

  复合文件,结构化存储,是微软组件思想的起源,在此基础上继续发展出了持续性、命名、ActiveX、对象嵌入、现场激活......一系列的新技术、新概念。因此理解和掌握 复合文件是非常重要的,即使在你的程序中并没有全面使用组件技术,复合文件技术也是可以单独被应用的。


注:可以用 DFView.exe 打开 MSWORD 的 DOC 文件进行复合文件的浏览。但是该程序并没有实现国际化,不能打开中文文件名的复合文件,因此需要改名后才能浏览。

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值