转载请标明是引用于 http://blog.csdn.net/chenyujing1234
上一篇文章<<金山卫士开源软件之旅(三) netmon下FwProxy工程的解析----COM组件的管理模式>>中讲到如何去实现CFwProxy::GetCLSID与CFwProxy::CreateInstance.
这里做继续介绍.
FwProxy主要是防火墙的设计及驱动的加安装卸载。这里涉及两个类CFwInstaller和CFwProxy.
1 、CFwinstaller接口的实现逻辑。
下面是此类的COM实现宏接口,有编译之美供我们学习。
实现的GetCLSID和CreateInstance就是给前面注册用的。一旦此DLL注册后,其它应用程序就能得到CFwInstaller 的接口了.
CLSID_IFwInsallerImpl在KingSoft\oss\pcmanager\src\import\kpfw\fwproxy_public.h文件中定义
class CFwInstaller :
public IFwInstaller,
public KSComRoot<CFwInstaller>
{
// 实现GetCLSID函数数,返回CLSDI
KS_DEFINE_GETCLSID(CLSID_IFwInstallerImpl);
// 实现AddRef( Release( CreateInstance(三个函数
DECLARE_INDEPENDENT_OBJECT();
// 实现QueryInterface函数
KSCOM_QUERY_BEGIN
KSCOM_QUERY_ENTRY( IFwInstaller )
KSCOM_QUERY_END
对于三个宏,我们继续分析:
//m_RefCnt是由public KSComRoot<CFwInstaller>得到的 #define IMPLEMENT_INDEPENDENT_ADDREF() \ unsigned long __stdcall AddRef() \ { \ KS_ASSERT(long(m_RefCnt) >= 0); \ long lRefCnt = ++m_RefCnt; \ if (1 == lRefCnt) \ { \ GlobalFactory::Instance().Lock();\ } \ return lRefCnt; \ }
// _ComType 是由public KSComRoot<CFwInstaller>得到的 #define IMPLEMENT_SINGLETON_CREATOR() \ static KSRESULT __stdcall CreateInstance(const KSIID &riid, void **ppv)\ { \ KS_ASSERT(ppv != NULL); \ _ComType *p = NULL; \ p = &SingletonHolder<_ComType>::Instance(); \ KSRESULT hRes; \ hRes = p->QueryInterface(riid, ppv); \ return hRes;\ }
////////////////////////////////////////////////////////////////////////// //QueryInterface实现宏,一个QueryInterface实现可以如下 //KSCOM_QUERY_BEGIN; //KSCOM_QUERY_ENTRY(IFaceSample); //KSCOM_QUERY_END; #define KSCOM_QUERY_BEGIN public: \ KSRESULT __stdcall QueryInterface(const KSIID &riid, void **ppv)\ { \ KSRESULT res = S_OK; \ if (riid == KS_IIDOF(IUnknown)){ \ *ppv = reinterpret_cast<IUnknown*>(this); #define KSCOM_QUERY_ENTRY(_interface) \ } \ else if(riid == KS_IIDOF(_interface)){ \ *ppv = static_cast<_interface*>(this); #define KSCOM_QUERY_ENTRY2(_interface, _derived) \ } \ else if(riid == KS_IIDOF(_interface)){ \ *ppv = static_cast<_interface*>(static_cast<_derived*>(this)); #define KSCOM_QUERY_END \ } \ else \ { \ *ppv = NULL; \ return E_NOINTERFACE; \ } \ reinterpret_cast<IUnknown*>(*ppv)->AddRef();\ return res; \ }
这样其他模块通过CLSID_IFwInstanceImpl就能得到CFwInstaller
接口,然后调用 CFwInstaller的三个public接口(由纯虚函数IFwInstaller继承得到的)。而把三个接口函数里用到的其它逻辑接口放到了protected:里.
class CFwInstaller : public IFwInstaller, public KSComRoot<CFwInstaller> { public: CFwInstaller(); virtual ~CFwInstaller(); STDMETHODIMP Install(); STDMETHODIMP UnInstall(); STDMETHODIMP SetConfig( DWORD dwEnableFlag, DWORD dwRequestFlag );
===============================================================================================
对于CFwProxy类的实现,同样有上述的特点。
(CFwProxy有一个函数相当重要: STDMETHODIMP CFwProxy::Initialize(IFwEvent* piEvent))
//////////////////////////////////////////////////////////////////////////
// 找开设备 L"\\\\.\\KTdiFilt"
// 通过判断Dump数据,是否有不兼容设备来判断是否能够加载
// 通过打开的设备注册事件TDI_EVENT_REGISTER
// 启动工作线程,通过等待刚刚注册的三个事件m_hExitEvent;m_hCommEvent;m_hActiveEvent;
// 当事件被激活时去获得相应的反馈信息,并把结果反馈给IFwEvent
STDMETHODIMP CFwProxy::Initialize(IFwEvent* piEvent)
{
.....
}
IFwEvent可以是KTdiDriverProxy,因为
HRESULT KTdiDriverProxy::Init(KProcessInfoMgr* pProcessMgr, KModuleMgr* pModuleMgr, KUrlMonCfg* pUrlCfgMon)
{
......
if ( m_pFwProxy->Initialize( this ) != S_OK )
{
......
// 启动驱动服务 L"kmodurl"
if ( !StartDriverSvr(TDI_FILTER_DRIVER) )
}
// 通过m_pFwProxy去通知设备全能防火墙
m_pFwProxy->EnableFirewall();
}
这里我们总结出CFwInstaller类的COM接口代码的书写很工整,相当紧凑。如果遵循了这个规则,以后的扩展只要写各个类的逻辑就可以了。
COM维护相当方便。
2、在其他模块中使用此类COM的方法.
如果大家搜索CLSID_IFwProxyImp,那么可以找到加载上述讲到的FwProxy编译出来的FwProxy.dll接口的地方.
\oss\pcmanager\src\src_kpfw\netmon\netmon\urlmon\kdriverproxy.cpp
得到的接口放到了
IFwProxy * m_pFwProxy;
HRESULT KTdiDriverProxy::Init(KProcessInfoMgr* pProcessMgr, KModuleMgr* pModuleMgr, KUrlMonCfg* pUrlCfgMon) { kws_log(TEXT("KTdiDriverProxy::Init begin")); m_pProcessMgr = pProcessMgr; m_pModuleMgr = pModuleMgr; m_pUrlCfgMon = pUrlCfgMon; // 启动驱动,如果发现没有安装,那么自动安装驱动,并且启动驱动 if ( !LoadInterface(CLSID_IFwProxyImp, (VOID**)&m_pFwProxy) ) { kws_log(TEXT("KTdiDriverProxy::Init LoadInterface failed")); return E_FAIL; }
来看一下LoadInterface的实现,它加载了DLL里的四个接口:
"KSDllGetClassObject"
"KSDllGetClassCount"
"KSDllGetClassInfo"
"KSDllCanUnloadNow"
最后调用GetClassObject便得到我们的接口
BOOL KTdiDriverProxy::LoadInterface(const GUID& iid, void** pInterface ) { static KSDll dll; static BOOL b = FALSE; if (!b) { WCHAR wszProxy[MAX_PATH + 1] = { 0 }; GetModuleFileName(NULL, wszProxy, MAX_PATH); *(wcsrchr(wszProxy, L'\\')) = 0L; wcscat_s(wszProxy, MAX_PATH, L"\\fwproxy.dll"); if (S_OK == dll.Open(wszProxy)) b = TRUE; } if (!b) return FALSE; return dll.GetClassObject(iid, iid, pInterface) == S_OK; }
通过这种方式,即使多次调用LoadInterface(CLSID_IFwProxyImp, (VOID**)&m_pFwProxy)
也不会产生多个对象,因为里面采用了单件模式。
例如在上述使用的同一文件处又调用了此接口,并使用此接口的方法来操作了注册表。
BOOL KTdiDriverProxy::DoCheckForceDisableTDI() { WCHAR bufPath[MAX_PATH] = {0}; ::GetModuleFileName(NULL, bufPath, MAX_PATH); ::PathRemoveFileSpecW(bufPath); ::PathAppend(bufPath, TEXT("AppData\\msg.ini")); int nNotify = GetPrivateProfileIntW(TEXT("netmon"), TEXT("forcedisabletdi"), 0, bufPath); IFwProxy* pProxy = NULL; if ( !LoadInterface(CLSID_IFwProxyImp, (VOID**)&pProxy) ) { kws_log(TEXT("KTdiDriverProxy::DoCheckForceDisableTDI LoadInterface failed")); return FALSE; } pProxy->SetForceDisableTdi(nNotify); pProxy->Release(); return TRUE; }
感谢一直支持我博客的朋友们,也请大家继续关注我的专栏,我一有时间就会把自己的学习心得,觉得比较好的知识点写出来和大家一起分享。
开发的路还很长很长,非常希望能和大家一起交流,共同学习,共同进步。
大家看过后觉得值得一看的话,可以顶一下这篇文章,你们的支持是我继续写下去的动力~
如果文章中有什么疏漏的地方,也请大家指正。也希望大家可以多留言来和我探讨编程相关的问题。
最后,谢谢你们一直的支持~~~