windows-nt/Source/XPSP1/NT/net/mmc/mprsnap/refresh.h
2020-09-26 16:20:57 +08:00

438 lines
12 KiB
C++

//============================================================================
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: refresh.h
//
// History:
// Kenn Takara Sept. 16, 1997 Created.
//
//============================================================================
#ifndef _REFRESH_H_
#define _REFRESH_H_
#include <afxmt.h>
#include <list>
#include "infoi.h"
#include "router.h"
#ifndef _HANDLERS_H_
#include "handlers.h"
#endif
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
#define DEFAULT_REFRESH_INTERVAL 60
/*---------------------------------------------------------------------------
Forward declarations
---------------------------------------------------------------------------*/
class RouterRefreshQueryElement; // COM
class RefreshItem;
class DomainStatusHandler;
struct MachineNodeData;
/*---------------------------------------------------------------------------
Class: RouterRefreshQueryElementList
---------------------------------------------------------------------------*/
class RouterRefreshQueryElementList
{
public:
~RouterRefreshQueryElementList();
HRESULT AddRefreshItem(RefreshItem* pItem); // no ref
HRESULT RemoveRefreshItem(RefreshItem& Item); // no ref
RouterRefreshQueryElement* Next(RouterRefreshQueryElement* pEle); // AddRef
protected:
CList<RouterRefreshQueryElement*, RouterRefreshQueryElement*> m_list;
CCriticalSection m_cs;
};
/*---------------------------------------------------------------------------
Class: RouterRefreshObjectGroup
Do refresh on a group, all it's members DoRefresh is called
---------------------------------------------------------------------------*/
class RouterRefreshObjectGroup
{
public:
RouterRefreshObjectGroup()
{
DEBUG_INCREMENT_INSTANCE_COUNTER(RouterRefreshObjectGroup);
}
~RouterRefreshObjectGroup();
HRESULT Join(RouterRefreshObject* pRefresh);
HRESULT Leave(RouterRefreshObject* pRefresh);
HRESULT Refresh();
protected:
CList<RouterRefreshObject*, RouterRefreshObject*> m_list;
};
/*---------------------------------------------------------------------------
Class: RouterRefreshObject
class RouterRefreshObject implements IRouterRefresh interface,
and also other two functions used by Status node refresh:
HRESULT AddStatusNode;
HRESULT RemoveStatusNode;
Internally to this object, it maitains a list of RefreshElements,
in this implementation, the element could be either build
from IRouterInfo pointer or, an machine status node pointer
The items are maintained by
thread safe list object RouterRefreshQueryElementList
---------------------------------------------------------------------------*/
class RouterRefreshObject :
public IRouterRefresh,
public IRouterRefreshModify,
public ThreadHandler
{
friend void RouterRefreshObjectTimerProc(LPARAM lParam, DWORD dwTime);
public:
DeclareIUnknownMembers(IMPL);
DeclareIRouterRefreshMembers(IMPL);
DeclareIRouterRefreshModifyMembers(IMPL);
DeclareITFSThreadHandlerMembers(IMPL);
RouterRefreshObject(/*IRouterInfo *pRouter, */HWND hWndSync);
~RouterRefreshObject();
// Interface in refresh Router Status nodes
HRESULT AddStatusNode(DomainStatusHandler* pStatusHandler, ITFSNode *pServerNode);
HRESULT RemoveStatusNode(ITFSNode *pServerNode);
HRESULT DoRefresh();
void SetGroup(RouterRefreshObjectGroup* pGroup) { m_pRefreshGroup = pGroup;};
protected:
void ExecuteRefresh();
AdviseDataList m_AdviseList; // list of advises
// Number of seconds between refresh intervals
DWORD m_dwSeconds;
// TRUE if we are currently in a refresh cycle
BOOL m_fInRefresh;
// TRUE if we have started the refresh mechanism
BOOL m_fStarted;
// Id returned by CTimerMgr::AllocateTimer()
int m_iEventId;
// This is tied directly to the IRouterInfo, it does not AddRef()
RouterRefreshQueryElementList m_listElements;
HWND m_hWndSync;
CRITICAL_SECTION m_critsec;
RouterRefreshObjectGroup* m_pRefreshGroup;
};
DeclareSmartPointer(SPRouterRefreshObject, RouterRefreshObject, if(m_p) m_p->Release());
typedef void (*REFRESHPROC)(LPARAM lParam, DWORD dwTime);
/*---------------------------------------------------------------------------
Class: CTimerDesc
This holds some of the per-refresh proc information.
---------------------------------------------------------------------------*/
class CTimerDesc
{
public:
LPARAM lParam;
UINT_PTR uTimerId;
UINT uTimerInterval;
REFRESHPROC refreshProc;
};
typedef CArray<CTimerDesc *, CTimerDesc *> CTimerArrayBase;
class CTimerMgr : protected CTimerArrayBase
{
public:
CTimerMgr();
~CTimerMgr();
public:
int AllocateTimer(REFRESHPROC procRefresh,
LPARAM lParam,
UINT uTimerInterval);
void FreeTimer(int uEventId);
void ChangeInterval(int uEventId, UINT uNewInterval);
//
// Function: GetTimerDesc
// Finds the TimerDesc based on the uTimerd (the one that is
// returned by SetTimer()).
//
CTimerDesc * GetTimerDesc(INT_PTR uTimerId);
CRITICAL_SECTION m_critsec;
};
extern CTimerMgr g_timerMgr;
enum RouterRefreshQueryElementStatus
{
RouterQuery_NoAction = 0,
RouterQuery_NeedQuery,
RouterQuery_Working,
RouterQuery_ToNotify,
};
/*---------------------------------------------------------------------------
Class: RefreshItem
RefreshItem generalize the interface for background refresh task to
DoQuery, and NotifyQueryResult
---------------------------------------------------------------------------*/
class RefreshItem
{
public:
RefreshItem(){
m_hBlockingThread = INVALID_HANDLE_VALUE;
DEBUG_INCREMENT_INSTANCE_COUNTER(RefreshItem);
};
virtual ~RefreshItem()
{
// this should be called in Destructor of derived class, to be safe, do it here again.
TerminateBlockingThread();
DEBUG_DECREMENT_INSTANCE_COUNTER(RefreshItem);
}
// helper function,
// Terminate Blocking Thread before Delete ..
// Should be called in Destructor of derived object
BOOL TerminateBlockingThread()
{
BOOL r = FALSE;
m_csBlockingThread.Lock();
if(m_hBlockingThread != INVALID_HANDLE_VALUE)
{
Assert(0); // just to notify some thread is still runing
r = TerminateThread(m_hBlockingThread, 1);
CloseHandle(m_hBlockingThread);
m_hBlockingThread = INVALID_HANDLE_VALUE;
}
m_csBlockingThread.Unlock();
return r;
};
void ResetBlockingThread()
{
SetBlockingThread(INVALID_HANDLE_VALUE);
};
BOOL SetBlockingThread(HANDLE hThread)
{
BOOL r = FALSE;
m_csBlockingThread.Lock();
if(m_hBlockingThread != INVALID_HANDLE_VALUE)
CloseHandle(m_hBlockingThread);
m_hBlockingThread = INVALID_HANDLE_VALUE;
if(hThread != INVALID_HANDLE_VALUE)
r = DuplicateHandle(GetCurrentProcess(),
hThread,
GetCurrentProcess(),
&m_hBlockingThread,
DUPLICATE_SAME_ACCESS,
FALSE,
DUPLICATE_SAME_ACCESS);
else
m_hBlockingThread = INVALID_HANDLE_VALUE;
m_csBlockingThread.Unlock();
return r;
}
// to detect if the query done, yet to Notify
virtual HRESULT NotifyQueryResult() = 0;
// this happens in background worker thread
virtual HRESULT DoQuery(HWND hwndHidden, UINT uMsgBase, ITFSThreadHandler* pHandler) = 0;
// used to compare if two items are the same
virtual LONG_PTR GetKey() = 0;
private:
HANDLE m_hBlockingThread;
CCriticalSection m_csBlockingThread;
};
/*---------------------------------------------------------------------------
Class: CRouterInfoRefreshItem
CRouterInfoRefreshItem implements the refresh task item for IRouterInfo
---------------------------------------------------------------------------*/
class CRouterInfoRefreshItem : public RefreshItem
{
public:
CRouterInfoRefreshItem(IRouterInfo* pRouter) : m_pRouter(pRouter){ASSERT(pRouter);};
virtual ~CRouterInfoRefreshItem()
{
TerminateBlockingThread();
};
// to detect if the query done, yet to Notify
virtual HRESULT NotifyQueryResult();
// this happens in background worker thread
virtual HRESULT DoQuery(HWND hwndHidden, UINT uMsgBase, ITFSThreadHandler* pHandler);
// used to compare if two items are the same
virtual LONG_PTR GetKey() {return (LONG_PTR)m_pRouter;};
protected:
// This is tied directly to the IRouterInfo, it does not AddRef()
IRouterInfo* m_pRouter;
SPIRouterInfo m_spRouterNew;
CCriticalSection m_cs;
};
/*---------------------------------------------------------------------------
Class: CStatusNodeRefreshItem
Implements the refresh task item fo the machine status node.
---------------------------------------------------------------------------*/
class CStatusNodeRefreshItem: public RefreshItem
{
public:
CStatusNodeRefreshItem(DomainStatusHandler* pStatusHandler,
ITFSNode *pServerNode);
virtual ~CStatusNodeRefreshItem();
// to detect if the query done, yet to Notify
virtual HRESULT NotifyQueryResult();
// this happens in background worker thread
virtual HRESULT DoQuery(HWND hwndHidden, UINT uMsgBase, ITFSThreadHandler* pHandler);
// used to compare if two items are the same
virtual LONG_PTR GetKey() { return (LONG_PTR)m_pNode;};
protected:
MachineNodeData* m_pData;
ITFSNode* m_pNode; //since this lives within the life time of node, so no ref count
DomainStatusHandler* m_pStatusHandler; // no ref count
CString m_strMachineName;
CCriticalSection m_cs;
};
/*---------------------------------------------------------------------------
Class: RouterRefreshQueryElement
RouterRefreshQueryElement is the unit of refresh, it is constructed by
using RefreshItem object. Each refresh item implements function
for DoQuery, and NotifyQueryResult
---------------------------------------------------------------------------*/
class ATL_NO_VTABLE RouterRefreshQueryElement :
public CComObjectRoot,
public IUnknown
{
BEGIN_COM_MAP(RouterRefreshQueryElement)
COM_INTERFACE_ENTRY(IUnknown)
END_COM_MAP()
public:
RouterRefreshQueryElement() : m_Status(RouterQuery_NoAction), m_pItem(NULL) {};
~RouterRefreshQueryElement(){ delete m_pItem; m_pItem = NULL;};
HRESULT SetRefreshItem(RefreshItem* pRouterInfo);
RefreshItem* GetRefreshItem();
RouterRefreshQueryElementStatus GetStatus()
{
RouterRefreshQueryElementStatus s;
m_cs.Lock();
s = m_Status;
m_cs.Unlock();
return s;
};
void SetStatus(RouterRefreshQueryElementStatus s)
{
m_cs.Lock();
m_Status = s;
m_cs.Unlock();
};
// to detect if the query done, yet to Notify
HRESULT TryNotifyQueryResult();
// set notify after query
void PostNotify(HWND hwndHidden, UINT uMsgBase, ITFSThreadHandler* pHandler);
// this happens in background worker thread
HRESULT DoQuery(HWND hwndHidden, UINT uMsgBase, ITFSThreadHandler* pHandler);
protected:
// This is tied directly to the IRouterInfo, it does not AddRef()
// we may need to change this in the future OPT
RefreshItem* m_pItem;
RouterRefreshQueryElementStatus m_Status;
CCriticalSection m_cs;
};
DeclareSmartPointer(SPRouterRefreshQueryElement, RouterRefreshQueryElement, if(m_p) m_p->Release());
/*---------------------------------------------------------------------------
Class: RouterRefreshQueryObject
RouterRefreshQueryObject is the worker of RouterRefreshObject, it execute
RefreshElements DoQuery in backgroud process
---------------------------------------------------------------------------*/
class RouterRefreshQueryObject : public CQueryObject
{
public:
RouterRefreshQueryObject();
void Init(RouterRefreshQueryElementList* plist)
{
ASSERT(plist);
m_plistElements = plist;
};
// Override the ITFSQueryObject::Execute
STDMETHOD(Execute)();
STDMETHOD(OnThreadExit)();
protected:
RouterRefreshQueryElementList* m_plistElements;
};
#endif _REFRESH_H_