转载请标明是引用于 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;
}
感谢一直支持我博客的朋友们,也请大家继续关注我的专栏,我一有时间就会把自己的学习心得,觉得比较好的知识点写出来和大家一起分享。
开发的路还很长很长,非常希望能和大家一起交流,共同学习,共同进步。
大家看过后觉得值得一看的话,可以顶一下这篇文章,你们的支持是我继续写下去的动力~
如果文章中有什么疏漏的地方,也请大家指正。也希望大家可以多留言来和我探讨编程相关的问题。
最后,谢谢你们一直的支持~~~