COM 组件设计与应用

目录

COM 设计用(一) 起源及合文件... 1

COM设计用(二) GUID 接口... 10

COM设计用(三) 数据... 20

COM设计用(四) 简单调... 31

 

COM 设计用(一)
起源及合文件

作者:

一、前言

  公元一九九五年某个夜黑高的上,我的一位老跟我呀,以后写程序就和搭木一啦。你赶快学一些OLE的技......”,当我心里就 玩笑?搭木方式写程序?再100年吧......”,但作一名听的好学生,我始在店里踅摸(注1)有OLE籍(注2)。功夫不有心人,到了我的第一本COMOLE2 级编程技》,800的大布了我1/5的月工......于是始日夜耕.....
功夫不有心人,我完了全部著作,感想是:,在么呐
功夫不有心人,我又完了一遍大布,感想是:咳~~~,没懂!
功夫不有心人,我再,我再,我再 ... 感想是:哦~~~懂了一点点啦,哈哈哈。
...... ......
功夫不有心人,我于,我于懂了。
800
书对现在的我来,其也就10有用。到这时候才体会出什越薄的道理了。到后来,能到的也多了,上网也更方便更便宜了......

  VCKBASE上的朋友,不再经历我曾的痛苦、不再重蹈我头苍蝇般探索的辛、VCKBASE的蓬勃展、了中国件事腾飞(糟糕,吹的太也高了)......我打算节约一些在 BBS 分的时间,写个系列文,就叫“COM设计吧。今天是第一部分——起源。

二、文件的存

  传说350年前,牛被苹果到了,于是发现了万有引力。但到了二十一世在,任何一个技明和展,已不再依靠圣人灵光的一。技进步转而是被社会的需求、商的利益、争的力、行透等推的。微Windows平台上的件技也不例外,它的明,有其必然因素。什个因素那?答案是——文件的存
  打开记事本程序,入了一篇文章后,保存。——这样的文件叫构化文件
  打开电子表格程序,入一个班的学生姓名和考,保存。——这样的文件叫构化文件
  在我写的程序中,需要把特定的数据按照一定的构和序写到文件中保存。——这样的文件叫自定义结构化文件;(比如 *.bmp 文件)
  以上三种类型的文件,大家都的多了。那文件存就依靠上述的方式能足所有的用需求?恩~~~,至少从算机明后的50多年来,一直是用的了。嘿嘿,下面看看商利益的推作用,文件 的存形式生了什么变化吧。30以上的朋友,我估以前都使用以下几个著名的件:WordStar(独霸DOS下的英文编辑软件),WPS( 裘伯 君写的中文编辑软件,据当年的市占有率高达90%,各种计算机培班的必修程),LOTUS-123花公司出品的子表格件)......
在成功地推出 Windows 3.1 后,始垂涎桌面公自域。微 OFFICE 开发,各小独立地开发 WORD EXCEL 件,并采用自定义结方式,文件行存。在激烈的市场竞争下,了打败竞手,微自然地生了一个念------如果我能在 WORD 程序中嵌入 EXCEL,那购买了我 WORD 件的情况下,不就没有必要再 LOTUS-123 ?!(中国微的同志看到了,不要激,我是加了引号的呀)的生后,他们开始了施工作,就是 COM 的前身 OLE 的起源(注3)。但立刻就遇到了一个重的技术问题:需要把 WORD 生的 DOC 文件和 EXCEL 生的 XLS 文件保存在一起。
 

方案

缺点

建立一个子目,把 DOCXLS 同一个子目中。

数据隔离性好,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
下面程序片段,演示了一些基本函数功能和用方法。
示例一:建立一个合文件,并在其下建立一个子存,在子存中再建立一个流,写入数据。

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> // ANSIMBCSUNICODE 转换

 

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象嵌入、现场激活......一系列的新技、新概念。因此理解和掌握 合文件是非常重要的,即使在你的程序中并没有全面使用件技合文件技也是可以独被用的。祝大家学社会主义软件事:-)

留作......
1:写个小用程序,从 MSWORD doc 文件中,提取出附加信息(作者、公司......)。
2:写个全功能的合文件浏览编辑

1:踅摸(xuemo)动词,北方方言,找搜索的意思。
2不上网查资料学
答:玩笑!在那遥1995年代,我的500,不吃不喝正好100Internet网。
3OLE象的接与嵌入。
4:可以用 DFView.exe MSWORD DOC 文件合文件的浏览。但是程序并没有实现化,不能打中文文件名的合文件,因此需要改名后才能浏览
5CLSID,在后的文章中介
6 COM 中内存使用的问题,在后的文章中介

 

 

