如何认识COM及其应用研究

来源 :北京电力高等专科学校学报 | 被引量 : 0次 | 上传用户:cairaymond
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  摘 要:本文开拓性的讨论了如何准确的认识COM,重新给COM进行定义和解释,针对COM的新理解,指出了如何创建、使用和销毁COM对象,并对IUnknown的基本接口与方法和在COM代码中如何处理串做了研究,由此引出了COM的新应用。
  关键词:COM;概念;应用
  中图分类号:TP3 文献标识码:A 文章编号:1009-0118(2012)-02-0-03
  一、COM到底是什么?
  从表层的意思看,COM是Component Object Model 取前三个字母的缩写,即组件对象模型,这三个字母在Windows的世界中随处可见。随时涌现出来的众多新技术都以COM为基础,各种文档中也充斥着诸如COM对象、接口、服务器之类的术语。从另一个角度讲,COM是一种跨应用和语言共享二进制代码的方法。与C++不同的是,它提倡源代码重用,其中ATL便是一个很好的例证。
  从定义可以看出,COM通过定义二进制标准解决了源代码重用和代码使用受限等问题,即COM明确指出二进制模块(DLLs和EXE)必须被编译成与指定的结构匹配。这个标准也确切规定了在内存中如何组织COM对象。COM定义的二进制标准还必须独立于任何编程语言(如C++中的命名修饰)。一旦满足了这些条件,就可以轻松地从任何编程语言中存取这些模块。由编译器负责所产生的二进制代码与标准兼容。这样使后人就能更容易地使用这些二进制代码。在内存中,COM对象的这种标准形式在C++虚函数中偶尔用到,所以这就是为什么许多COM代码使用C++的原因。但是,编写模块所用的语言是无关的,因为在结果里二进制代码为所有语言可用。
  二、COM的基本元素定义
  从下往上看,接口只不过是一组函数,这些函数被称为方法。接口名字以大写的I开头,例如C++中的IShellLink,接口被设计成一个抽象基类,其中只有纯粹的虚拟函数。接口可以从其它接口继承,这里所说的继承的原理就类似C++中的单继承(接口是不允许多继承的)。coclass(简称组件对象类——component object class)被包含在DLL或EXE中,并且包含着一个或者多个接口的代码。组件对象类(coclasss)实现这些接口。COM对象在内存中表现为组件对象类(coclasss)的一个实例。当然COM“类”和C++“类”是不相同的,尽管常常称COM类实现的就是一个C++类。
  COM服务器是包含了一个或多个coclass的二进制(DLL或EXE)。注册(Registration)是创建注册表入口的一个过程,告诉操作系统COM服务器放在什么位置。取消注册(Unregistration)则相反,是从注册表删除这些注册入口。
  GUID(全球唯一标识符globally unique identifier)是个128位的数字,它是一种独立于COM编程语言的标识方法。每一个接口和coclass有一个GUID。因为每一个GUID都是全球唯一的,所以只要我们用COM API创建它们,就避免了名字冲突。类ID或者CLSID是命名coclass的GUID。接口ID或者IID是命名接口的GUID。在COM中广泛地使用GUID有两个理由:一是GUID只是简单的数字,任何编程语言都可以对之进行处理。二是GUID可以在任何机器上被任何人创建,一旦完成创建,它就是唯一的。因此,COM开发人员可以创建自己特有的GUID而不会与其它开发人员所创建的GUID有冲突。这样就消除了集中授权发布GUID的必要。
  三、创建和销毁COM对象
  (一)创建COM对象:为了创建COM对象并从这个对象获得接口,必须调用COM库的API函数,CoCreateInstance()。其原型为:
  HRESULT CoCreateInstance (
  REFCLSID rclsid, // rclsid:coclass的CLSID,例如,可以传递CLSID_ShellLink创建一个COM对象来建立快捷方式
  LPUNKNOWN pUnkOuter, // pUnkOuter:这个参数只用于COM对象的聚合,利用它向现有的coclass添加新方法。参数值为null表示不使用聚合
  DWORD dwClsContext, // dwClsContext:表示所使用COM服务器的种类。在使用的是最简单的COM服务器时,如一个进程内(in-process)DLL,传递的参数值为CLSCTX_INPROC_SERVER
  REFIID riid, // riid:请求接口的IID。例如,可以傳递IID_IShellLink获得IShellLink接口指针
  LPVOID* ppv ); // ppv:接口指针的地址。COM库通过这个参数返回请求的接口
  当我们调用CoCreateInstance( )时,它负责在注册表中查找COM服务器的位置,将服务器加载到内存,并创建我们所请求的coclass实例。以下是一个创建CLSID_ShellLink对象的实例并请求指向这个对象IShellLink接口指针。
  HRESULT hr;
  IShellLink* pISL;
  hr = CoCreateInstance ( CLSID_ShellLink, // coclass 的CLSID
  NULL, // 不是用聚合
  CLSCTX_INPROC_SERVER, // 服务器类型
  IID_IShellLink, // 接口的IID
  (void**) &pISL ); // 指向接口的指针
  if ( SUCCEEDED ( hr ) )
  {
   // 用pISL调用方法
   }
   else
   {
   // 不能创建COM对象,hr 为出错代码
   }
  首先声明一个接受CoCreateInstance()返回值的HRESULT和IShellLink指针,调用CoCreateInstance()来创建新的COM对象,如果hr接受到一个表示成功的代码,则SUCCEEDED宏返回TRUE,否则返回FALSE,FAILED是一个与SUCCEEDED对应的宏用来检查失败代码。
  (二)销毁COM对象:对于COM对象,不用释放,只需告诉已经用完对象即可。IUnknown是每一个COM对象必须实现的接口,它有一个Release()方法,调用这个方法通知COM对象我们不再需要;一旦调用了这个方法之后,就不能再次使用这个接口,因为这个COM对象可能从此就从内存中消失。
  在应用程序使用许多不同的COM对象的情况下,在用完某个接口后调用Release()就显得非常重要:如果不释放接口,这个COM对象(包含代码的DLLs)将保留在内存中,这会增加不必要的开销;如果应用程序要长时间运行,就应该在应用程序处于空闲期间调用CoFreeUnusedLibraries()API,这个API将卸载任何没有明显引用的COM服务器,因此这也降低了应用程序使用的内存开销。
  继续用上面的例子来看看该如何使用Release()://像上面一样创建COM对象,然后,
   if ( SUCCEEDED ( hr ) )
  {
  // 用pISL调用方法
  // 通知COM 对象不再使用它
  pISL->Release();
  }
  四、IUnknown的基本接口与方法
  (一)AddRef(),通知COM对象增加它的引用计数。如果进行了一次接口指针的拷贝,就必须调用一次这个方法,并且原始的值和拷贝的值两者都要用到。
  (二)Release(),通知COM对象减少它的引用计数。
  (三)QueryInterface(),从COM对象请求一个接口指针,当coclass实现一个以上的接口时,就要用到这个方法。
  该如何使用QueryInterface()呢?当使用CoCreateInstance()创建对象的时候,就会得到一个返回的接口指针,如果这个COM对象实现一个以上的接口(不包括IUnknown),就必须用QueryInterface( )方法来获得任何需要的附加的接口指针。QueryInterface( )的原型如下:
  HRESULT IUnknown::QueryInterface (
  REFIID iid, // iid:所请求的接口的IID
  void** ppv ); // ppv:接口指针的地址,QueryInterface()通过这个参数在成功时返回该接口
  在外壳链接的例子实现了IShellLink 和IPersistFile接口。如果已经有一个IShellLink指针pISL,可以从COM对象请求IPersistFile接口:
  HRESULT hr;
  IPersistFile* pIPF;
  hr = pISL->QueryInterface ( IID_IPersistFile, (void**) &pIPF );
  然后使用SUCCEEDED宏检查hr的值以确定QueryInterface()的调用情况,如果成功的话就可以象使用其它接口指针那样使用新的接口指针pIPF。必须记住的是调用pIPF->Release()通知COM对象已经用完这个接口。
  五、在COM代码中处理串
  任何时候,只要COM方法返回一个串,这个串都是Unicode串(这里指的是写入COM规范的所有方法)。Unicode是一种字符编码集,类似ASCII,但用两个字节表示一个字符。如果想更好地控制或操作串的话,应该将它转换成TCHAR类型串。
  TCHAR和以_t开头的函数(如_tcscpy())被设计用来让我们用相同的源代码处理Unicode和ANSI串。在大多数情况下编写的代码都是用来处理ANSI串和ANSI WindowsAPIs,这里所说的字符串都是指TCHAR类型。
  我们可以用WideCharToMultiByte()将一个Unicode串转换成一个ANSI串,函数的原型如下:
  int WideCharToMultiByte (
  UINT CodePage, // CodePage:Unicode字符转换成的代码页
  DWORD dwFlags, // dwFlags:确定Windows如何处理“复合” Unicode字符,它是一种后面带读音符号的字符
  LPCWSTR lpWideCharStr, // lpWideCharStr:要转换的Unicode串
  int cchWideChar, // cchWideChar:lpWideCharStr在Unicode 字符中的长度。通常传递-1,表示串是以0x00结尾
  LPSTR lpMultiByteStr,// lpMultiByteStr:接受转换的串的字符缓冲
  int cbMultiByte,// cbMultiByte:lpMultiByteStr的字节大小
  LPCSTR lpDefaultChar, //lpDefaultChar:可选,当dwFlags包含WC_COMPOSITECHECK | WC_DEFAULTCHAR并且某个Unicode字符不能被映射到同等的ANSI串时所传递的一个单字符ANSI串,包含被插入的“缺省”字符
  LPBOOL lpUsedDefaultChar ); // lpUsedDefaultChar:可选,指向BOOL类型的一个指针,设置它来表示是否缺省字符曾被插入ANSI串。可以传递NULL来忽略这个参数
  下面是帮助理解如何使用这个API的例子//假设已经有了一个Unicode 串 wszSomeString...
  char szANSIString [MAX_PATH];
  WideCharToMultiByte ( CP_ACP, // ANSI 代码页
  WC_COMPOSITECHECK, //检查重音字符
  wszSomeString, // 原Unicode 串
  -1, // -1 意思是串以0x00结尾
  szANSIString, // 目的char字符串
  sizeof(szANSIString), // 缓冲大小
  NULL, // 肥缺省字符串
  NULL ); // 忽略这个参数
  调用这个函数后,szANSIString将包含Unicode串的ANSI版本。CRT函数wcstombs()是个简化版,但它终结了WideCharToMultiByte()的调用,所以最终结果是一样的。其原型如下:
  size_t wcstombs (
  char* mbstr, // mbstr:接受结果ANSI串的字符(char)缓冲
  const wchar_t* wcstr, // wcstr:要轉换的Unicode串
  size_t count ); // count:mbstr参数所指的缓冲大小
  六、COM技术应用(可以说明COM概念的例子)
  下面的两个例子可以帮助演示前文所述的COM概念,第一个例子展示的是单接口COM对象,使用外壳中的活动桌面组件对象类(CLSID_ActiveDesktop)来获得当前桌面墙纸的文件名,是相对简单的例子,应用前提是系统中安装了活动桌面(Active Desktop)。编程步骤如下:
  (一)初始化COM库。(Initialize)
  (二)创建一个与活动桌面交互的COM对象,并取得IActiveDesktop接口。
  (三)调用COM对象的GetWallpaper( )方法。
  (四)如果GetWallpaper()成功,则输出/显示墙纸文件名。
  (五)释放接口(Release())。
  (六)收回COM库(Uninitialize)。
  WCHAR wszWallpaper [MAX_PATH];
  CString strPath;
  HRESULT hr;
  IActiveDesktop* pIAD;
  CoInitialize ( NULL );
  hr = CoCreateInstance ( CLSID_ActiveDesktop,
  NULL,
  CLSCTX_INPROC_SERVER,
  IID_IActiveDesktop,
  (void**) &pIAD );
  if ( SUCCEEDED(hr) )
  {
  hr = pIAD->GetWallpaper ( wszWallpaper, MAX_PATH, 0 );
  if ( SUCCEEDED(hr) )
  {
  wcout << L"Wallpaper path is:\n " << wszWallpaper << endl << endl;
  }
  else
  {
  cout << _T("GetWallpaper() failed.") << endl << endl;
  }
  pIAD->Release();
  }
  else
  {
  cout << _T("CoCreateInstance() failed.") << endl << endl;
  }
  CoUninitialize();
  在这个例子中,输出/显示Unicode 串 wszWallpaper用的是std::wcout。
  
  参考文献:
  [1](美)Box,D.潘爱民译.Essential COM[M].北京:中国电力出版社,2001.
  [2]潘爱民.COM 原理与应用[M].北京:清华大学出版社,1999.
  [3](美)Dale Rogerson.COM技术内幕[M].北京:清华大学出版社,1999.
