晓寒的小屋

随笔分类

随笔档案

相册

最新评论

阅读排行榜

评论排行榜

程序员博客   首页  新随笔  订阅  管理  登录 
 
晓寒 阅读(2167) 评论(11)

监测类的框架,使用了一个回调模式.可以回调普通函数和成员函数。
特别说明:该代码是我当时使用的,因为我使用的是成员函数,所以就使用了模版。但是这也带来了问题:如果用户仅仅使用普通函数作为回调的话,就很不方便。所以,如果想仅仅使用普通函数的话,需要把该类一分为二:把实现普通回调和成员回调分开。
特别鸣谢:[jzhang]、[hpho]两位朋友的建议和意见。
代码如下:

/**
*  @file     CHMonitor.h
*  @class    CHMonitor
*  @author   flyingleaf
*  @version  1.0.0.0
*  @date     2005-07-26
*  @brief    您可以任使用此文件,但是需要保留本声明
*/


#ifndef _XHJ_CHMONITOR_H_
#define _XHJ_CHMONITOR_H_
#include 
<windows.h>

template 
<class T>
class CHMonitor
{
public:
    CHMonitor():m_MemberFunction(
0),m_DelegaterHandle(0){};
    
virtual ~CHMonitor(){};

private:
    typedef  
void  (*DelegaterHandle)();
    typedef  
void  (T::*TMemberFunctionPointer)();
   
public:
    
//开始监测
    virtual int StartMonitor() = 0;

    
//停止监测
    virtual BOOL StopMonitor() = 0;

    
//挂起监测
    virtual BOOL SuspendMonitor() = 0;

    
//继续监测
    virtual BOOL ResumeMonitor() = 0;

    
virtual void SetCallBackHandle(DelegaterHandle handle) { m_DelegaterHandle = handle;}

    
virtual void SetCallbackFunction(T* host, TMemberFunctionPointer memberFunction)
    
{
        m_spHost 
= host;
        m_MemberFunction 
= memberFunction;
    }


    
    
virtual void InvokeHandle() 
    

        
if(m_DelegaterHandle)
            m_DelegaterHandle();
        
if(m_MemberFunction)
        
{
            ((static_cast
<T*>(m_spHost)->*m_MemberFunction)());
        }

    }


protected:

    DelegaterHandle m_DelegaterHandle;
    T
* m_spHost;
    TMemberFunctionPointer m_MemberFunction;
}
;

#endif

别看了.完了.cpp没有内容
别怕头晕,我来一个实现:

*  @file     CHProcessMonitor.h
*  @class    CHProcessMonitor
*  @author   flyingleaf
*  @version  1.0.0.0
*  @date     2006-08-08
*  @brief    您可以任使用此文件,但是需要保留本声明
*/


#ifndef _XHJ_CHWMIMONITOR_H_
#define _XHJ_CHWMIMONITOR_H_
#include 
"CHWmi.h"
#include 
"CHMonitor.h"
#include 
<string>
#include 
<CHMutex.h>

using namespace std;
using namespace XHJ;


template 
<class T>
class CHProcessMonitor : public CHMonitor<T>
{
public:
    CHProcessMonitor()
    
{
    }

    
    
//参数分别是IP,用户名,密码,wql语句。
    
//如果是本机,则ip为127.0.0.1,用户名和密码都可以为空。
    CHProcessMonitor(const char* wql,const char* ip = "127.0.0.1"
        
const char* username = ""const char* psw="" )
    
{
        m_Wql      
= wql;
        m_IP       
= ip;
        m_UserName 
= username;
        m_Psw      
= psw;
  m_EventHandle     
= NULL;
  m_ThreadHandle    
= NULL;
    }

    
~CHProcessMonitor()
    
{
    }

public:    
    
//开始监测
    int StartMonitor()
    
{
  m_EventHandle 
= CreateEvent(NULL,FALSE,FALSE,"XHJ_CHProcessMonitor_Event");
  
if(m_EventHandle == NULL)
  
{
   
return -3;
  }

        m_ThreadHandle 
= CreateThread(NULL, 0, ThreadFuncNotify, (void*)this00);
        
if(m_ThreadHandle == NULL)
        
{
            
return -4;
        }
  
        
return 0;
    }

    
    
//停止监测
    BOOL StopMonitor()
    
{
  Lock 
lock(m_Mutex);
        SetEvent(m_EventHandle);
        
return TRUE;
    }

    
//挂起监测
    BOOL SuspendMonitor()
    
{
        
if(SuspendThread(m_ThreadHandle) == 0xFFFFFFFFreturn FALSE;
        
return TRUE;
    }

    
//继续监测
    BOOL ResumeMonitor()
    
{
        
if(ResumeThread (m_ThreadHandle) == 0xFFFFFFFFreturn FALSE;
        
return TRUE;
    }

    
const char* GetUserName() const return m_UserName.c_str();}
    
const char* GetIP() const return m_IP.c_str();    }
    
const char* GetPsw() const return m_Psw.c_str();    }
    
