金山卫士开源软件之旅(四) netmon下FwProxy工程的解析---接口实现及接口使用方法

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

 

感谢一直支持我博客的朋友们,也请大家继续关注我的专栏,我一有时间就会把自己的学习心得,觉得比较好的知识点写出来和大家一起分享。

开发的路还很长很长,非常希望能和大家一起交流,共同学习,共同进步。

大家看过后觉得值得一看的话,可以顶一下这篇文章,你们的支持是我继续写下去的动力~

如果文章中有什么疏漏的地方,也请大家指正。也希望大家可以多留言来和我探讨编程相关的问题。

最后,谢谢你们一直的支持~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值