敬业的IT人 >> 编程开发 >> C/C++ >> 编写可复用性更好的C++代码:Band对象和COMToys(9)

编写可复用性更好的C++代码:Band对象和COMToys(9)

敬业的IT人 互联网 佚名 2008-1-3 19:31:19

  第一部分:Band 对象介绍

  第二部分:BandObj的类层次和MyBands服务程序的注册

  第三部分:深入Band内部,揭开Band的面纱

  第四部分:Band对象使用中遇到的一些问题

  第五部分:建立自己的COM编程平台ComToys

  第六部分:设计和构造COMToys

  第七部分:类的实现

  第八部分:类厂和注册以及美中不足

  第九部分 且看看COMToys的更多特性以及与MFC的比较

  COMToys的更多特性

  除了主要的功能以外,COMToys还有一些其它特性。

  智能指针

  ATL的智能指针是我不得不赞扬的一个东西。如果你到目前为止还没用使用过智能指针的话,那么就赶快终结这个时代吧!我的意思是,终止对AddRef 和 Release的一切操心。不管你的函数有多少退出路径,智能指针都能保证所有的引用计数正确无误。免得你殚精竭虑,费尽心思和功夫来查找引用计数的bugs。有过这种经历的兄弟都知道,那是一个可怕的噩梦:

编写可复用性更好的C++代码:Band对象和COMToys(9)(图一)

  图十九 Aaaaaaaah

  对于那些一见到模板就往后退的家伙来说,COMToys有一个宏隐藏了那些尖括弧:

#define DECLARE_SMARTPTR(ifacename) \
typedef CComQIPtr SP##ifacename;   

  现在你可以写:

DECLARE_SMARTPTR(IPersist);   

  为了定义新类型SPIPersist。以便在任何出现IPersist的地方都能使用这个新类型。SPIUnknown是个专门派生的,因为它需要CComPtr,而不是CComQIPtr。(没有必要为IUnknown调用QueryInterface——每个接口都具备)。下面的代码段是一些典型的使用和没有使用智能指针的COM代码,通过比较,相信不再需要更多的解释: 

///////////////////////////////////////////////////////////////////////
// 简化后的智能指针代码:
// 典型的没有用智能指针实现的 COM 函数,当有多个退出路径时,这种做法很糟糕。
//
//
STDMETHODIMP CExplorerBar::SetSite(IUnknown* punkSite)
{
  // If a site is being held, release it.
  if(m_pSite) {
    m_pSite->Release();
    m_pSite = NULL;
  }
  // If punkSite is not NULL, a new site is being set.
  if (punkSite) {
  ......
   // Get and keep the IInputObjectSite pointer.
    if (SUCCEEDED(punkSite->QueryInterface(IID_IInputObjectSite,
     (LPVOID*)&m_pSite))) {
     return S_OK;
    } 
    return E_FAIL;
  }
  return S_OK;
}
/////////////////////////////////////////////////////////////////////////////////////
// 用智能指针实现的相同的 COM 函数,从 12 行代码减少到 2 行。
// 因为 m_pSite 被声明为 CComQIPtr,没有必要调用 QueryInterface(IID_IInputObjectSite),
// 也没有任何必要调用 AddRef 累加新的指针或调用Release释放旧的指针。智能指针全都搞掂
//
STDMETHODIMP CBandObj::SetSite(IUnknown* punkSite)
{
  if (m_pSite = punkSite) {
  ......
  }
  return punkSite && !m_pSite ? E_FAIL : S_OK;
}   

  有关ATL智能指针更深层次的探讨请参考另外一篇专题文章:“用ATL建立轻量级的COM对象”。这篇文章还描述了智能指针可能导致麻烦的罕见情形。 多线程COMToys并不能实现所有的COM对象,它的应用仅限于外壳扩展。其线程模型是单线程公寓(STA),这种情况下,类成员的线程安全是自动的,并且只有全局量需要保护。有静态成员(全局量)的COMToys类同时也有临界部分,g_mydata,在存取它之前必须锁定。COMToys的一个小类CTLockData可以很轻松完成这种锁定,由构造函数锁定临界部分,而由析构函数进行解锁,所以你要做的只是用下面的代码:

  图二十 啊!我的注册表键值到哪去了?

  怎么会这样啊;一定是REGEDIT搞错了。我退出REGEDIT并从"开始"菜单中重新运行REGEDIT,结果给我显示出一个小对话框。"这个程序引用了一个不存在的lnk文件……",这些信息看似无所谓,但实际上我面临的形势严峻。我桌面上的东西不翼而飞。资源管理器失踪了?IE也没了?每个图标被替换成莫名其妙的图标。我甚至不能启动MS-DOS窗口。我气得恼羞成怒,差点把显示器砸了。只好重启机器。但很不幸,我被欺骗了。MFC把整个注册表删掉了。我沮丧地望着屏幕无可奈何,想着最后一次备份是在什么时候...... 