const char* GetWql() const return m_Wql.c_str();    }
    
void SetIP(const char* ip) { m_IP = ip;    }
    
void SetUserName(const char* username) { m_UserName = username;}
    
void SetPsw(const char* psw) { m_Psw = psw;}
    
void SetWql(const char* wql) { m_Wql = wql;    }
protected:
    
//监测线程
    static DWORD WINAPI ThreadFuncNotify( LPVOID lpParam )
    
{
        CHProcessMonitor
* monitor = (CHProcessMonitor*)lpParam;
        IEnumWbemClassObject
* m_pEnum = NULL;
        
if(monitor->m_Wql.length() == 0return -7;
        CHWMI
* m_CHWMIHandle = new CHWMI;
        
if(m_CHWMIHandle == NULL) return -1;
        
int ret = m_CHWMIHandle->Connect(monitor->m_IP,monitor->m_UserName, monitor->m_Psw);
        
if(ret != CWMI_RET_OK)
        
{
            delete m_CHWMIHandle;
            
return -2;
        }

        IWbemClassObject
*  pObject = NULL;
        ret 
= m_CHWMIHandle->WMINotificationQuery(monitor->m_Wql, &m_pEnum,&pObject);
        
if(ret != CWMI_RET_OK)
        
{
            
if(pObject)
                pObject
->Release();
            delete m_CHWMIHandle;
            
return -3;
        }


        
while(WaitForSingleObject(monitor->m_EventHandle, 0!= WAIT_OBJECT_0)
        
{
            ret 
= m_CHWMIHandle->EnumInstanceNext(m_pEnum,
                    
&pObject,500);
            
if(ret == CWMI_RET_OK)
            
{            
                monitor
->InvokeHandle();
                
if(pObject)
                    pObject
->Release();
                pObject 
= NULL;
            }

        }

        m_CHWMIHandle
->EnumInstanceEnd(m_pEnum);
        
if(pObject) 
            pObject
->Release();
        
if(m_CHWMIHandle)
            delete m_CHWMIHandle;
        
return 0;
    }

private:
    
string m_Wql;
    
string m_IP;
    
string m_UserName;
    
string m_Psw;
 HANDLE m_EventHandle;
    HANDLE m_ThreadHandle;
    CHWMI
* m_CHWMIHandle;
 CHMutex m_Mutex;
    IEnumWbemClassObject
* m_pEnum;
}
;
#endif


附带wmi的简单封装
/**
*  @file     CHWMI.h
*  @class    CHWMI
*  @author   flyingleaf
*  @version  1.0.0.0
*  @date     2005-05-09
*  @brief    您可以任使用此文件,但是需要保留本声明
*/


#ifndef _XHJ_CHWMI_H_
#define _XHJ_CHWMI_H_

// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。
// 有关不同平台的相应值的最新信息,请参考 MSDN。
#ifndef WINVER                // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。
#define WINVER 0x0400        //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。
#endif

#ifndef _WIN32_WINNT        
// 允许使用 Windows NT 4 或更高版本的特定功能。
#define _WIN32_WINNT 0x0400        //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。
#endif                        

#ifndef _WIN32_WINDOWS        
// 允许使用 Windows 98 或更高版本的特定功能。
#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。
#endif

#ifndef _WIN32_IE            
// 允许使用 IE 4.0 或更高版本的特定功能。
#define _WIN32_IE 0x0400    //为 IE 5.0 及更新版本改变为适当的值。
#endif

#include 
<Atlbase.h>
#include 
<Wbemidl.h>
#include 
<string>


#define CWMI_RET_OK 0
#define CWMI_RET_ERROR -1
#define CWMI_RET_ERROR_HRESULT -2
#define CWMI_RET_ERROR_DEFINE -3
#define CWMI_RET_TIMEOUT   -4

#define CWMI_ENUM_CREAT 1
#define CWMI_ENUM_QUERY 2

class CHWMI
{
public:
    CHWMI();
    
~CHWMI();

    
int Connect(const std::string szHost, const std::string szUserName, const std::string szPsw );
    
int EnumInstanceEnd(IEnumWbemClassObject *IEnum);
    
int EnumInstanceNext(IEnumWbemClassObject *IEnum,
                            IWbemClassObject 
**pObject,
                            
int timeout = WBEM_INFINITE);

    
int WMINotificationQuery(const std::string& Querystdstring, 
        IEnumWbemClassObject 
**ppEnum, IWbemClassObject **pObject);

protected:
    
// WMI服务器指针
    IWbemServices * m_pIWbemServices;

private:
    
// 用于身份验证
    std::string m_csHost;
    std::
string m_csUsername;
    std::
string m_csPassword;

    std::
string m_csDefaultNameSpace;
}
;
#endif

#include "CHTWmi.h"

#include 
<Iphlpapi.h>
#include 
<Winsock2.h>

#include 
<objbase.h>
#pragma comment(lib, 
"Wbemuuid.lib")
#pragma comment(lib, 
"ole32.lib")

