监测类的框架,使用了一个回调模式.可以回调普通函数和成员函数。
特别说明:该代码是我当时使用的,因为我使用的是成员函数,所以就使用了模版。但是这也带来了问题:如果用户仅仅使用普通函数作为回调的话,就很不方便。所以,如果想仅仅使用普通函数的话,需要把该类一分为二:把实现普通回调和成员回调分开。
特别鸣谢:[jzhang]、[hpho]两位朋友的建议和意见。
代码如下:
别看了.完了.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*)this, 0, 0);
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) == 0xFFFFFFFF) return FALSE;
return TRUE;
}
//继续监测
BOOL ResumeMonitor()

{
if(ResumeThread (m_ThreadHandle) == 0xFFFFFFFF) return 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() == 0) return -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, 0, 0, &m_pIWbemServices );
}
else

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

hres = (pIWbemLocator)->ConnectServer(bstrNamespace, bstrUsername,
bstrPassword, 0, NULL, 0, 0,
&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;
}
jzhang2013-1-17 23:05:00
路过
while( !(monitor->m_TerminiteThread) )
这个写法不对,应该用WaitForSingleObject :)
另外,Command模式是指 m_MemberFunction 么?
hpho2013-1-17 23:05:00
re: 基础库___监测类框架
1
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的成员函数那就用不了.
晓寒2013-1-17 23:05:00
re: 基础库___监测类框架
1、3ks, 看来我的确需要多写些typedef :)
2、m_DelegaterHandle 是偶的错。当时漏掉了。
3、SetCallbackFunction需要使用者自己来保证实例的存在,所以内存也由他来管理 :P
4、呵呵,就是一个简单的使用。所以支持的接口的确少。
btw:
这句话的意思是?
"这几个在派生类使用时最后加一个域名, 因为你的成员都写在最下面, 而且名字也不短, 很容易会使阅读的人搞混"
再次感谢[jzhang] 和[hpho]。 我这就修改这些问题。 :)
jzhang2013-1-17 23:05:00
re: 基础库___监测类框架
1. WaitForSingleObject第二个参数设置为0,就不会阻塞了。
用while( !(monitor->m_TerminiteThread) ) 会有并发问题
2. 回调函数本身就是种模式,虽然他不是OO的。Command模式专指将对用户指令的处理用一个对象来抽象。
晓寒2013-1-17 23:05:00
re: 基础库___监测类框架
hehe,收到.第二个明白了.不过第一个问题:WaitForSingleObject我还是不知道有何好处,并且为何要使用WaitForSingleObject以及在这里如何使用 :(
晓寒2013-1-17 23:05:00
re: 基础库___监测类框架
顺带说个缺点:
最大的缺点是:使用了模板!如果现在仅仅想回调一个普通函数的话,呵呵,这个问题就出来了。。。。。
jzhang2013-1-17 23:05:00
re: 基础库___监测类框架
monitor->m_TerminiteThread会在两个线程中用,一个读一个写。在你这个例子中可能不会出什么问题,但是通用的给线程一个通知的办法是用事件
if(WaitForSingleObject(monitor->Event,0) == WAIT_OBJECT_0)
{
break;
}
这就不会产生并发的问题。
晓寒2013-1-17 23:05:00
re: 基础库___监测类框架
收到。我修改下。 :)