编写可复用性更好的C++代码:Band对象和COMToys(9)
第一部分:Band 对象介绍
第二部分:BandObj的类层次和MyBands服务程序的注册
第三部分:深入Band内部,揭开Band的面纱
第四部分:Band对象使用中遇到的一些问题
第五部分:建立自己的COM编程平台ComToys
第六部分:设计和构造COMToys
第七部分:类的实现
第八部分:类厂和注册以及美中不足
第九部分 且看看COMToys的更多特性以及与MFC的比较
COMToys的更多特性
除了主要的功能以外,COMToys还有一些其它特性。
智能指针
ATL的智能指针是我不得不赞扬的一个东西。如果你到目前为止还没用使用过智能指针的话,那么就赶快终结这个时代吧!我的意思是,终止对AddRef 和 Release的一切操心。不管你的函数有多少退出路径,智能指针都能保证所有的引用计数正确无误。免得你殚精竭虑,费尽心思和功夫来查找引用计数的bugs。有过这种经历的兄弟都知道,那是一个可怕的噩梦:

图十九 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:进入讨论组讨论。- 最新文章
- 编写可复用性更好的C++代码:Band对象和COMToys(..[01-03]
- C++ Builder中MDI应用程序的设计[01-03]
- 用C++ Builder编写Tray程序[01-03]
- 在C++ Builder中实现拖放功能[01-03]
- Visual C++ 6 Add-in编程实例[01-03]
- 编写可复用性更好的C++代码:Band对象和COMToys(..[01-03]
- 相关文章
