转载请标明是引用于 http://blog.csdn.net/chenyujing1234
类似于MFC中加入COM,由放多的宏实现COM的定义和接口的声明。在金山卫士中也采用了MFC中加入COM的方法,这大大减少了开发COM的难度。
1、COM组件的管理模式。(单件模式)
FwProxy创建的dll为COM组件,它的COM创建方法与一般方法类似,但管理方法却采用单件模式,这值得我们学习。
先从最根的def文件开始吧.
EXPORTS KSDllGetClassObject @1 PRIVATE KSDllGetClassCount @2 PRIVATE KSDllGetClassInfo @3 PRIVATE KSDllCanUnloadNow @4 PRIVATE
它是从fwproxy.cpp文件里的DECLARE_DLLEXPORTS();定义的,我们来看看此宏做了什么
#define DECLARE_DLLEXPORTS() \ IMPLEMENT_KSDLLGETCLASSOBJECT() \ IMPLEMENT_KSDLLGETCLASSCOUNT() \ IMPLEMENT_KSDLLGETCLASSINFO() \ IMPLEMENT_KSDLLCANUNLOADNOW()
主要分析IMPLEMENT_KSDLLGETCLASSOBJECT,此宏分解开来是调用了COM工厂里的接口。
#define IMPLEMENT_KSDLLGETCLASSOBJECT() \ extern "C" \ KSRESULT __stdcall KSDllGetClassObject(const KSCLSID &clsid, const KSIID &riid , void **ppv) \ {\ return GlobalFactory::Instance().CreateInstance(clsid,riid, ppv); \ }
GlobalFactory是一个KFactory类的单件模式的包装。
typedef SingletonHolder_Static<KFactory> GlobalFactory;
单件类SingletonHoder值得我们学习。eg:给出接口Instance();返回实例的引用。
////////////////////////////////////////////////////////////////////////// //这个单件模板可以被静态(或全局)对象的构造函数调用,因为KSComThreadMutex没有构造函数, //是通过内部的标记判断是否初始化,如果没有初始化则进行初始化,但是由于第一次调用到时才进行 //KSComThreadMutex的初始化,当不是被静态(或全局)对象的构造函数调用时,如果多线程同时调用 //Instance()函数,有被初始化两次的可能. template<class T> class SingletonHolder_Static { public: typedef T* volatile _PtrInstanceType; static T& Instance(); private: SingletonHolder_Static(){}; SingletonHolder_Static(const SingletonHolder_Static&){}; SingletonHolder_Static& operator = (const SingletonHolder_Static&){}; // ~SingletonHolder() // { // m_pInstance = 0; // m_destroyed = true; // }; static void MakeInstance(); static void DestroySingleton(); static void OnDeadReference(); struct _Lock { _Lock() { m_Lock.Lock(); } ~_Lock() { m_Lock.Unlock(); } }; friend struct _Lock; private: static KSComThreadMutex m_Lock; static _PtrInstanceType m_pInstance; static bool m_destroyed; };
单件模式的实现主要通过以下两个函数:
template<class T> inline T& SingletonHolder_Static<T>::Instance() { if (!m_pInstance) { MakeInstance(); } return *m_pInstance; } ////////////////////////////////////////////////////////////////////////// //MakeInstance() template<class T> inline void SingletonHolder_Static<T>::MakeInstance() { //KSClassLockGuard<T> guard; _Lock guard; //防止多线程时初始化两次 if (!m_pInstance) { if (m_destroyed) { OnDeadReference(); } //static T TheInstance; //m_pInstance = &TheInstance; m_pInstance = new T; m_destroyed = false; atexit(DestroySingleton); } }
2、COM组件的管理模式。(内部GUID自我维护)
我们来看一下维护这些GUID的窗口是什么,是一个map,KMODULEINFOMAP m_ComponentMap;
class KFactory { #if _MSC_VER >= 1400 template<class T> friend class SingletonHolder_Static; #else friend class SingletonHolder_Static<KFactory>; #endif public: typedef std::map< KSCLSID, KMODULEINFO > KMODULEINFOMAP; private: KMODULEINFOMAP m_ComponentMap;
它的主要接口是
KSRESULT CreateInstance(const KSCLSID &clsid, const KSIID &riid, void **ppv) { //try //{ KMODULEINFOMAP::iterator iter = m_ComponentMap.find(clsid); if (iter != m_ComponentMap.end()) { KSRESULT hRes = (iter->second).m_pfnCreateInstance(riid, ppv); return hRes; } else { return NTE_NOT_FOUND; } //} //catch(...) //{ // SCOM_ASSERT_MESSAGE(SCOM_ASSERT_TEXT("CreateInstance failed.Maybe you haven't Initialized SCOM library"), false); // return E_FAIL; //} }
这是创建实例的函数。
那么大家一定有疑问COM组件的注册在哪里呢?
是的,这里有些人可能发现了KFactory中的一个成员函数KSRESULT Register(KMODULEINFO Info).
那么调用它的地方在哪里呢?
刚开始调用的地方是在fwproxy.cpp文件里的
REGISTER_TO_FACTORY(CFwProxy,"IFwProxy.1"); REGISTER_TO_FACTORY(CFwInstaller,"IFwInstaller.1");
//产生静态对象的宏 #define REGISTER_TO_FACTORY(_class, _ProgID) \ static RegisterDummy dummy##_class(_class::GetCLSID(), _class::CreateInstance, _ProgID, 0);
通过构造的对象RegisterDummy中的构造函数把此CLSID(通过GetCLSID获得)和自己的创建对象方法指针(CreateInstance)注册.(其实是把它放到COM管理中去)
Register其实就是往自己的COM接口库里insert数据.
//注册组件信息的类
class RegisterDummy
{
public:
RegisterDummy(const KSCLSID& clsid, _SCOM_CREATORFUNC *pfnCreateInstance, const char *pszProgID, DWORD dwProperty)
{
m_MoudleInfo.m_CLSID = clsid;
m_MoudleInfo.m_pfnCreateInstance = pfnCreateInstance;
m_MoudleInfo.m_pszProgID = pszProgID;
m_MoudleInfo.m_dwProperty = dwProperty;
GlobalFactory::Instance().Register(m_MoudleInfo);
}
KSRESULT Register(KMODULEINFO Info) { std::pair<KMODULEINFOMAP::iterator, bool> RetPair = m_ComponentMap.insert( KMODULEINFOMAP::value_type(Info.m_CLSID, Info) ); //m_ComponentMap[Info.m_CLSID] = Info; if(RetPair.second) { return S_OK; }
以上红色部分指的获得方法大家可以参照我的下一篇文章<<金山卫士开源软件之旅(四) http://blog.csdn.net/chenyujing1234/article/details/7439568>>