windows-nt/Source/XPSP1/NT/admin/snapin/mtfrmwk/treedata.h
2020-09-26 16:20:57 +08:00

718 lines
22 KiB
C++

// This is a part of the Microsoft Management Console.
// Copyright (C) Microsoft Corporation, 1995 - 1999
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Management Console and related
// electronic documentation provided with the interfaces.
#ifndef _TREEDATA_H
#define _TREEDATA_H
/////////////////////////////////////////////////////////////////////////////
// Miscellanea
extern LPCWSTR g_lpszNullString;
/////////////////////////////////////////////////////////////////////////////
// Generic Helper functions
template<class TYPE>
inline void SAFE_RELEASE(TYPE*& pObj)
{
if (pObj != NULL)
{
pObj->Release();
pObj = NULL;
}
else
{
TRACE(_T("Release called on NULL interface ptr"));
}
}
///////////////////////////////////////////////////////////////////
// Context Menu data structures and macros
#define MAX_CONTEXT_MENU_STRLEN 128
struct MENUDATARES
{
WCHAR szBuffer[MAX_CONTEXT_MENU_STRLEN*2];
UINT uResID;
};
struct MENUMAP
{
MENUDATARES* dataRes;
CONTEXTMENUITEM2* ctxMenu;
};
#define DECLARE_MENU(theClass) \
class theClass \
{ \
public: \
static LPCONTEXTMENUITEM2 GetContextMenuItem() { return GetMenuMap()->ctxMenu; }; \
static MENUMAP* GetMenuMap(); \
};
#define BEGIN_MENU(theClass) \
MENUMAP* theClass::GetMenuMap() {
#define BEGIN_CTX static CONTEXTMENUITEM2 ctx[] = {
#define CTX_ENTRY_TOP(cmdID, languageIndependantStringID) { L"",L"", cmdID, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0, languageIndependantStringID},
#define CTX_ENTRY_NEW(cmdID, languageIndependantStringID) { L"",L"", cmdID, CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, 0, languageIndependantStringID},
#define CTX_ENTRY_TASK(cmdID, languageIndependantStringID) { L"",L"", cmdID, CCM_INSERTIONPOINTID_PRIMARY_TASK, 0, 0, languageIndependantStringID},
#define CTX_ENTRY_VIEW(cmdID, languageIndependantStringID) { L"",L"", cmdID, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0, languageIndependantStringID},
#define END_CTX { NULL, NULL, 0, 0, 0, 0} };
#define BEGIN_RES static MENUDATARES dataRes[] = {
#define RES_ENTRY(resID) {L"", resID },
#define END_RES { NULL, 0 } };
#define END_MENU \
static MENUMAP menuMap = { dataRes, ctx }; \
return &menuMap; }
BOOL LoadContextMenuResources(MENUMAP* pMenuMap);
//
// Toolbar macros
//
#define DECLARE_TOOLBAR_MAP() \
public: \
virtual HRESULT ToolbarNotify(int event, \
CComponentDataObject* pComponentData, \
CNodeList* pNodeList);
#define BEGIN_TOOLBAR_MAP(theClass) \
HRESULT theClass::ToolbarNotify(int event, \
CComponentDataObject* pComponentData, \
CNodeList* pNodeList) \
{ \
HRESULT hr = S_OK; \
event; \
pComponentData; \
pNodeList;
#define TOOLBAR_EVENT(toolbar_event, function) \
if (event == toolbar_event) \
{ \
hr = function(pComponentData, pNodeList); \
}
#define END_TOOLBAR_MAP() \
return hr; \
}
#define DECLARE_TOOLBAR_EVENT(toolbar_event, value) \
static const int toolbar_event = value;
////////////////////////////////////////////////////////////
// header control resources data structures
#define MAX_RESULT_HEADER_STRLEN 128
struct RESULT_HEADERMAP
{
WCHAR szBuffer[MAX_RESULT_HEADER_STRLEN];
UINT uResID;
int nFormat;
int nWidth;
};
BOOL LoadResultHeaderResources(RESULT_HEADERMAP* pHeaderMap, int nCols);
////////////////////////////////////////////////////////////
// bitmap strips resources data structures
template <UINT nResID> class CBitmapHolder : public CBitmap
{
public:
BOOL LoadBitmap() { return CBitmap::LoadBitmap(nResID);}
};
///////////////////////////////////////////////////////////////////////////////
// FORWARD DECLARATIONS
class CComponentDataObject;
class CContainerNode;
class CMTContainerNode;
class CLeafNode;
class CPropertyPageHolderBase;
class CBackgroundThread;
class CQueryObj;
/////////////////////////////////////////////////////////////////////
// CObjBase
// base class for all objects relying on RTTI and class type info
class CObjBase
{
public:
CObjBase() {}
virtual ~CObjBase() {}
};
/////////////////////////////////////////////////////////////////////
// CTreeNode
// cannot construct objects of this class, have to derive from it
#define DECLARE_NODE_GUID() \
static const GUID NodeTypeGUID; \
virtual const GUID* GetNodeType() { return &NodeTypeGUID;}
// use the HIWORD for generic flags and leave the LOWORD for application specific data
#define TN_FLAG_HIDDEN (0x00010000) // does not appear in the UI
#define TN_FLAG_NO_WRITE (0x00020000) // cannot edit or create
#define TN_FLAG_NO_DELETE (0x00040000) // cannot delete
#define TN_FLAG_HAS_SHEET (0x00080000) // this node or a child has a property sheet up
#define TN_FLAG_CONTAINER (0x00100000) // container (i.e. not leaf)
#define TN_FLAG_CONTAINER_ENUM (0x00200000) // container node has been enumerated (back end)
#define TN_FLAG_CONTAINER_EXP (0x00400000) // container node has been expanded (UI node)
class CTreeNode : public CObjBase
{
public:
virtual ~CTreeNode() {}
CContainerNode* GetContainer() { return m_pContainer; }
void SetContainer(CContainerNode* pContainer) { m_pContainer = pContainer; }
BOOL HasContainer(CContainerNode* pContainerNode);
virtual LPCWSTR GetDisplayName() { return m_szDisplayName; }
virtual void SetDisplayName(LPCWSTR lpszDisplayName) { m_szDisplayName = lpszDisplayName;}
//
// Data Object related data
//
virtual const GUID* GetNodeType() { return NULL;}
virtual HRESULT GetDataHere(CLIPFORMAT,
LPSTGMEDIUM,
CDataObject*) { return DV_E_CLIPFORMAT;}
virtual HRESULT GetData(CLIPFORMAT,
LPSTGMEDIUM,
CDataObject*) { return DV_E_CLIPFORMAT;}
virtual HRESULT GetResultViewType(CComponentDataObject* pComponentData,
LPOLESTR* ppViewType,
long* pViewOptions);
virtual HRESULT OnShow(LPCONSOLE) { return S_OK; }
//
// flag manipulation API's
//
BOOL IsContainer() { return (m_dwNodeFlags & TN_FLAG_CONTAINER) ? TRUE : FALSE;}
BOOL IsVisible() { return (m_dwNodeFlags & TN_FLAG_HIDDEN) ? FALSE : TRUE;}
BOOL CanDelete() { return (m_dwNodeFlags & TN_FLAG_NO_DELETE) ? FALSE : TRUE;}
virtual void SetFlagsDown(DWORD dwNodeFlags, BOOL bSet);
void SetFlagsUp(DWORD dwNodeFlags, BOOL bSet);
DWORD GetFlags() { return m_dwNodeFlags;}
virtual BOOL CanExpandSync() { return FALSE; }
virtual void Show(BOOL bShow, CComponentDataObject* pComponentData);
//
// Verb handlers
//
virtual HRESULT OnRename(CComponentDataObject*,
LPWSTR) { return S_FALSE; }
virtual void OnDelete(CComponentDataObject* pComponentData,
CNodeList* pNodeList) = 0;
virtual BOOL OnRefresh(CComponentDataObject*,
CNodeList*) { return FALSE; }
virtual HRESULT OnCommand(long,
DATA_OBJECT_TYPES,
CComponentDataObject*,
CNodeList*) { return S_OK; };
virtual HRESULT OnAddMenuItems(IContextMenuCallback2* pContextMenuCallback2,
DATA_OBJECT_TYPES type,
long *pInsertionAllowed,
CNodeList* pNodeList);
virtual HRESULT OnAddMenuItemsMultipleSelect(IContextMenuCallback2*,
DATA_OBJECT_TYPES,
long*,
CNodeList*) { return S_OK; }
virtual MMC_CONSOLE_VERB GetDefaultVerb(DATA_OBJECT_TYPES type,
CNodeList* pNodeList);
virtual void OnSetVerbState(LPCONSOLEVERB pConsoleVerb,
DATA_OBJECT_TYPES type,
CNodeList* pNodeList);
virtual HRESULT OnSetToolbarVerbState(IToolbar* pToolbar,
CNodeList* pNodeList);
virtual BOOL OnSetRenameVerbState(DATA_OBJECT_TYPES type,
BOOL* pbHide,
CNodeList* pNodeList);
virtual BOOL OnSetDeleteVerbState(DATA_OBJECT_TYPES type,
BOOL* pbHide,
CNodeList* pNodeList);
virtual BOOL OnSetRefreshVerbState(DATA_OBJECT_TYPES type,
BOOL* pbHide,
CNodeList* pNodeList);
virtual BOOL OnSetCutVerbState(DATA_OBJECT_TYPES type,
BOOL* pbHide,
CNodeList* pNodeList);
virtual BOOL OnSetCopyVerbState(DATA_OBJECT_TYPES type,
BOOL* pbHide,
CNodeList* pNodeList);
virtual BOOL OnSetPasteVerbState(DATA_OBJECT_TYPES type,
BOOL* pbHide,
CNodeList* pNodeList);
virtual BOOL OnSetPrintVerbState(DATA_OBJECT_TYPES type,
BOOL* pbHide,
CNodeList* pNodeList);
//
// Property Page methods
//
virtual BOOL DelegatesPPToContainer() { return FALSE; }
virtual void ShowPageForNode(CComponentDataObject* pComponentDataObject);
virtual BOOL HasPropertyPages(DATA_OBJECT_TYPES type,
BOOL* pbHideVerb,
CNodeList* pNodeList);
virtual HRESULT CreatePropertyPages(LPPROPERTYSHEETCALLBACK,
LONG_PTR,
CNodeList*) { return E_FAIL; }
virtual void OnPropertyChange(CComponentDataObject* pComponentData,
BOOL bScopePane,long changeMask);
virtual BOOL CanCloseSheets() { return TRUE;}
void OnCreateSheet();
void OnDeleteSheet();
BOOL HasSheet() { return (m_dwNodeFlags & TN_FLAG_HAS_SHEET) ? TRUE : FALSE;}
BOOL GetSheetCount() { return m_nSheetCount;}
virtual void IncrementSheetLockCount();
virtual void DecrementSheetLockCount();
BOOL IsSheetLocked() { return m_nSheetLockCount > 0;}
//
// Misc.
//
virtual LPWSTR GetDescriptionBarText() { return L""; }
virtual LPCWSTR GetString(int nCol) = 0;
virtual int GetImageIndex(BOOL bOpenImage) = 0;
virtual void Trace() { TRACE(_T("Name %s "), (LPCTSTR)m_szDisplayName);}
void DeleteHelper(CComponentDataObject* pComponentData);
protected:
CString m_szDisplayName; // name of the item
CContainerNode* m_pContainer; // back pointer to the container the node is in
DWORD m_dwNodeFlags;
LONG m_nSheetLockCount; // keeps track if a node has been locked by a property sheet
LONG m_nSheetCount; // keeps track of the # of sheets the node has up
CTreeNode()
{
m_pContainer = NULL;
m_nSheetLockCount = 0;
m_dwNodeFlags = 0x0; //m_dwNodeFlags |= TN_FLAG_HIDDEN;
m_nSheetCount = 0;
}
virtual LPCONTEXTMENUITEM2 OnGetContextMenuItemTable() { return NULL;}
virtual BOOL OnAddMenuItem(LPCONTEXTMENUITEM2,
long*) { return TRUE;}
friend class CContainerNode; // to get access to the m_pContainer member
//
// Provides a default implementation for toolbar support
//
DECLARE_TOOLBAR_MAP()
};
///////////////////////////////////////////////////////////////////////
// CNodeList
// collection of nodes
typedef CList<CTreeNode*,CTreeNode*> CNodeListBase;
class CNodeList : public CNodeListBase
{
public:
BOOL RemoveNode(CTreeNode* p)
{
POSITION pos = Find(p);
if (pos == NULL)
return FALSE;
RemoveAt(pos);
return TRUE;
}
void RemoveAllNodes()
{
while (!IsEmpty())
delete RemoveTail();
}
BOOL HasNode(CTreeNode* p)
{
return NULL != Find(p);
}
};
////////////////////////////////////////////////////////////////////////
// CContainerNode
// node that can be a container of other nodes
class CContainerNode : public CTreeNode
{
public:
CContainerNode()
{
m_ID = 0;
m_dwNodeFlags |= TN_FLAG_CONTAINER;
m_nState = -1;
m_dwErr = 0x0;
m_nThreadLockCount = 0;
}
virtual ~CContainerNode() { ASSERT(m_nSheetLockCount == 0); RemoveAllChildrenFromList(); }
CContainerNode* GetRootContainer()
{ return (m_pContainer != NULL) ? m_pContainer->GetRootContainer() : this; }
//
// Thread Helpers
//
void IncrementThreadLockCount();
void DecrementThreadLockCount();
BOOL IsThreadLocked() { return m_nThreadLockCount > 0;}
virtual BOOL OnEnumerate(CComponentDataObject*, BOOL bAsync = TRUE)
{ bAsync; return TRUE;} // TRUE = add children in the list to UI
//
// Node state helpers
//
BOOL HasChildren() { return !m_containerChildList.IsEmpty() || !m_leafChildList.IsEmpty(); }
void ForceEnumeration(CComponentDataObject* pComponentData);
void MarkEnumerated(BOOL bEnum = TRUE);
BOOL IsEnumerated() { ASSERT(IsContainer()); return (m_dwNodeFlags & TN_FLAG_CONTAINER_ENUM) ? TRUE : FALSE;}
void MarkExpanded() { ASSERT(IsContainer()); m_dwNodeFlags |= TN_FLAG_CONTAINER_EXP; }
BOOL IsExpanded() { ASSERT(IsContainer()); return (m_dwNodeFlags & TN_FLAG_CONTAINER_EXP) ? TRUE : FALSE;}
void MarkEnumeratedAndLoaded(CComponentDataObject* pComponentData);
void SetScopeID(HSCOPEITEM ID) { m_ID = ID;}
HSCOPEITEM GetScopeID() { return m_ID;}
BOOL AddedToScopePane() { return GetScopeID() != 0;}
virtual CColumnSet* GetColumnSet() = 0;
virtual LPCWSTR GetColumnID() = 0;
virtual void SetFlagsDown(DWORD dwNodeFlags, BOOL bSet);
void SetFlagsOnNonContainers(DWORD dwNodeFlags,BOOL bSet);
//
// child list mainpulation API's
//
CNodeList* GetContainerChildList() { return &m_containerChildList; }
CNodeList* GetLeafChildList() { return &m_leafChildList; }
BOOL AddChildToList(CTreeNode* p);
BOOL AddChildToListSorted(CTreeNode* p, CComponentDataObject* pComponentData);
BOOL RemoveChildFromList(CTreeNode* p);
void RemoveAllChildrenFromList();
void RemoveAllContainersFromList() { m_containerChildList.RemoveAllNodes(); }
void RemoveAllLeavesFromList() { m_leafChildList.RemoveAllNodes(); }
//
// given a node, it searches for it recursively and if successful it returns the
// container the node is in
//
BOOL FindChild(CTreeNode* pNode, CTreeNode** ppContainer);
BOOL AddChildToListAndUI(CTreeNode* pChildToAdd, CComponentDataObject* pComponentData);
BOOL AddChildToListAndUISorted(CTreeNode* pChildToAdd, CComponentDataObject* pComponentData);
virtual int Compare(CTreeNode* pNodeA, CTreeNode* pNodeB, int nCol, LPARAM lUserParam);
virtual HRESULT CreatePropertyPagesHelper(LPPROPERTYSHEETCALLBACK,
LONG_PTR,
long) { return E_FAIL;}
virtual BOOL OnRefresh(CComponentDataObject* pComponentData,
CNodeList* pNodeList);
virtual void OnColumnsChanged(int*, int) {}
void RemoveAllChildrenHelper(CComponentDataObject* pComponentData);
protected:
virtual void OnChangeState(CComponentDataObject*) {}
void AddCurrentChildrenToUI(CComponentDataObject* pComponentData);
LONG m_nThreadLockCount;
CNodeList m_leafChildList; // leaf contents of the node
CNodeList m_containerChildList; // container contents of the node
HSCOPEITEM m_ID; // ID when the item is inserted in the master tree
int m_nState; // for general purpose finite state machine implementation
DWORD m_dwErr; // for general purpose error handling
};
////////////////////////////////////////////////////////////////////////
// CLeafNode
// node that is not a container of other nodes
class CLeafNode : public CTreeNode
{
public:
};
///////////////////////////////////////////////////////////////////
// data nodes
// the root, with folders in it
class CRootData : public CContainerNode
{
public:
CRootData(CComponentDataObject* pComponentData)
{
ASSERT(pComponentData != NULL);
m_pComponentData = pComponentData;
m_bDirty = FALSE;
}
virtual LPCWSTR GetString(int nCol)
{
if (nCol == 0)
return GetDisplayName();
return g_lpszNullString;
}
CComponentDataObject* GetComponentDataObject(){ return m_pComponentData;}
CTreeNode* GetNodeFromCookie(MMC_COOKIE cookie)
{
// cookie == 0 means root to enumerate
if (cookie == NULL)
{
return (CTreeNode*)this;
}
else
{
CTreeNode* pNode = (CTreeNode*)cookie;
CTreeNode* pContainer;
if (FindChild(pNode,&pContainer))
{
return pNode;
}
}
return NULL;
}
// IStream manipulation helpers
virtual HRESULT IsDirty() { return m_bDirty ? S_OK : S_FALSE; }
virtual HRESULT Load(IStream*) { return S_OK; }
virtual HRESULT Save(IStream*, BOOL) { return S_OK; }
void SetDirtyFlag(BOOL bDirty) { m_bDirty = bDirty ;}
private:
CComponentDataObject* m_pComponentData;
BOOL m_bDirty;
CString m_szSnapinType; // constant part of the name loaded from resources
};
//////////////////////////////////////////////////////////////////////
// CBackgroundThread
class CBackgroundThread : public CWinThread
{
public:
CBackgroundThread();
virtual ~CBackgroundThread();
void SetQueryObj(CQueryObj* pQueryObj);
BOOL Start(CMTContainerNode* pNode, CComponentDataObject* pComponentData);
virtual BOOL InitInstance() { return TRUE; } // MFC override
virtual int Run(); // MFC override
void Lock() { ::EnterCriticalSection(&m_cs); }
void Unlock() { ::LeaveCriticalSection(&m_cs); }
void Abandon();
BOOL IsAbandoned();
BOOL OnAddToQueue(INT_PTR nCount);
CObjBase* RemoveFromQueue();
BOOL IsQueueEmpty();
BOOL PostHaveData();
BOOL PostError(DWORD dwErr);
BOOL PostExiting();
void AcknowledgeExiting() { VERIFY(0 != ::SetEvent(m_hEventHandle));}
private:
// communication with ComponentData object
BOOL PostMessageToComponentDataRaw(UINT Msg, WPARAM wParam, LPARAM lParam);
void WaitForExitAcknowledge();
CRITICAL_SECTION m_cs; // critical section to sync access to data
HANDLE m_hEventHandle; // syncronization handle for shutdown notification
CMTContainerNode* m_pContNode; // back pointer to node the thread is executing for
CQueryObj* m_pQueryObj; // query object the thread is executing
INT_PTR m_nQueueCountMax; // max size of the queue
HWND m_hHiddenWnd; // handle to window to post messages
BOOL m_bAbandoned;
};
//////////////////////////////////////////////////////////////////////
// CQueryObj
typedef CList<CObjBase*,CObjBase*> CObjBaseList;
class CQueryObj
{
public:
CQueryObj() { m_dwErr = 0; m_pThread = NULL;}
virtual ~CQueryObj()
{
while (!m_objQueue.IsEmpty())
delete m_objQueue.RemoveTail();
};
void SetThread(CBackgroundThread* pThread)
{
ASSERT(pThread != NULL);
m_pThread = pThread;
}
CBackgroundThread* GetThread() {return m_pThread;}
virtual BOOL Enumerate() { return FALSE;}
virtual BOOL AddQueryResult(CObjBase* pObj)
{
BOOL bRes = FALSE;
if (m_pThread != NULL)
{
BOOL bPostedHaveDataMessage = FALSE;
m_pThread->Lock();
bRes = NULL != m_objQueue.AddTail(pObj);
bPostedHaveDataMessage = m_pThread->OnAddToQueue(m_objQueue.GetCount());
m_pThread->Unlock();
// wait for the queue length to go down to zero
if (bPostedHaveDataMessage)
{
INT_PTR nQueueCount = 0;
do
{
m_pThread->Lock();
nQueueCount = m_objQueue.GetCount();
m_pThread->Unlock();
if (m_pThread->IsAbandoned())
{
break;
}
if (nQueueCount > 0)
{
::Sleep(100);
}
}
while (nQueueCount > 0);
} // if
}
else
{
bRes = NULL != m_objQueue.AddTail(pObj);
}
ASSERT(bRes);
return bRes;
}
virtual void OnError(DWORD dwErr)
{
if (m_pThread != NULL)
{
m_pThread->Lock();
m_dwErr = dwErr;
m_pThread->Unlock();
m_pThread->PostError(dwErr);
}
else
{
m_dwErr = dwErr;
}
}
CObjBaseList* GetQueue() { return &m_objQueue;}
DWORD GetError()
{
if (m_pThread != NULL)
{
m_pThread->Lock();
DWORD dwErr = m_dwErr;
m_pThread->Unlock();
return dwErr;
}
else
{
return m_dwErr;
}
}
private:
CBackgroundThread* m_pThread; // back pointer, if in the context of a thread
CObjBaseList m_objQueue; // queue for results
DWORD m_dwErr; // error code, if any
};
////////////////////////////////////////////////////////////////////////
// CMTContainerNode
// container that can do operations from a secondary thread
class CMTContainerNode : public CContainerNode
{
public:
CMTContainerNode()
{
m_pThread = NULL;
}
virtual ~CMTContainerNode();
virtual BOOL OnEnumerate(CComponentDataObject* pComponentData, BOOL bAsync = TRUE);
virtual BOOL OnRefresh(CComponentDataObject* pComponentData,
CNodeList* pNodeList);
protected:
// thread creation
virtual CBackgroundThread* CreateThreadObject()
{
return new CBackgroundThread; // override if need derived tipe of object
}
// query creation
virtual CQueryObj* OnCreateQuery() // override to create a user defined query object
{
return new CQueryObj(); // return a do-nothing query
}
// main message handler for thread messages
virtual void OnThreadHaveDataNotification(CComponentDataObject* pComponentDataObject);
virtual void OnThreadErrorNotification(DWORD dwErr, CComponentDataObject* pComponentDataObject);
virtual void OnThreadExitingNotification(CComponentDataObject* pComponentDataObject);
virtual void OnHaveData(CObjBase*, CComponentDataObject*) {}
virtual void OnError(DWORD dwErr) { m_dwErr = dwErr; }
BOOL StartBackgroundThread(CComponentDataObject* pComponentData, BOOL bAsync = TRUE);
CBackgroundThread* GetThread() { ASSERT(m_pThread != NULL); return m_pThread;}
void AbandonThread(CComponentDataObject* pComponentData);
private:
CBackgroundThread* m_pThread; // pointer to thread object executing the code
friend class CHiddenWnd; // to get OnThreadNotification()
friend class CRunningThreadTable; // to get AbandonThread()
};
#endif // _TREEDATA_H