选择显示字体大小

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\{......}主键下,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亿个地址。可是没想到啊,没想到,自从 inte.net 选择了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()比较2个id是否相等
stringfromclsid()、stringfromguid2()、stringfromiid()由 clsid,iid 得到注册表中clsid样式的字符串,注意释放内存

  五、接口(interface)的来历

  到此,我们已经知道了 clsid 或 progid 唯一地表示一个组件服务程序,那么根据这些id,就可以加载运行组件,并为客户端程序提供服务了。(启动组件程序的方法,会陆续介绍)。接下来先讨论如何调用组件提供的函数?-----接口。

  作为客户端程序员,它希望或者说他要求:我的程序只写一次,然后不做任何修改就可以调用任意一个组件。举例来说:
  1. 你可以在 word 中嵌入 excel,也可以嵌入 picture,也可以嵌入任何第三方发表的 activex 文档......也就是说,连 word 自己都不知道使用它的人将会在 doc 里面插入什么东东;
  2. 你可以在 html 文件中插入一个 activex,也可以插入一个程序脚本script,......你自己写的插件也可以插入到 ie 环境中。为了完成你的功能, 你绝对也不会去让微软修改ie吧?!


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons