二、CLSID 概念
有一个非常简单的解决方案,那就是在对象数据的前面,保存有处理这个数据的程序名。(见下图左上)
图一、CLSID 的概念
这的确是一个简单的方法,但同时问题也很严重。在“张三”的计算机上,Excel 的路径是:"c:\office\Excel.exe",如果把这个 doc 文件复制到“李四”的计算机上使用,而“李四”的 Excel 的路径是:
"d:\Program files\Microsoft Office\Office\Excel.exe",完蛋了:-(
于是,微软想出了一个解决方案,那就是不使用直接的路径表示方法,而使用一个叫 CLSID(注1)的方式间接描述这些对象数据的处理程序路径。CLSID 其实就是一个号码,或者说是一个16字节的数。观察注册表(上图),在HKCR\CLSID\{......}主键下,LocalServer32(DLL组件使用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亿年。反正等到地球没有了都不会使用完的:-)