COM设计用(二)
GUID
接口

作者:

一、前言

  接上回话说 doc(Word) 合文件中,已解决了保存 xls(Excel) 数据的问题了。那,接下来又要解决另一个问题:当 WORD 程序合文件,遇到了 xls 数据的候,它如何启 Excel 呢?启后,又如何 Excel 自己去入、解析、 xls 数据呢?

二、CLSID 概念

  有一个非常简单的解决方案,那就是象数据的前面,保存有个数据的程序名。(左上)

一、CLSID 的概念

  的确是一个简单的方法,但同时问题也很重。在算机上,Excel 的路径是:"c:/office/Excel.exe",如果把 doc 文件制到李四算机上使用,而李四 Excel 的路径是:
"d:/Program files/Microsoft Office/Office/Excel.exe"
,完蛋了:-(
  于是,微想出了一个解决方案,那就是不使用直接的路径表示方法,而使用一个叫 CLSID(注1)的方式接描述象数据的理程序路径。CLSID 就是一个号,或者是一个16的数。察注册表(上),在HKCR/CLSID/{......}下,LocalServer32DLL件使用InprocServer32 中保存着程序路径名称。CLSID 构定如下:

typedef struct _GUID {

       DWORD Data1;  // 随机数

       WORD Data2;   // 时间

       WORD Data3;   // 时间

       BYTE Data4[8];      // 和网卡MAC

} GUID;

 

typedef GUID CLSID;  // ID

typedef GUID IID;    // 接口ID

#define REFCLSID const CLSID &

 

// 的声明和赋值方法

CLSID CLSID_Excel = {0x00024500,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};

struct __declspec(uuid("00024500-0000-0000-C000-000000000046")) CLSID_Excel;

class DECLSPEC_UUID("00024500-0000-0000-C000-000000000046") CLSID_Excel;

// 注册表中的表示方法

{00024500-0000-0000-C000-000000000046}

  用一个号码间接表示程序名,的确是个 Good idea实现件位置的透明性,并方便地展出 DCOM件)。但,但,但,但.....CLSID 16个字128位二制数,干这么长的数字呀?遥想当年......在上幼儿园的候,人们设计 socket,用 TCP/IP 协议进行网个参与通算机都有一个4 IP 表示号地址,范 0,0,0,0 ~ 255,255,255,255 42亿个地址。可是没想到啊,没想到,自从 Internet 选择TCP/IP 协议后,42亿个地址就不全世界的劳动人民分配啦。除了劳动人民,有冰箱、彩电饭锅、手机、手提电脑......些都需要网呀。在公室通络开电饭锅给焖饭,下班回家后就能吃成的啦,多幸福呀?!(注:在我家老婆是领导,所以是我做。咳......
由于前,微软这设计 CLSID/IID 就使用了GUID概念的16个字下好啦,全世界60亿人口,个人分配10亿个号,那需要分配1800亿年。反正等到地球没有了都不会使用完的:-)