URL:进入讨论组讨论。

  幸运的是我用一个买来的程序每天都自动备份注册表。但lnk文件都没了怎么运行呢?终于我还能从"开始"菜单中到"运行"窗口,然后敲入command.com/cmd.exe打开外壳MS-DOS窗口。进到ConfigSafe目录并运行它将注册表恢复到前一天的配置。到这我才松了口气。 

  这件事情导致系统临近崩溃的边缘。后来Band对象不能插入,它们不需要ProgID。MyBands的注册表串没有ProgID,所以CTFactory::GetProgID自然返回空CString。注意是空empty,不是NULL。我将这个空串传到AfxOleUnregisterClass函数,它包含如下的代码行:

if (pszProgID != NULL)
  _AfxRecursiveRegDeleteKey(HKEY_CLASSES_ROOT,
   (LPTSTR)pszProgID);   

  我想不需要再做进一步解释了,函数名中的单词“recursive”说明了一切。MFC象傻子一样欣然地删除了HKEY_CLASSES_ROOT下的所有东西。微软的人会修复这个问题吗! 这次的经验证明,在操作注册表的时候,以下几点是一定要注意的:

1、  必须要小心谨慎,这一点怎么强调都不过分。
2、  如果程序中要处理注册表键,要针对NULL值和空串增加一些附加的安全检查代码。
3、  如果没有用某个程序每天备份注册表,那么现在就赶快备份吧,亡羊补牢,为时不晚。
4、  不要相信MFC。不要相信任何人。并且如果你有心脏病,那么就不要做程序员(开玩笑)。   

  总结 

  无论你是否决定在自己的程序中使用COMToys,我都希望你至少认识到使用ATL、MFC或任何其它从ATL/MFC继承的系统并不是绝对的。重要的是不要陷入任何一个系统的怪圈中,而要按照自己方式来使用它们。我就乐意将COMToys看成是带多继承的MFC,或者无模板的ATL。 

  我还希望你能明白,花点时间建立一点儿自己的编程平台或者说基础结构(COMToys包括执行类只有2400行左右的代码,)这样你可以极大地方便自己的C++COM编程。宏,智能指针,跟踪——这些简单的工具对编程也大有帮助,使编程更加容易。最终的COMToys库源代码不可能在此全部列出,需要的话可以全部下载。总之,用COMToys来编写BandObj对象很简单,只需将一些预先做好的东西粘合在一起并加入你要的新特性。它的宗旨就是可重用性。不仅仅是在BandObj中使用,它也可用于其它的应用。今后还可以进一步实现IPersistStream接口以扩充更大的功能。 COMToys并不是十全十美,也没有哪个系统能做到。但COMToys在实践中运行良好,而且我用它建立了Band对象和一个快速的浏览文件的浏览器。今后我会不断完善COMToys,所以请关注最新开发动向和源代码。

进入讨论组讨论。
  • 如何重装xp系统图解
  • 下载Flash播放插件
  • 巧妙清除Windows 2000/XP登录密码
  • 如何利用路由器设置局域网
  • QQ空间打不开
  • 开机后鼠标不动怎么办
  • Excel密码保护的解除方法与解除原理
  • Windows XP注册表详解
  • 3dmax不锈钢金属材质的制作方法
  • 硬盘变成raw格式怎么办

  最后祝大家编程愉快!

  (全文完)

URL:进入讨论组讨论。
粤ICP备06119539号
Copyright CiscoSky.Org,Some Rights Reserved.
Email:me1228#tom.com