//============================================================================ // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: refresh.h // // History: // Kenn Takara Sept. 16, 1997 Created. // //============================================================================ #ifndef _REFRESH_H_ #define _REFRESH_H_ #include #include #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 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 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 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_