三、 CLSID
 

  1. 如果使用开发环件程序,IDE会自帮你 CLSID
  2. 你可以手工写 CLSID,但千万不要和人家已生成的 CLSID 呀,所以重地不推荐;(可是微CLSID都是手工写的,州官放火,不百姓点灯
  3. 程序中,可以用函数 CoCreateGuid() CLSID
  4. 使用工具 GUID(注2);

vc6.0版本运行:"vc/Common/Tools/GuidGen.exe"程序(你可以参照上回文章中介的方法,把个工具程序加到开发环境中,方便用)。vc.net版本,在菜工具/GUID”中,就可以行了。

四、ProgID 概念

  一个COM件都需要指定一个 CLSID,并且不能重名。它之所以使用16个字,就是要从概率上保不可能的。但是,(世界上就怕但是二字)微软为了使用方便,也支持另一个字符串名称方式,叫 ProgID(3)。注册表的ProgID 内容(注4)。由于 CLSID ProgID 是一个概念的两个不同的表示形式,所以我在程序中可以随便使用任何一。(有些人就是讨厌说话不算数。明明 GUID 的目的就是禁止重,但居然又允使用 ProgID?!ProgID 是一个字符串的名字,重的可能性就太大了呀。赶明儿我也写个程序,我打算个程序的 ProgID “Excel.Application”,嘿嘿)下面介一下 CLSID ProgID 转换方法和相的函数:

函数

功能

CLSIDFromProgID()CLSIDFromProgIDEx()

ProgID 得到 CLSID。没什的,你自己都可以写,注册表

ProgIDFromCLSID()

CLSID 得到 ProgID用者使用完成后要 ProgID 的内存(5)

CoCreateGuid()

随机生成一个 GUID

IsEqualGUID()IsEqualCLSID()IsEqualIID()

2ID是否相等

StringFromCLSID()StringFromGUID2()StringFromIID()

CLSID,IID 得到注册表中CLSID式的字符串,注意放内存

五、接口(Interface)的来

  到此,我知道了 CLSID ProgID 唯一地表示一个件服程序,那根据ID,就可以加运行件,并端程序提供服了。(启动组件程序的方法,会陆续)。接下来先讨论如何件提供的函数?-----接口。
  作端程序,它希望或者他要求:我的程序只写一次,然后不做任何修改就可以用任意一个件。例来

  1. 你可以在 Word 中嵌入 Excel,也可以嵌入 Picture,也可以嵌入任何第三方表的 ActiveX 文档......也就是 Word 自己都不知道使用它的人将会在 doc 里面插入什么东东
  2. 你可以在 HTML 文件中插入一个 ActiveX,也可以插入一个程序脚本Script......你自己写的插件也可以插入到 IE 境中。了完成你的功能, 绝对也不会去修改IE吧?!

  个要求在有点度,Office 开发停滞了。巧,一天老O(Office 目的工程)和小B(VB 目的工程)一起喝酒,老O向小B倾诉了他的烦恼
O:怎我写的程序C,可以用其它人写的程序S中的函数?(C表示客程序,S表示提供服的程序)
B:你是不是喝糊涂了?S作成 DLL,你去 LoadLibrary()GetProcAddress()...FreeLibrary()?!
O废话!要是这么简单就好了。问题是,我都不知道S程序是干什的?能干什?我怎么调用呀?
B:哦......个比,但我在不能告你,因我怕你印象不深。
O~·#%……—*......
B:是这样的,在VB中,我制定了一个准,准允任何一个VB开发者,把他自己写的某个功能的小程序放在VB的工具上,这样就好象他展了 VB 的功能一
O:哦?就是那个叫什 VBX 玩意儿?
B:我...... VBX 西不起眼儿,的确我也没看上它。但你猜怎着?在有成千上万的 VB 程序好者把他写的各式各功能的 VBX 小程序,放到网上,大家共享那。
O:哦~~~,那你 VBX 准是什
B:嘿嘿......简单,就是在 VBX 中必须实现7个函数,7个函数名称和功能必是:初始化、放、示、消息......,而至于它内部想干什,我也管不着。我只是在需要的用我需要的7个函数。
O:哦~~~这样......了,我有个急事,我先走了。88,你付......
B:喂!喂喂...... 这么急干什包都掉了:-)
  老O包,仍然兴奋地冲回公室,他始了思考......

1、我的程序C,要能用任何人写的程序B。那B要按照我事先的要求,提供我需要的函数F1(),F2(),F3(),K1(),K2()
2
BASIC 是解释执行,因此它的函数不用考虑书序,只要出函数名,解器就能找到。但我使用的是 C++......
3
C++编译后的代中没有函数名,只有函数地址,因此我必进为VTAB(虚函数表)表示函数入口:

二、VTAB

4
好,需要改一下,因所有的函数地址都放在一个表中会不灵活、不好修改、不易展。恩,有了!按照函数功能的行分

三、多个 VTAB

5
问题又来了,在有2 VTAB 虚函数表,那从一个表找到另一个表那?恩又有法了,我要求你必实现一个函数,并且个函数地址必放在所有表的开头(表中的第一个函数指),个函数就叫 QueryInterface()吧,完成从一个表找到另一个表的功能:(除了QueryInterface()函数,便也完成另外两个函数,叫 AddRef() Release()两个函数的功能以后再

四、COM 接口

6
了以后描述方便,不再使用上四)的方法了,而使用这样简洁式:

五、COM 接口构的简洁图


六、接口(Interface)概念