#pragma warning(disable:
4267)

CHWMI::CHWMI()
{
    ::CoInitialize(NULL);
    m_csDefaultNameSpace 
= "\ROOT\CIMV2";
}


CHWMI::
~CHWMI()
{
    ::CoUninitialize();
}


int CHWMI::Connect(const std::string szHost, 
                   
const std::string szUserName, 
                   
const std::string szPsw )
{
    HRESULT        hres;
    IWbemLocator 
*pIWbemLocator;
    hres 
= CoCreateInstance    ( CLSID_WbemLocator, 0
        CLSCTX_INPROC_SERVER, IID_IWbemLocator    ,
        (LPVOID 
*&pIWbemLocator    );

    
if (FAILED(hres))
    
{
        
return CWMI_RET_ERROR_DEFINE;
    }


    m_csHost 
= szHost;
    m_csUsername 
= szUserName;
    m_csPassword 
= szPsw;

    std::
string csWMINameSpace = "\\";
    csWMINameSpace 
+= m_csHost;
    csWMINameSpace 
+= m_csDefaultNameSpace;
    CComBSTR bstrNamespace(csWMINameSpace.c_str());

    
if ( m_csUsername.empty())    
    
{
        hres 
= (pIWbemLocator)->ConnectServer(bstrNamespace, NULL, NULL    ,
            
0, NULL, 00&m_pIWbemServices    );
    }

    
else    
    
{
        CComBSTR bstrUsername(m_csUsername.c_str()), bstrPassword(m_csPassword.c_str());

        hres 
= (pIWbemLocator)->ConnectServer(bstrNamespace, bstrUsername, 
            bstrPassword, 
0, NULL, 00
            
&m_pIWbemServices    );
    }


    
if (FAILED(hres))   
    
{
        (pIWbemLocator)
->Release();
        
return CWMI_RET_ERROR_DEFINE;
    }


    std::
string username,domain;
    username 
= m_csUsername;
    domain 
= "";

    SEC_WINNT_AUTH_IDENTITY AuthInfo;
    AuthInfo.User 
= (unsigned char *)(LPCTSTR)username.c_str();
    AuthInfo.Password 
= (unsigned char *)(LPCTSTR)m_csPassword.c_str();
    AuthInfo.Domain 
= (unsigned char *)(LPCTSTR)domain.c_str();
    AuthInfo.UserLength 
= m_csUsername.length();
    AuthInfo.DomainLength 
= 0;
    AuthInfo.PasswordLength 
= m_csPassword.length();
    AuthInfo.Flags 
= SEC_WINNT_AUTH_IDENTITY_ANSI;

    hres 
= CoSetProxyBlanket( m_pIWbemServices    , 
        RPC_C_AUTHN_WINNT    , 
        RPC_C_AUTHZ_NONE    , 
        NULL, 
        RPC_C_AUTHN_LEVEL_CALL        ,
        RPC_C_IMP_LEVEL_IMPERSONATE    , 
        
&AuthInfo,
        EOAC_NONE);

    
if(FAILED(hres))    
    
{
        (pIWbemLocator)
->Release();
        (m_pIWbemServices)
->Release();
        m_pIWbemServices 
= NULL;
        
return CWMI_RET_ERROR_DEFINE;
    }


    (pIWbemLocator)
->Release();


    
return CWMI_RET_OK;
}



int CHWMI::EnumInstanceNext(IEnumWbemClassObject *pIEnum,
                            IWbemClassObject 
**ppIObject,
                            
int timeout)
{
    
if!m_pIWbemServices )
    
{
        
return CWMI_RET_ERROR_DEFINE;
    }


    ULONG            uReturned;

    
if(*ppIObject != NULL)
        (
*ppIObject)->Release();

    HRESULT hres 
= pIEnum->Next(timeout, 1, ppIObject, &uReturned );

    
if ( SUCCEEDED( hres ) && uReturned == 1)
        
return CWMI_RET_OK;
    
else if(hres == WBEM_S_TIMEDOUT)
        
return CWMI_RET_TIMEOUT;
    
else
        
return CWMI_RET_ERROR;
}