其他文献
摘 要:本文以湖南黑麋峰抽水储能水电站为实例研究抽水储能电站的静态效益和动态效益,对如何对其进行评价,充分发挥抽水储能电站在电网中的调节作用等方面进行了讨论。  关键词:抽水储能电站;经济效益;综合评价  中图分类号:TM67 文献标识码:A
期刊
摘 要:图书馆的发展要注重创新与构建和谐。在创新和构建和谐形式下寻求发展是图书馆发展的根本。本文从数字信息时代图书馆、服务理念的转变、和谐社会的构建三方面探讨建设海南国际旅游岛新形式下,适合形式发展的新时代图书馆。  关键词:数字信息图书馆;创新;服务;和谐  中图分类号:G25
期刊
摘 要:随着近年来高科技的不断发展,变电站向着数字化方向发展。数字化变电站也得到 了业界人士的广泛重视,数字化变电站在传统的IEC61850通信规约的基础上,发展为智能化一次设备和网络化二次设备分层共同组建,实现了变电站设备间信息共享和互操作的现代化变电站,本文根据国内外变电站的发展和运行情况,简单介绍了基于IEC61850数字化变电站的电气二次设计的过度方案。  关键词:数字化变电站;
期刊
摘 要:介绍了输配电设备的关键技术,如输配电线路中的降耗节能技术,成功实现带电作业技术,实现输配电线路中的运行与保护技术等技术。  关键词:输配电线路 降耗节能 带电作业 运行保护  中图分类号:TM73 文献标识码:A
期刊
摘 要:通过调查发现,羽毛球运动中运动员膝关节的损伤比较高。本文就羽毛球运动中,导致膝关节运动损伤的原因、损伤类型和治疗方法进行分析研究,旨在为羽毛球运动爱好者预防和治疗运动损伤提供理论依据。  关键词:羽毛球;膝关节损伤;预防  中图分类号:G642 文献标识码:A
期刊
摘 要:如果我们的计算机安装了操作系统, 并处于网络中。那么在计算机黑客肆虐的今天, 作为一名用户如何保护自己的网络安全? 如何进行有效的防御?当今开放的信息系统必然存在众多潜在的安全隐患,黑客和反黑客、破坏和反破坏的斗争仍将继续。在这样的斗争中,安全技术作为一个独特的领域越来越受到IT行业的关注。随着计算机网络技术的迅速发展,计算机网络安全日益突显, 计算机网络安全面临的主要威胁有黑客侵袭、计算
期刊
摘 要:在体育教学中后进生是客观存在的。但在体育教学中,往往只注重对大多数学生的教育与培养,而忽视对个别后进生的帮助,从而加大了他们之间的距离。本文通过分析后进生出现的原因,找出培养后进生的部分方法,从而整体提高体育教学质量。  关键词:身体健康;学习兴趣;自主学习  中图分类号:G642
期刊
摘 要:本文通过PDMS软件在火力发电厂工程设计中的应用,总结了三维设计软件在电厂设计工作中所体现的优势,并对在应用过程中所暴露出来的问题做了总结,为进一步的利用好三维设计软件提供了借鉴。  关键词:火力发电厂;PDMS;三维设计  中图分类号:TM6 文献标识码:A
期刊
摘 要:在高职院校体育教学中实施审美教育,培养学生感受美、表现美的能力,是现代体育教育不可忽视的一个重要方面,也是健美操教学中不可缺少的内容之一,本文结合教学实践,对如何在健美操教学中实施美育渗透进行探讨与论述,以此来提高健美操教学质量,使健美操教学课真正成为实施素质教育、培养大学生综合能力的课堂。  关键词:健美操教学;美育渗透;培养  中图分类号:G127
期刊
摘 要:陇东,位于甘肃省的东部,主要包括今天的平凉和庆阳一带。在西周以前已经得到了有效的开发,是我国农业文明最早的发源地之一。这一重农传统对陇东地区的生产和生活等方面影响颇深,尤其是民俗艺术。陇东的民俗艺术,门类众多,艺术个性独特,具有较强的农耕文化色彩。  关键词:陇东;民俗艺术;农耕文化  中图分类号:G07
期刊