1、函数是通 VTAB 虚函数表提供其地址, 从另一个角度来看,不管用什么语开发编译生的代都能生成个表。这样实现件的制特性实现件的跨言要求。
2
、假有一个指量保存着 VTAB 的首地址,则这量就叫接口指”(6) 量命名的候,习惯上加上"I"开头。另外了区分不同的接口,个接口 也都要有一个名字,名字就和 CLSID ,使用 GUID 方式,叫 IID
3
、接口一经发表,就不能再修改了。不然就会出向前兼容的问题个性接口不
4
件中必3个函数,QueryInterfaceAddRefRelease,它3个函数也成一个接口,叫"IUnknown"(7)
5
、任何接口,其都包含了 IUnknown 接口。随着你接触到更多的接口就会了更体会解到接口的另一个性承性
6
、在任何接口上,用表中的第一个函数,就是 QueryInterface()函数,就得到你想要的另外一个接口指个性接口的传递
7
C/C++言中需要事先函数声明,那 会要求件也必提供C言的文件。不行!了能使COM具有跨言的能力,决定不再任何言提供对应的函数接口声明,而是独立地提供一个叫TLB)的声明。言的IDE境自己去根据TLB生成自己言需要的包装。个性接口声明的独立性(注8

七、客程序与件之

  回到我的上一个话题Word中嵌入一个件,那Word是如何商使用件的那?下面是容器和件之的一个模拟对话过程:
 

 

容器 商部分

答部分

1

根据CLSID动组
CoCreateInstance()

生成象,行构造函数,行初始化作。

2

你有IUnknown接口

有,你!

3

恩,太好了,那你有IPersistStorage接口(9)
IUnknown::QueryInterface(IID_IPersistStorage...)

没有!

4

真差连这个都没有。那你有IPersistStreamInit接口(10)
IUnknown::QueryInterface(IID_IPersistStreamInit...)

哈,个有,

5

好,好,这还差不多。你我初始化吧。
IPersistStreamInit::InitNew()

OK,初始化完成了。

6

完成了?好!在你数据去吧。
IPersistStreamInit::Load()

完啦。我根据数据,已在窗口中示出来了。

7

好,在咱各自理用的鼠键盘消息吧......

......

8

哎呀!用要保存退出程序了。你的数据被用修改了
IPersistStreamInit::IsDirty()

改了,用修改啦。

9

那好,那修改后,你的数据需要多大的存呀?
IPersistStreamInit::GetSizeMax()

恩,我算算呀......好了,共需要500KB

10

,你这么个小玩意居然占用这么大空?!......好了,你可以存了。
IPersistStreamInit::Save()

谢谢,我已存好了。

11

恩。拜拜了您那。(11)
IPersistStreamInit::Release()
IUnknown::Release()

行析构函数,象。

12

我自己也退出了......
PostQuitMessage()

 

  容器(或者端)就是这样对话用的。如果件甲实现 IA 接口,那容器就会使用它,如果件乙没有提供 IA 接口,但是它提供了 IB 接口,那容器就会 IB 接口的函数......如此,容器程序根本就不需要知道件到底是干什的,件到底是用什么语开发的,件的磁位置到底在哪里,它都可以正常运行。太奇妙了!太精彩了!怎一个字了得!

八、小

  第二回中,介了两个非常重要的概念:CLSID Interface。由于全篇都是概念描述而没有示例程序相配合,可能者的理解不太深入、不底。着急,我们马上就要入到件程序设计阶段了,到那个候,你根据具体的程序代,再回过头来再次阅读本回文章,没懂?哦......!慢慢地您老人家就懂了:-)

留作......
1
IDispatch 接口的 IID 是多少?(哎~~~ 笨笨,在源程序中,用鼠键执Go to definition 呀)
2
IPicture 接口有几个函数?功能是什?(玩了!你多大了?想不想在程序中 JPG 像呀,看 MSDN 去)
  想知道COM函数是返回 HRESULT ?想知道如何使用 BSTRVARIANT ?想知道 COM 应该如何使用内存?想知道如何使用 UNICODE ......~~~,我在不能告你,我在告你,怕你印象不深!且听下回分解......

1CLSID = Class ID 上回了把CLSID写入合文件的函数:WriteClassStg()IStorage::SetClass()
2GUID 全局唯一示符,CLSID/IID 是借用了GUID的概念。
3ProgID = Program ID,等价于 CLSID, 是用字符串表示的。
4:注册表子 ProgID VersionIndependentProgID 表示真正的 ProgID 和版本无 ProgID。比如在我算机上安装的 Excel,它的 ProgID = "Excel.Application.9",而 VersionIndependentProgID = "Excel.Application"
5COM 件的内存管理,的文章。
6Interface = 接口,以前微不叫它接口,而叫协议Protocol。其 认为这

你可能感兴趣的:(COM 组件设计与应用)