COM 组件设计与应用----起源及复合文件

C++下读写复合文档       今天的工程要用到复合文档,查了一下MSDN,没有介绍如何使用。上网查了一下,相关的资料少之又少,而且还不完整,于是想起我的电脑中存有一份DELPHI的文档,里面有介绍过如何在DELPHI下读写复合文档。虽然是DELPHI写的,但都是用SDK,转为C++应该不难。(复合文档也叫做结构化文件)读写复合文档主要用到其中的几个函数就可以了先用 StgCreateDocfile 函数创建一个复合文档 HRESULT StgCreateDocfile(    const WCHAR *pwcsName,  阅读详情

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

方案

优点

缺点

建立一个子目录,把 DOC、XLS 存储在这同一个子目录中。

数据隔离性好,WORD 不用了解 EXCEL 的存储结构;容易扩展。

结构太松散,容易造成数据的损坏或丢失。
不易携带。

修改文件存储结构,在DOC结构基础上扩展出包容 XLS 的结构。

结构紧密,容易携带和统一管理。

WORD 的开发人员需要通晓 EXCEL 的存储格式;缺少扩展性,总不能新加一个类型就扩展一下结构吧?!

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

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

三、复合文件的特点

1.复合文件的内部是使用指针构造的一棵树进行管理的。编写程序的时候要注意,由于使用的是单向指针,因此当做定位操作的时候,向后定位比向前定位要快;

2.复合文件中的“流对象”,是真正保存数据的空间。它的存储单位为512字节。也就是说,即使你在流中只保存了一个字节的数据,它也要占据512字节的文件空间。啊~~~,这也太浪费了呀?不浪费!因为文件保存在磁盘上,即使一个字节也还要占用一个“簇”的空间那;

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

4.大家都有这样的体会,当需要往一个文件中插入一个字节的话,需要对整个文件进行操作,非常烦琐并且效率低下。而复合文件则提供了非常方便的“增量访问”能力;

5.当频繁地删除文件,复制文件后,磁盘空间会变的很零碎,需要使用磁盘整理工具进行重新整合。和磁盘管理非常相似,复合文件也会产生这个问题,在适当的时候也需要整理,但比较简单,只要调用一个函数就可以完成了。

四、浏览复合文件

VC6.0 附带了一个工具软件“复合文件浏览器”,文件名是“vc目录\Common\Tools\DFView.exe”。为了方便使用该程序,可以把它加到工具(tools)菜单中。方法是:Tools\Customize...\Tools卡片中增加新的项目。运行 DFView.exe,就可以打开一个复合文件进行观察了(注4)。但奇怪的是,在 Microsoft Visual Studio .NET 2003 中,我反而找不到这个工具程序了,汗!不过这恰好提供给大家一个练习的机会,在你阅读完本篇文章并掌握了编程方法后,自己写一个“复合文件浏览编辑器”程序,又练手了,还有实用的价值。

五、复合文件函数

复合文件的函数和磁盘目录文件的操作非常类似。所有这些函数,被分为3种类型:WIN API 全局函数,存储 IStorage 接口函数,流 IStream 接口函数。什么是接口?什么是接口函数?以后的文章中再陆续介绍,这里大家只要把“接口”看成是完成一组相关操作功能的函数集合就可以了。

WIN API 函数

功能说明

StgCreateDocfile()

建立一个复合文件,得到根存储对象

StgOpenStorage()

打开一个复合文件,得到根存储对象

StgIsStorageFile()

判断一个文件是否是复合文件

 

IStorage 函数

功能说明

CreateStorage()

在当前存储中建立新存储,得到子存储对象

CreateStream()

在当前存储中建立新流,得到流对象

OpenStorage()

打开子存储,得到子存储对象

OpenStream()

打开流,得到流对象

CopyTo()

复制存储下的所有对象到目标存储中,该函数可以实现“整理文件,释放碎片空间”的功能

MoveElementTo()

移动对象到目标存储中

DestoryElement()

删除对象

RenameElement()

重命名对象

EnumElements()

枚举当前存储中所有的对象

SetElementTimes()

修改对象的时间

SetClass()

在当前存储中建立一个特殊的流对象,用来保存CLSID(注5)

Stat()

取得当前存储中的系统信息

Release()

关闭存储对象

 

IStream 函数

功能说明

Read()

从流中读取数据

Write()

向流中写入数据

Seek()

定位读写位置

SetSize()

设置流尺寸。如果预先知道大小,那么先调用这个函数,可以提高性能

CopyTo()

复制流数据到另一个流对象中

Stat()

取得当前流中的系统信息

Clone()

克隆一个流对象,方便程序中的不同模块操作同一个流对象

Release()

关闭流对象

 

WIN API 补充函数

功能说明

WriteClassStg()

写CLSID到存储中,同IStorage::SetClass()

ReadClassStg()

读出WriteClassStg()写入的CLSID,相当于简化调用IStorage::Stat()

WriteClassStm()

写CLSID到流的开始位置

ReadClassStm()

读出WriteClassStm()写入的CLSID

WriteFmtUserTypeStg()

写入用户指定的剪贴板格式和名称到存储中

ReadFmtUserTypeStg()

读出WriteFmtUserTypeStg()写入的信息。方便应用程序快速判断是否是它需要的格式数据。

CreateStreamOnHGlobal()

内存句柄 HGLOBAL 转换为流对象

GetHGlobalFromStream()

取得CreateStreamOnHGlobal()调用中使用的内存句柄

为了让大家快速地浏览和掌握基本方法,上面所列表的函数并不是全部,我省略了“事务”函数和未实现函数部分。更全面的介绍,请阅读 MSDN。

下面程序片段,演示了一些基本函数功能和调用方法。

示例一:建立一个复合文件,并在其下建立一个子存储,在该子存储中再建立一个流,写入数据。

01.void SampleCreateDoc()

02.{

03.::CoInitialize(NULL);   // COM 初始化

04.// 如果是MFC程序,可以使用AfxOleInit()替代

05. 

06.HRESULT hr;     // 函数执行返回值

07.IStorage *pStg = NULL;  // 根存储接口指针

08.IStorage *pSub = NULL;  // 子存储接口指针

09.IStream *pStm = NULL;   // 流接口指针

10. 

11.hr = ::StgCreateDocfile(    // 建立复合文件

12.L"c:\\a.stg",   // 文件名称

13.STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,    // 打开方式

14.0,      // 保留参数

15.&pStg);     // 取得根存储接口指针

16.ASSERT( SUCCEEDED(hr) );    // 为了突出重点,简化程序结构,所以使用了断言。

17.// 在实际的程序中则要使用条件判断和异常处理

18. 

19.hr = pStg->CreateStorage(    // 建立子存储

20.L"SubStg",  // 子存储名称

21.STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,

22.0,0,

23.&pSub);     // 取得子存储接口指针

24.ASSERT( SUCCEEDED(hr) );

25. 

26.hr = pSub->CreateStream( // 建立流

27.L"Stm",     // 流名称

28.STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,

29.0,0,

30.&pStm);     // 取得流接口指针

31.ASSERT( SUCCEEDED(hr) );

32. 

33.hr = pStm->Write(        // 向流中写入数据

34."Hello",        // 数据地址

35.5,      // 字节长度(注意,没有写入字符串结尾的\0)

36.NULL);      // 不需要得到实际写入的字节长度

37.ASSERT( SUCCEEDED(hr) );

38. 

39.if( pStm )  pStm->Release();// 释放流指针

40.if( pSub )  pSub->Release();// 释放子存储指针

41.if( pStg )  pStg->Release();// 释放根存储指针

42. 

43.::CoUninitialize()      // COM 释放

44.// 如果使用 AfxOleInit(),则不调用该函数

45.}

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

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

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

02. 

03.void SampleEnum()

04.{   // 假设你已经做过 COM 初始化了

05. 

06.LPCTSTR lpFileName = _T( "c:\\a.stg" );

07.HRESULT hr;

08.IStorage *pStg = NULL;

09. 

10.USES_CONVERSION;                // (注6)

11.LPCOLESTR lpwFileName = T2COLE( lpFileName );   // 转换T类型为宽字符

12.hr = ::StgIsStorageFile( lpwFileName ); // 是复合文件吗?

13.if( FAILED(hr) )    return;

14. 

15.hr = ::StgOpenStorage(          // 打开复合文件

16.lpwFileName,            // 文件名称

17.NULL,

18.STGM_READ | STGM_SHARE_DENY_WRITE,

19.0,

20.0,

21.&pStg);             // 得到根存储接口指针

22. 

23.IEnumSTATSTG *pEnum=NULL;   // 枚举器

24.hr = pStg->EnumElements( 0, NULL, 0, &pEnum );

25.ASSERT( SUCCEEDED(hr) );

26. 

27.STATSTG statstg;

28.while( NOERROR == pEnum->Next( 1, &statstg, NULL) )

29.{

30.// statstg.type 保存着对象类型 STGTY_STREAM 或 STGTY_STORAGE

31.// statstg.pwcsName 保存着对象名称

32.// ...... 还有时间,长度等很多信息。请查看 MSDN

33. 

34.::CoTaskMemFree( statstg.pwcsName );    // 释放名称所使用的内存(注6)

35.}

36. 

37.if( pEnum ) pEnum->Release();

38.if( pStg )  pStg->Release();

39.}

六、小结

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

 

复合文档的二进制存储格式 立即下载

相关推荐

家庭宽带IPv6避坑指南:如何通过DHCPv6-PD获取公网地址(附OpenWRT配置)

本文详细解析了家庭宽带IPv6的地址分配机制,重点介绍了通过DHCPv6-PD获取公网地址的方法,并提供了OpenWRT路由器的具体配置步骤。从路由器通告(RA)标记位到前缀委派(PD)流程,帮助用户解决IPv6部署中的常见问题,实现稳定高效的IPv6网络连接。

backprop5master的博客 1217

OLe复合文档介绍

/////////////////////////////////////////////////结构化存储和OLE对象///////////////////////////////////////////////// 1 引言 目前,传统的二层C/S(Client/Server)结构应用软件已发展为多层结构的分布式应用 系统[2]。为了改善系统的工作效率以及提高系统的伸缩性,很多软件开发人

让软件普及到企业中去而奋斗终生 3452

kali虚拟机-----破解wifi密码(WiFi渗透)

文章目录一、将无线网卡挂载到 虚拟机上二、查看是否挂载成功三、查看网卡是否支持监听模式四、检查文件监听影响并杀死影响五、开启无线监听模式六、开始监听七、开始抓包(新建一个命令窗口)八、对已连接的终端进行攻击,使它掉线重连,以此来获取数据包。(新建一个命令窗口)九、开始解密 一、将无线网卡挂载到 虚拟机上 可能出现的问题:在可移动设备处无法连接无线网卡; 解决:在虚拟机设置中将usb控制器设置成如图所示。 注意要先关闭虚拟机在设置。 二、查看是否挂载成功 使用ifconfig命令查看 三、查看网卡是

weixin_46471800的博客 1万+

COM 组件设计与应用(一)起源及复合文件

作者:杨老师一、前言  公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:“小杨呀,以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......”,当时我心里就寻思 :“开什么玩笑?搭积木方式写程序?再过100年吧......”,但作为一名听话的好学生,我开始在书店里“踅摸”(注1)有关OLE的书籍(注2)。功夫不负有心人,终于买到了我的第一本COM书《OLE2 高级编程技术》,这本8

wingsfly的专栏 1238

迈德威视相机调用( 基于 Linux系统+ OpenCV )

迈德威视相机调用( 基于 Linux系统+ OpenCV )前言一、登录迈德威视官网,下载官方SDK二、代码调用与视频帧处理( 基于 OpenCV )总结 前言     此博客记录了迈德威视工业相机在 Linux 系统下的代码调用及其环境配置,通过 OpenCV 对视频帧进行处理。   一、登录迈德威视官网,下载官方SDK      迈德威视官网 : http://www.mindvision.com.cn/     1. 进入官网后,在服务支持中选择软件下载。    2. 选择Linux系统S.

kkkkkk0729的博客 5680

【GPIO模拟串口通信协议】

由于这段时间搞了个安卓相关的项目,需要和安卓进行Uart通信。但是选用的芯片并没有自带uart功能,所以在充分评估项目后,考虑波特率不高的情况下,决定使用GPIO去模拟串口通信协议了。

学海无涯苦作舟 2638

复杂的结构化存取(一)

为什么80%的码农都做不了架构师?>>> ...

weixin_34007291的博客 228

Ventoy引导自定义菜单配置详解:手把手教你用ventoy_grub.cfg启动硬盘里的Manjaro

本文详细解析了Ventoy引导自定义菜单配置方法,重点介绍如何通过ventoy_grub.cfg文件启动硬盘中的Manjaro系统。从Ventoy与GRUB2的协作原理到具体配置步骤,包括分区布局设计、关键参数解析及常见问题解决方案,帮助用户实现多系统引导的灵活管理。

weixin_28738165的博客 301

COM组件设计与应用(一)——起源及复合文件

本文摘自:http://blog.vckbase.com/teacheryang/archive/2005/06/27/8883.html 一、前言   公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:“小杨呀,以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......”,当时我心里就寻思 :“开什么玩笑?搭积木方式写程序?再过100年吧......”,但作为一名听话的

发展是曲折的但也是前进的 1935

simulink调用C代码函数-C Caller模块

simulink中如何调用写好的C代码函数?使用C Caller模块调用C代码。

weixin_40531919的博客 5675

基于Simulink的电机驱动逆变器仿真

本文完成了电机驱动逆变器的Simulink多层级仿真平台搭建,实现了:✅ 构建了从理想到器件级的逆变器模型体系✅ 实现了Si/SiC损耗精确计算与结温预测✅ 建模了母线寄生参数、死区效应、栅极驱动等关键非理想特性✅ 支持故障注入与保护策略验证✅ 集成了热管理、EMI、寿命预测与碳足迹评估。

amy_mhd的博客 88

【转载】COM 组件设计与应用(一)——起源及复合文件

原文:http://vckbase.com/index.php/wv/1201.html  COM 组件设计与应用 系列文章:http://vckbase.com/index.php/piwz?&amp;p=1   一、前言 公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:“小杨呀,以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......”,当时我心里就寻思 :“开什么玩...

weixin_33802505的博客 111

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

COM 组件设计与应用1 - 起源及复合文件

一、前言  公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:“小杨呀,以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......”,当时我心里就寻思 :“开什么玩笑?搭积木方式写程序?再过100年吧......”,但作为一名听话的好学生,我开始在书店里“踅摸”(注1)有关OLE的书籍(注2)。功夫不负有心人,终于买到了我的第一本COM书《OLE2 高级编程技术》,这本800多页的大

蜗牛档案室 1712

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

COM 组件设计与应用(一)——起源及复合文件

作者:杨老师一、前言  公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:“小杨呀,以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......”,当时我心里就寻思 :“开什么玩笑?搭积木方式写程序?再过100年吧......”,但作为一名听话的好学生,我开始在书店里“踅摸”(注1)有关OLE的书籍(注2)。功夫不负有心人,终于买到了我的第一本COM书《OLE2 高级编程技术》,这

junchieh 608

COM 组件设计与应用(一)--起源及复合文件

 一、前言  公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:“小杨呀,以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......”,当时我心里就寻思:“开什么玩笑?搭积木方式写程序?再过100年吧......”,但作为一名听话的好学生,我开始在书店里“踅摸”(注1)有关OLE的书籍(注2)。功夫不负有心人,终于买到了我的第一本COM书《OLE2高级编程

Welcom to zougangx's blog 1432

【转载】COM组件设计与应用(一)——起源及复合文件

一、前言  公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:“小杨呀,以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......”,当时我心里就寻思 :“开什么玩笑?搭积木方式写程序?再过100年吧......”,但作为一名听话的好学生,我开始在书店里“踅摸”(注1)有关OLE的书籍(注2)。功夫不负有心人,终于买到了我的第一本COM书《OLE2 高级编程技术》,这本8...

weixin_30840573的博客 144

COM 组件设计与应用(一) 起源及复合文件

作者:杨老师   原文:http://www.vckbase.com/document/viewdoc/?id=1483  一、前言   公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:“小杨呀,以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......”,当时我心里就寻思 :“开什么玩笑?搭积木方式写程序?再过100年吧......”,但作为一名听话的好学生,我开始在

c++自学 726

起源及复合文件-COM 组件设计与应用(一)

COM 组件设计与应用(一)起源及复合文件作者:杨老师一、前言  公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:“小杨呀,以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......”,当时我心里就寻思 :“开什么玩笑?搭积木方式写程序?再过100年吧......”,但作为一名听话的好学生,我开始在书店里“踅摸”(注1)有关OLE的书籍(注2)。功夫不负有心人,终于买到了我的第

da1505的专栏 457

COM 组件设计与应用 - 起源及复合文件

一、前言  公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:“小杨呀,以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......”,当时我心里就寻思 :“开什么玩笑?搭积木方式写程序?再过100年吧......”,但作为一名听话的好学生,我开始在书店里“踅摸”(注1)有关OLE的书籍(注2)。功夫不负有心人,终于买到了我的第一本COM书《OLE2 高级编程技术》,这本800多页的大

885
上一篇: 改变 CListCtrl、CHeaderCtrl 高度、字体、颜色和背景
下一篇: IOCP
htt9931
博客等级 码龄24年 43粉丝 14原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值