金山卫士开源软件之旅(三) netmon下FwProxy工程的解析----COM组件的管理模式

转载请标明是引用于 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>>


 

 

你可能感兴趣的:(多线程,struct,iterator,Class,library,金山)