int CHWMI::EnumInstanceEnd(IEnumWbemClassObject *pIEnum)
{
    pIEnum
->Release();

    
return CWMI_RET_OK;
}

int CHWMI::WMINotificationQuery(const std::string& QueryString,
                                IEnumWbemClassObject 
**ppEnum,
                                IWbemClassObject 
**ppObject)
{
    CComBSTR        bstrQueryString(QueryString.c_str());
    CComBSTR        bstrWQL(
"WQL");

    
*ppObject = NULL;
    HRESULT hres;
    hres 
= m_pIWbemServices->ExecNotificationQuery(
        bstrWQL, 
        bstrQueryString, 
        WBEM_FLAG_RETURN_IMMEDIATELY 
| WBEM_FLAG_FORWARD_ONLY ,
        NULL, 
        ppEnum 
        );
    
if(hres == WBEM_S_NO_ERROR)
    
{
        std::
string username,domain;
        username 
= m_csUsername;
        domain 
= "";

        SEC_WINNT_AUTH_IDENTITY AuthInfo;
        AuthInfo.User 
= (unsigned char *)(LPCTSTR)username.c_str();
        AuthInfo.Password 
= (unsigned char *)(LPCTSTR)m_csPassword.c_str();
        AuthInfo.Domain 
= (unsigned char *)(LPCTSTR)domain.c_str();
        AuthInfo.UserLength 
= m_csUsername.length();
        AuthInfo.DomainLength 
= 0;
        AuthInfo.PasswordLength 
= m_csPassword.length();
        AuthInfo.Flags 
= SEC_WINNT_AUTH_IDENTITY_ANSI;

        HRESULT hres 
= CoSetProxyBlanket( *ppEnum    , 
            RPC_C_AUTHN_WINNT    , 
            RPC_C_AUTHZ_NONE    , 
            NULL, 
            RPC_C_AUTHN_LEVEL_CALL        ,
            RPC_C_IMP_LEVEL_IMPERSONATE    , 
            
&AuthInfo,
            EOAC_NONE);

        
if(FAILED(hres))    
        
{
            (
*ppEnum)->Release();

            
return CWMI_RET_ERROR_DEFINE;
        }

        
return CWMI_RET_OK;
    }

    
else
        
return CWMI_RET_ERROR;
}






评论列表
晓寒
一个测试

void PrintInfo()
{
    cout 
<<  "PrintInfo::发现有进程被创建" << endl;
}


class Test
{
public:
    
void PrintInfo()
    
{
        cout 
<< "Test::发现有进程被创建" << endl;
    }

}
;

typedef CHProcessMonitor
<Test> Monitor;

int _tmain(int argc, _TCHAR* argv[])
{
    Monitor
* gCreateMonitor;  
    gCreateMonitor 
= new MonitorType("select * from __InstanceCreationEvent within 0.5 where TargetInstance isa "Win32_Process"");
    
if(!gCreateMonitor) return -1;
    gCreateMonitor
->SetCallBackHandle(PrintInfo);
    Test
* test = new Test;
    gCreateMonitor
->SetCallbackFunction(test,Test::PrintInfo); 
  gCreateMonitor
->StartMonitor();

    getchar();

    
if(gCreateMonitor) delete gCreateMonitor;
    
if(test) delete test;

    
return 0;
}

jzhang
路过
while( !(monitor->m_TerminiteThread) )
这个写法不对,应该用WaitForSingleObject :)
另外,Command模式是指 m_MemberFunction 么?
hpho
re: 基础库___监测类框架

   DelegaterHandle m_DelegaterHandle;
    T* m_spHost;
    TMemberFunctionPointer m_MemberFunction;
这几个在派生类使用时最后加一个域名, 因为你的成员都写在最下面, 而且名字也不短, 很容易会使阅读的人搞混.
typedef CHMonitor<T> Base;
Base::m_DelegaterHandle=NULL;

2
很奇怪 
CHMonitor():m_MemberFunction(0){};
只初始化m_MemberFunction. 把m_DelegaterHandle留给了派生类初始化, 那不是间接地避别人看你基类代码一遍!?

3
这个SetCallbackFunction若果对象指针是一个局部对象实例的, 那你在线程里引用不会有问题!??

4
这个函数指针接口太窄了吧, 若有参数或是一个CONST的成员函数那就用不了.
晓寒
re: 基础库___监测类框架
1、3ks, 看来我的确需要多写些typedef :)
2、m_DelegaterHandle 是偶的错。当时漏掉了。
3、SetCallbackFunction需要使用者自己来保证实例的存在,所以内存也由他来管理 :P
4、呵呵,就是一个简单的使用。所以支持的接口的确少。

btw:
这句话的意思是?
"这几个在派生类使用时最后加一个域名, 因为你的成员都写在最下面, 而且名字也不短, 很容易会使阅读的人搞混"

再次感谢[jzhang] 和[hpho]。 我这就修改这些问题。 :)
jzhang
re: 基础库___监测类框架
1. WaitForSingleObject第二个参数设置为0,就不会阻塞了。
用while( !(monitor->m_TerminiteThread) ) 会有并发问题

2. 回调函数本身就是种模式,虽然他不是OO的。Command模式专指将对用户指令的处理用一个对象来抽象。

晓寒
re: 基础库___监测类框架
hehe,收到.第二个明白了.不过第一个问题:WaitForSingleObject我还是不知道有何好处,并且为何要使用WaitForSingleObject以及在这里如何使用 :(
晓寒
re: 基础库___监测类框架
顺带说个缺点:
最大的缺点是:使用了模板!如果现在仅仅想回调一个普通函数的话,呵呵,这个问题就出来了。。。。。
jzhang
re: 基础库___监测类框架
monitor->m_TerminiteThread会在两个线程中用,一个读一个写。在你这个例子中可能不会出什么问题,但是通用的给线程一个通知的办法是用事件
if(WaitForSingleObject(monitor->Event,0) == WAIT_OBJECT_0)
{
break;
}
这就不会产生并发的问题。

晓寒
re: 基础库___监测类框架
收到。我修改下。 :)

发表评论
切换编辑模式