//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1998 - 1999
//
//  File:       compbase.h
//
//--------------------------------------------------------------------------

#ifndef _COMPBASE_H
#define _COMPBASE_H


///////////////////////////////////////////////////////////////////////////////
// Base classes implementing the IComponent and IComponentData interfaces
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
// IConsole::UpdateAllViews() : values for the Hint argument

#define ADD_RESULT_ITEM				( 0x00000001 )
#define DELETE_RESULT_ITEM			( 0x00000002 )
#define CHANGE_RESULT_ITEM_DATA		( 0x00000004 )
#define CHANGE_RESULT_ITEM_ICON		( 0x00000008 )
#define CHANGE_RESULT_ITEM			( CHANGE_RESULT_ITEM_DATA | CHANGE_RESULT_ITEM_ICON )
#define REPAINT_RESULT_PANE			( 0x00000010 )
#define DELETE_ALL_RESULT_ITEMS		( 0x00000011 )
#define UPDATE_VERB_STATE			( 0x00000012 )
#define SORT_RESULT_PANE			( 0x00000013 )
#define UPDATE_DESCRIPTION_BAR ( 0x00000100 )
#define UPDATE_RESULT_PANE_VIEW ( 0x00000200 )
#define DELETE_MULTIPLE_RESULT_ITEMS ( 0x00000400)

///////////////////////////////////////////////////////////////////////////////
// DATA STRUCTURES

extern DWORD _MainThreadId;
extern CString LOGFILE_NAME;

///////////////////////////////////////////////////////////////////////////////
// FORWARD DECLARATIONS

class CComponentDataObject;		
class CComponentObject;			
class CRootData;				
class CTreeNode;				
class CContainerNode;			
class CMTContainerNode;			
class CLeafNode;				
class CPropertyPageHolderTable;

///////////////////////////////////////////////////////////////////////////////
// global functions


struct _NODE_TYPE_INFO_ENTRY
{
	const GUID* m_pNodeGUID;
	LPCTSTR		m_lpszNodeDescription;
};


HRESULT RegisterSnapin(const GUID* pSnapinCLSID,
                       const GUID* pStaticNodeGUID,
                       const GUID* pAboutGUID,
					   LPCTSTR lpszNameString, LPCTSTR lpszVersion, LPCTSTR lpszProvider,
             BOOL bExtension, _NODE_TYPE_INFO_ENTRY* pNodeTypeInfoEntryArray,
             UINT nSnapinNameID = 0);

HRESULT UnregisterSnapin(const GUID* pSnapinCLSID);

HRESULT RegisterNodeType(const GUID* pGuid, LPCTSTR lpszNodeDescription);
HRESULT UnregisterNodeType(const GUID* pGuid);

HRESULT RegisterNodeExtension(const GUID* pNodeGuid, LPCTSTR lpszExtensionType,
							  const GUID* pExtensionSnapinCLSID, LPCTSTR lpszDescription, BOOL bDynamic);
HRESULT UnregisterNodeExtension(const GUID* pNodeGuid, LPCTSTR lpszExtensionType,
							  const GUID* pExtensionSnapinCLSID, BOOL bDynamic);

/////////////////////////////////////////////////////////////////////////////
// CTimerThread

class CTimerThread : public CWinThread
{
public:
	CTimerThread() { m_bAutoDelete = FALSE; m_hWnd = 0;}

	BOOL Start(HWND hWnd);
	virtual BOOL InitInstance() { return TRUE; }	// MFC override
	virtual int Run() { return -1;}					// MFC override

protected:
	BOOL PostMessageToWnd(WPARAM wParam, LPARAM lParam);
private:
	HWND					m_hWnd;

};


/////////////////////////////////////////////////////////////////////////////
// CWorkerThread

class CWorkerThread : public CWinThread
{
public:
	CWorkerThread();
	virtual ~CWorkerThread();

	BOOL Start(HWND hWnd);
	virtual BOOL InitInstance() { return TRUE; }	// MFC override
	virtual int Run() { return -1;}					// MFC override

	void Lock() { ::EnterCriticalSection(&m_cs); }
	void Unlock() { ::LeaveCriticalSection(&m_cs); }

	void Abandon();
	BOOL IsAbandoned();

	void AcknowledgeExiting() { VERIFY(0 != ::SetEvent(m_hEventHandle));}

protected:
	virtual void OnAbandon() {}

protected:
	BOOL PostMessageToWnd(UINT Msg, WPARAM wParam, LPARAM lParam);
	void WaitForExitAcknowledge();

private:
	CRITICAL_SECTION		m_cs;	
	HANDLE					m_hEventHandle;

	HWND					m_hWnd;
	BOOL					m_bAbandoned;
};



////////////////////////////////////////////////////////////////////
// CHiddenWnd : Hidden window to syncronize threads and CComponentData object

class CHiddenWnd : public CHiddenWndBase
{
public:
	CHiddenWnd(CComponentDataObject* pComponentDataObject);

	static const UINT s_NodeThreadHaveDataNotificationMessage;
	static const UINT s_NodeThreadErrorNotificationMessage;
	static const UINT s_NodeThreadExitingNotificationMessage;

	static const UINT s_NodePropertySheetCreateMessage;
	static const UINT s_NodePropertySheetDeleteMessage;	

	static const UINT s_ExecCommandMessage;		
	static const UINT s_ForceEnumerationMessage;			
	static const UINT s_TimerThreadMessage;			

	UINT_PTR m_nTimerID;
private:
	CComponentDataObject* m_pComponentDataObject; // back pointer
public:

	BEGIN_MSG_MAP(CHiddenWnd)
	  MESSAGE_HANDLER( CHiddenWnd::s_NodeThreadHaveDataNotificationMessage, OnNodeThreadHaveDataNotification )
	  MESSAGE_HANDLER( CHiddenWnd::s_NodeThreadErrorNotificationMessage, OnNodeThreadErrorNotification )
	  MESSAGE_HANDLER( CHiddenWnd::s_NodeThreadExitingNotificationMessage, OnNodeThreadExitingNotification )

	  MESSAGE_HANDLER( CHiddenWnd::s_NodePropertySheetCreateMessage, OnNodePropertySheetCreate )
	  MESSAGE_HANDLER( CHiddenWnd::s_NodePropertySheetDeleteMessage, OnNodePropertySheetDelete )
	  
	  MESSAGE_HANDLER( CHiddenWnd::s_ExecCommandMessage, OnExecCommand )
	  MESSAGE_HANDLER( CHiddenWnd::s_ForceEnumerationMessage, OnForceEnumeration )
	  MESSAGE_HANDLER( CHiddenWnd::s_TimerThreadMessage, OnTimerThread )

    MESSAGE_HANDLER( WM_TIMER, OnTimer )
	    
    CHAIN_MSG_MAP(CHiddenWndBase)
  END_MSG_MAP()

	LRESULT OnNodeThreadHaveDataNotification(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnNodeThreadErrorNotification(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnNodeThreadExitingNotification(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnNodePropertySheetCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnNodePropertySheetDelete(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnExecCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnForceEnumeration(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnTimerThread(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

	LRESULT OnTimer(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
};

////////////////////////////////////////////////////////////////////////////////////
// CRunningThreadTable
// all CMTContainerNode with running refresh/enumerate background threads will
// register/unregister in this table to allow proper thread abandoning at shutdown

class CRunningThreadTable
{
public:
	CRunningThreadTable(CComponentDataObject* pComponentData);
	~CRunningThreadTable();

	void Add(CMTContainerNode* pNode);
	void Remove(CMTContainerNode* pNode);
	void RemoveAll();
  BOOL IsPresent(CMTContainerNode* pNode);

private:
	CComponentDataObject* m_pComponentData; // back pointer

	CMTContainerNode** m_pEntries;
	int m_nSize;
};
	


////////////////////////////////////////////////////////////////////////////////////
// CExecContext

class CExecContext
{
public:
	CExecContext();
	~CExecContext();
	virtual void Execute(LPARAM arg) = 0; // code to be executed from main thread
	void Wait();	// secondary thread waits on this call
	void Done();	// called when main thread done executing
private:
	HANDLE	m_hEventHandle;
};


////////////////////////////////////////////////////////////////////////////////////
// CNotificationSinkBase

class CNotificationSinkBase
{
public:
	virtual void OnNotify(DWORD dwEvent, WPARAM dwArg1, LPARAM dwArg2) = 0;
};

////////////////////////////////////////////////////////////////////////////////////
// CNotificationSinkEvent

class CNotificationSinkEvent : public CNotificationSinkBase
{
public:
	CNotificationSinkEvent();
	~CNotificationSinkEvent();

public:
	void OnNotify(DWORD dwEvent, WPARAM dwArg1, LPARAM dwArg2);
	virtual void Wait();
private:
	HANDLE	m_hEventHandle;
};


////////////////////////////////////////////////////////////////////////////////////
// CNotificationSinkTable

class CNotificationSinkTable
{
public:
	CNotificationSinkTable();
	~CNotificationSinkTable();
	
	void Advise(CNotificationSinkBase* p);
	void Unadvise(CNotificationSinkBase* p);
	void Notify(DWORD dwEvent, WPARAM dwArg1, LPARAM dwArg2);

private:
	void Lock()
	{
		TRACE(_T("CNotificationSinkTable::Lock()\n"));
		::EnterCriticalSection(&m_cs);
	}
	void Unlock()
	{
		TRACE(_T("CNotificationSinkTable::Unlock()\n"));
		::LeaveCriticalSection(&m_cs);
	}

	CRITICAL_SECTION m_cs;
	CNotificationSinkBase**	m_pEntries;
	int m_nSize;
};



////////////////////////////////////////////////////////////////////////////////////
// CPersistStreamImpl

class CPersistStreamImpl : public IPersistStream
{
public:
	HRESULT STDMETHODCALLTYPE GetClassID(CLSID* pClassID) = 0;
  HRESULT STDMETHODCALLTYPE IsDirty() = 0;
  HRESULT STDMETHODCALLTYPE Load(IStream __RPC_FAR *pStm) = 0;
  HRESULT STDMETHODCALLTYPE Save(IStream __RPC_FAR *pStm, BOOL fClearDirty) = 0;
  HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize)
	{
		ASSERT(FALSE);

    //
		// arbitrary value, do we ever get called?
    //
		pcbSize->LowPart = 0xffff;
    pcbSize->HighPart= 0x0;
		return S_OK;
	}
};

///////////////////////////////////////////////////////////////////////////////
// CWatermarkInfo

class CWatermarkInfo
{
public:
	CWatermarkInfo()
	{
		m_nIDBanner = 0;
		m_nIDWatermark = 0;
		m_hPalette = NULL;
		m_bStretch = TRUE;
	}
	UINT		m_nIDBanner;
	UINT		m_nIDWatermark;
	HPALETTE	m_hPalette;
	BOOL		m_bStretch;
};



////////////////////////////////////////////////////////////////////////////////
// CColumn

class CColumn
{
public:
  CColumn(LPCWSTR lpszColumnHeader,
          int nFormat,
          int nWidth,
          UINT nColumnNum) 
  {
    m_lpszColumnHeader = NULL;
    SetHeader(lpszColumnHeader);
    m_nFormat = nFormat;
    m_nWidth = nWidth;
    m_nColumnNum = nColumnNum;
  }

  ~CColumn() 
  {
    free(m_lpszColumnHeader);
  }

  LPCWSTR GetHeader() { return (LPCWSTR)m_lpszColumnHeader; }
  void SetHeader(LPCWSTR lpszColumnHeader) 
  { 
    if (m_lpszColumnHeader != NULL)
    {
      free(m_lpszColumnHeader);
    }
    size_t iLen = wcslen(lpszColumnHeader);
    m_lpszColumnHeader = (LPWSTR)malloc(sizeof(WCHAR) * (iLen + 1));
    if (m_lpszColumnHeader != NULL)
    {
      wcscpy(m_lpszColumnHeader, lpszColumnHeader);
    }
  }

  int  GetFormat() { return m_nFormat; }
  void SetFormat(int nFormat) { m_nFormat = nFormat; }
  int  GetWidth() { return m_nWidth; }
  void SetWidth(int nWidth) { m_nWidth = nWidth; }
  UINT GetColumnNum() { return m_nColumnNum; }
  void SetColumnNum(UINT nColumnNum) { m_nColumnNum = nColumnNum; }

protected:
  LPWSTR m_lpszColumnHeader;
  int   m_nFormat;
  int   m_nWidth;
  UINT  m_nColumnNum;
};


////////////////////////////////////////////////////////////////////////////////
// CColumnSet

class CColumnSet : public CList<CColumn*, CColumn*>
{
public :          
	CColumnSet(LPCWSTR lpszColumnID) 
	{
		// Make a copy of the column set ID
    size_t iLen = wcslen(lpszColumnID);
    m_lpszColumnID = (LPWSTR)malloc(sizeof(WCHAR) * (iLen + 1));
    if (m_lpszColumnID != NULL)
    {
      wcscpy(m_lpszColumnID, lpszColumnID);
    }
  }

	CColumnSet(LPCWSTR lpszColumnID, CList<CColumn*, CColumn*>&)
	{
		// Make a copy of the column set ID
    size_t iLen = wcslen(lpszColumnID);
    m_lpszColumnID = (LPWSTR)malloc(sizeof(WCHAR) * (iLen + 1));
    wcscpy(m_lpszColumnID, lpszColumnID);
  }

	~CColumnSet() 
	{
    while(!IsEmpty())
    {
      CColumn* pColumn = RemoveTail();
      delete pColumn;
    }
		free(m_lpszColumnID);
	}

  void AddColumn(LPCWSTR lpszHeader, int nFormat, int nWidth, UINT nCol)
  {
    CColumn* pNewColumn = new CColumn(lpszHeader, nFormat, nWidth, nCol);
    AddTail(pNewColumn);
  }

	LPCWSTR GetColumnID() { return (LPCWSTR)m_lpszColumnID; }

	UINT GetNumCols() { return static_cast<UINT>(GetCount()); }

private :
	LPWSTR m_lpszColumnID;
};

////////////////////////////////////////////////////////////////////////////////
// CColumnSetList

class CColumnSetList : public CList<CColumnSet*, CColumnSet*>
{
public :
	// Find the column set given a column set ID
	CColumnSet* FindColumnSet(LPCWSTR lpszColumnID)
	{
		POSITION pos = GetHeadPosition();
		while (pos != NULL)
		{
			CColumnSet* pTempSet = GetNext(pos);
			ASSERT(pTempSet != NULL);

			LPCWSTR lpszTempNodeID = pTempSet->GetColumnID();

			if (wcscmp(lpszTempNodeID, lpszColumnID) == 0)
			{
				return pTempSet;
			}
		}
		return NULL;
	}

	void RemoveAndDeleteAllColumnSets()
	{
		while (!IsEmpty())
		{
			CColumnSet* pTempSet = RemoveTail();
			delete pTempSet;
		}
	}
};

///////////////////////////////////////////////////////////////////////////////
// CComponentDataObject
// * this class contains the master tree data (i.e. the "document")
// * base class, have to derive from it


class CWatermarkInfoState; // fwd decl of private class

class CComponentDataObject:
  public IComponentData,
  public IExtendPropertySheet2,
	public IExtendContextMenu,
	public CPersistStreamImpl,
  public ISnapinHelp2,
  public IRequiredExtensions,
  public CComObjectRoot
{

BEGIN_COM_MAP(CComponentDataObject)
	COM_INTERFACE_ENTRY(IComponentData)
	COM_INTERFACE_ENTRY(IExtendPropertySheet2)
	COM_INTERFACE_ENTRY(IExtendContextMenu)
	COM_INTERFACE_ENTRY(IPersistStream)
  COM_INTERFACE_ENTRY(ISnapinHelp2)
  COM_INTERFACE_ENTRY(IRequiredExtensions)
END_COM_MAP()

#ifdef _DEBUG_REFCOUNT
	static unsigned int m_nOustandingObjects; // # of objects created
	int dbg_cRef;
    ULONG InternalAddRef()
    {
		++dbg_cRef;
		TRACE(_T("CComponentDataObject::InternalAddRef() refCount = %d\n"), dbg_cRef);
        return CComObjectRoot::InternalAddRef();
    }
    ULONG InternalRelease()
    {
		--dbg_cRef;
		TRACE(_T("CComponentDataObject::InternalRelease() refCount = %d\n"), dbg_cRef);
        return CComObjectRoot::InternalRelease();
    }
#endif // _DEBUG_REFCOUNT

	CComponentDataObject();
	virtual ~CComponentDataObject();
	HRESULT FinalConstruct();
	void FinalRelease();

public:
// IComponentData interface members
    STDMETHOD(Initialize)(LPUNKNOWN pUnknown);
    STDMETHOD(CreateComponent)(LPCOMPONENT* ppComponent) = 0; // must override
	STDMETHOD(Notify)(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param);
    STDMETHOD(Destroy)();
    STDMETHOD(QueryDataObject)(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject);
    STDMETHOD(GetDisplayInfo)(SCOPEDATAITEM* pScopeDataItem);
	STDMETHOD(CompareObjects)(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB);

// IExtendPropertySheet2 interface members
public:
    STDMETHOD(CreatePropertyPages)(LPPROPERTYSHEETCALLBACK lpProvider,
                        LONG_PTR handle,
                        LPDATAOBJECT lpIDataObject);
    STDMETHOD(QueryPagesFor)(LPDATAOBJECT lpDataObject);
    STDMETHOD(GetWatermarks)(LPDATAOBJECT lpDataObject, HBITMAP* lphWatermark, HBITMAP* lphHeader,
                                    HPALETTE* lphPalette, BOOL* pbStretch);

    HRESULT CreatePropertySheet(CTreeNode* pNode, HWND hWndParent, LPCWSTR lpszTitle);

public:

  //
  // IExtendContextMenu interface members
  //
	STDMETHOD(AddMenuItems)(LPDATAOBJECT pDataObject,
							LPCONTEXTMENUCALLBACK pCallbackUnknown,
							long *pInsertionAllowed);
	STDMETHOD(Command)(long nCommandID, LPDATAOBJECT pDataObject);
  
  //
  // IPersistStream interface members
  //
  STDMETHOD(IsDirty)();
	STDMETHOD(Load)(IStream __RPC_FAR *pStm);
  STDMETHOD(Save)(IStream __RPC_FAR *pStm, BOOL fClearDirty);

  //
  // ISnapinHelp2 interface members
  //
  STDMETHOD(GetHelpTopic)(LPOLESTR* lpCompiledHelpFile);
  STDMETHOD(GetLinkedTopics)(LPOLESTR* lpCompiledHelpFile);

  //
  // IRequiredExtensions interface members
  //
  STDMETHOD(EnableAllExtensions)() { return S_OK;} // load all always
  STDMETHOD(GetFirstExtension)(LPCLSID) { return S_FALSE;} // should not be called
  STDMETHOD(GetNextExtension)(LPCLSID) { return S_FALSE;} // should not be called

// virtual functions
protected:
	virtual HRESULT OnSetImages(LPIMAGELIST lpScopeImage) = 0; // must override
	virtual HRESULT OnExtensionExpand(LPDATAOBJECT, LPARAM)
		{ return E_FAIL;}
  virtual HRESULT OnRemoveChildren(LPDATAOBJECT lpDataObject, LPARAM arg);

// Notify handler declarations
private:
  HRESULT OnAdd(CTreeNode* cookie, LPARAM arg, LPARAM param);
  HRESULT OnRename(CInternalFormatCracker& ifc, LPARAM arg, LPARAM param);
  HRESULT OnExpand(CInternalFormatCracker& ifc, 
                   LPARAM arg, 
                   LPARAM param, 
                   BOOL bAsync = TRUE);
  HRESULT OnSelect(CInternalFormatCracker& ifc, LPARAM arg, LPARAM param);
  HRESULT OnContextMenu(CTreeNode* cookie, LPARAM arg, LPARAM param);
  HRESULT OnPropertyChange(LPARAM param, long fScopePane);

// Scope item creation helpers
private:
    void EnumerateScopePane(CTreeNode* cookie, 
                            HSCOPEITEM pParent, 
                            BOOL bAsync = TRUE);
    BOOL IsScopePaneNode(LPDATAOBJECT lpDataObject);

// Helpers

public:
	LPCONSOLE GetConsole() { return m_pConsole;}

	HRESULT OnDeleteVerbHandler(CInternalFormatCracker& ifc, CComponentObject* pComponentObject);
	HRESULT OnRefreshVerbHandler(CInternalFormatCracker& ifc);
	HRESULT OnHelpHandler(CInternalFormatCracker& ifc, CComponentObject* pComponentObject);

	HRESULT AddNode(CTreeNode* pNodeToAdd);
  HRESULT AddNodeSorted(CTreeNode* pNodeToAdd);
	HRESULT DeleteNode(CTreeNode* pNodeToDelete);
  HRESULT DeleteMultipleNodes(CNodeList* pNodeList);
	HRESULT ChangeNode(CTreeNode* pNodeToChange, long changeMask);
	HRESULT UpdateVerbState(CTreeNode* pNodeToChange);
	HRESULT RemoveAllChildren(CContainerNode* pNode);
	HRESULT RepaintSelectedFolderInResultPane();
	HRESULT RepaintResultPane(CContainerNode* pNode);
	HRESULT DeleteAllResultPaneItems(CContainerNode* pNode);
	HRESULT SortResultPane(CContainerNode* pContainerNode);
  HRESULT UpdateResultPaneView(CContainerNode* pContainerNode);

	CPropertyPageHolderTable* GetPropertyPageHolderTable() { return &m_PPHTable; }
	CRunningThreadTable* GetRunningThreadTable() { return &m_RTTable; }
	CNotificationSinkTable* GetNotificationSinkTable() { return &m_NSTable; }

  void WaitForThreadExitMessage(CMTContainerNode* pNode);

	CWatermarkInfo* SetWatermarkInfo(CWatermarkInfo* pWatermarkInfo);

	BOOL IsExtensionSnapin() { return m_bExtensionSnapin; }

  void SetLogFileName(PCWSTR pszLogName) { LOGFILE_NAME = pszLogName; }

protected:
	void SetExtensionSnapin(BOOL bExtensionSnapin)
			{ m_bExtensionSnapin = bExtensionSnapin;}

private:
	HRESULT UpdateAllViewsHelper(LPARAM data, LONG_PTR hint);
	void HandleStandardVerbsHelper(CComponentObject* pComponentObj,
									LPCONSOLEVERB pConsoleVerb,
									BOOL bScope, BOOL bSelect,
									LPDATAOBJECT lpDataObject);
protected:
	virtual HRESULT SnapinManagerCreatePropertyPages(LPPROPERTYSHEETCALLBACK,
										LONG_PTR) {return S_FALSE; }
	virtual BOOL HasPropertyPages(DATA_OBJECT_TYPES) {return FALSE; }
	
	virtual void OnInitialize();
	virtual void OnDestroy();

	// help handling
  virtual LPCWSTR GetHTMLHelpFileName() { return NULL; }
	BOOL WinHelp(LPCTSTR lpszHelpFileName, UINT uCommand, DWORD dwData);
	virtual void OnNodeContextHelp(CTreeNode*){}
  virtual void OnNodeContextHelp(CNodeList*) {}

public:
	virtual void OnDialogContextHelp(UINT, HELPINFO*) {}

  virtual BOOL IsMultiSelect() { return FALSE; }

// Scope pane helpers
public:

protected:
	HRESULT AddContainerNode(CContainerNode* pNodeToInsert, HSCOPEITEM pParentScopeItem);
	HRESULT AddContainerNodeSorted(CContainerNode* pNodeToInsert, HSCOPEITEM pParentScopeItem);

private:
	HRESULT DeleteContainerNode(CContainerNode* pNodeToDelete);
	HRESULT ChangeContainerNode(CContainerNode* pNodeToChange, long changeMask);
	void InitializeScopeDataItem(LPSCOPEDATAITEM pScopeDataItem, HSCOPEITEM pParentScopeItem, LPARAM lParam,
									  int nImage, int nOpenImage, BOOL bHasChildren);

// Column Set helpers
public:
	CColumnSetList* GetColumnSetList() { return &m_ColList; }

private:
	CColumnSetList m_ColList;

// Result pane helpers
public:

protected:

private:
	HRESULT AddLeafNode(CLeafNode* pNodeToAdd);
	HRESULT DeleteLeafNode(CLeafNode* pNodeToDelete);
	HRESULT ChangeLeafNode(CLeafNode* pNodeToChange, long changeMask);

// Attributes
private:
	LPCONSOLE					      m_pConsole;				// IConsole interface pointer
  LPCONSOLENAMESPACE2			  m_pConsoleNameSpace;    // IConsoleNameSpace interface pointer

	CPropertyPageHolderTable	m_PPHTable;				// property page holder table
	CRunningThreadTable			  m_RTTable;				// table of running MT nodes
	CNotificationSinkTable		m_NSTable;				// notification sink table, for advise in events

	CWatermarkInfoState*      m_pWatermarkInfoState;		// internal watermark info for Wizards
	BOOL						m_bExtensionSnapin;		// is this an extension?

// critical section (Serialization of calls to console)
public:
	void Lock() { ::EnterCriticalSection(&m_cs); }
	void Unlock() { ::LeaveCriticalSection(&m_cs); }
private:
	CRITICAL_SECTION			m_cs;					// general purpose critical section

// RootData
protected:
	CRootData* m_pRootData; // root node for the cache
	virtual CRootData* OnCreateRootData() = 0; // must override
public:
	CRootData* GetRootData() { ASSERT(m_pRootData != NULL); return m_pRootData;}

// Hidden window
private:
	CHiddenWnd m_hiddenWnd;		//	syncronization with background threads
  CTimerThread* m_pTimerThreadObj; // timer thread object
	HWND m_hWnd;				// thread safe HWND (gotten from the MFC CWnd)
public:
	BOOL PostExecMessage(CExecContext* pExec, LPARAM arg); // call from secondary thread
	BOOL PostForceEnumeration(CMTContainerNode* pContainerNode); // call from secondary thread
	HWND GetHiddenWindow() { ASSERT(m_hWnd != NULL); return m_hWnd;}

	BOOL OnCreateSheet(CPropertyPageHolderBase* pPPHolder, HWND hWnd);
	BOOL OnDeleteSheet(CPropertyPageHolderBase* pPPHolder, CTreeNode* pNode);

  HRESULT SetDescriptionBarText(CTreeNode* pTreeNode);

// Timer and Background Thread
public:
	BOOL StartTimerThread();
	void ShutDownTimerThread();
	BOOL PostMessageToTimerThread(UINT Msg, WPARAM wparam, LPARAM lParam);
	DWORD GetTimerInterval() { return m_dwTimerInterval;}
	
protected:
	DWORD m_dwTimerTime;	// sec

	// overrides that MUST be implemented
	virtual void OnTimer() { ASSERT(FALSE); }
	virtual void OnTimerThread(WPARAM, LPARAM) { ASSERT(FALSE); }
	virtual CTimerThread* OnCreateTimerThread() { return NULL; }
private:
	BOOL SetTimer();
	void KillTimer();
	void WaitForTimerThreadStartAck();
	DWORD m_nTimerThreadID;
	BOOL m_bTimerThreadStarted;
	DWORD m_dwTimerInterval; // sec

// friend class declarations
	friend class CDataObject; // for the GetRootData() member
	friend class CComponentObject; // for the FindObject() and OnPropertyChange() members
	friend class CHiddenWnd;
};


	
///////////////////////////////////////////////////////////////////////////////
// CComponentObject
// * this class is the view on the data contained in the "document"
// * base class, have to derive from it

class CComponentObject :
  public IComponent,
  public IExtendPropertySheet2,
	public IExtendContextMenu,
  public IExtendControlbar,
	public IResultDataCompareEx,
	public CComObjectRoot
{
public:

#ifdef _DEBUG_REFCOUNT
	static unsigned int m_nOustandingObjects; // # of objects created
	int dbg_cRef;
  ULONG InternalAddRef()
  {
		++dbg_cRef;
    return CComObjectRoot::InternalAddRef();
  }
  ULONG InternalRelease()
  {
		--dbg_cRef;
    return CComObjectRoot::InternalRelease();
  }
#endif // _DEBUG_REFCOUNT

	CComponentObject();
	virtual ~CComponentObject();

BEGIN_COM_MAP(CComponentObject)
	COM_INTERFACE_ENTRY(IComponent)
  COM_INTERFACE_ENTRY(IExtendPropertySheet2)
	COM_INTERFACE_ENTRY(IExtendContextMenu)
  COM_INTERFACE_ENTRY(IExtendControlbar)
  COM_INTERFACE_ENTRY(IResultDataCompareEx)
END_COM_MAP()

public:
  //
  // IComponent interface members
  //
  STDMETHOD(Initialize)(LPCONSOLE lpConsole);
  STDMETHOD(Notify)(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param);
  STDMETHOD(Destroy)(MMC_COOKIE cookie);
  STDMETHOD(GetResultViewType)(MMC_COOKIE cookie,  LPOLESTR* ppViewType, long* pViewOptions);
  STDMETHOD(QueryDataObject)(MMC_COOKIE cookie, DATA_OBJECT_TYPES type,
                      LPDATAOBJECT* ppDataObject);
  STDMETHOD(GetDisplayInfo)(LPRESULTDATAITEM  pResultDataItem);
	STDMETHOD(CompareObjects)( LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB);

  //
  // IExtendPropertySheet2 interface members
  //
  STDMETHOD(CreatePropertyPages)(LPPROPERTYSHEETCALLBACK lpProvider,
                                 LONG_PTR handle,
                                 LPDATAOBJECT lpIDataObject);
  STDMETHOD(QueryPagesFor)(LPDATAOBJECT lpDataObject);
  STDMETHOD(GetWatermarks)(LPDATAOBJECT lpDataObject, HBITMAP* lphWatermark, HBITMAP* lphHeader,
                                  HPALETTE* lphPalette, BOOL* pbStretch);

  //
  // IExtendContextMenu interface members
  //
	STDMETHOD(AddMenuItems)(LPDATAOBJECT pDataObject,
		            					LPCONTEXTMENUCALLBACK pCallbackUnknown,
							            long *pInsertionAllowed);
	STDMETHOD(Command)(long nCommandID, LPDATAOBJECT pDataObject);

  //
  // IExtendControlbar interface memebers
  //
  STDMETHOD(SetControlbar)(LPCONTROLBAR pControlbar);
  STDMETHOD(ControlbarNotify)(MMC_NOTIFY_TYPE type, LPARAM arg, LPARAM param);

  //
  // IResultDataCompare
  //
  STDMETHOD(Compare)(RDCOMPARE* prdc, int* pnResult);

// Helpers for CComponentObject
public:
  void SetIComponentData(CComponentDataObject* pData);
	void SetSelectedNode(CTreeNode* pSelectedNode, DATA_OBJECT_TYPES selectedType)
	{ m_pSelectedNode = pSelectedNode; m_selectedType = selectedType; }

// Notify event handlers
protected:
  HRESULT OnFolder(CTreeNode* cookie, LPARAM arg, LPARAM param);
  HRESULT OnShow(CInternalFormatCracker& ifc, LPARAM arg, LPARAM param);
  HRESULT OnActivate(CTreeNode* cookie, LPARAM arg, LPARAM param);
	HRESULT OnResultItemClk(CInternalFormatCracker& ifc, BOOL fDblClick);
  HRESULT OnMinimize(CInternalFormatCracker& ifc, LPARAM arg, LPARAM param);
  HRESULT OnPropertyChange(LPARAM param, long fScopePane);
  HRESULT OnUpdateView(LPDATAOBJECT lpDataObject, LPARAM data, LONG_PTR hint);
	HRESULT OnAddImages(CInternalFormatCracker& ifc, LPARAM arg, LPARAM param);
  HRESULT SetDescriptionBarText(CTreeNode* pTreeNode);

	// Added by JEFFJON : response to MMCN_COLUMNS_CHANGED
	HRESULT OnColumnsChanged(CInternalFormatCracker& ifc, LPARAM arg, LPARAM param);
	HRESULT OnColumnSortChanged(LPARAM arg, LPARAM param);

// Helper functions
protected:
  BOOL IsEnumerating(LPDATAOBJECT lpDataObject);
  void Construct();
  void LoadResources();
  virtual HRESULT InitializeHeaders(CContainerNode* pContainerNode) = 0;
  virtual HRESULT InitializeToolbar(IToolbar*) { return E_NOTIMPL; }

public:
	HRESULT ForceSort(UINT iCol, DWORD dwDirection);

protected:
  void EnumerateResultPane(CContainerNode* pContainerNode);

// Result pane helpers
  virtual HRESULT InitializeBitmaps(CTreeNode* cookie) = 0;
	void HandleStandardVerbs(BOOL bScope, BOOL bSelect, LPDATAOBJECT lpDataObject);
	HRESULT AddResultPaneItem(CLeafNode* pNodeToInsert);
	HRESULT DeleteResultPaneItem(CLeafNode* pNodeToDelete);
	HRESULT ChangeResultPaneItem(CLeafNode* pNodeToChange, LONG_PTR changeMask);
	HRESULT FindResultPaneItemID(CLeafNode* pNode, HRESULTITEM* pItemID);

// Interface pointers
protected:
  LPCONSOLE          m_pConsole;			// IConsole interface pointer
  LPHEADERCTRL        m_pHeader;			// Result pane's header control interface
  LPRESULTDATA        m_pResult;          // My interface pointer to the result pane
  LPIMAGELIST         m_pImageResult;     // My interface pointer to the result pane image list
  LPTOOLBAR           m_pToolbar;         // Toolbar for view
  LPCONTROLBAR        m_pControlbar;      // control bar to hold my tool bars
  LPCONSOLEVERB       m_pConsoleVerb;		// pointer the console verb

	LPCOMPONENTDATA     m_pComponentData;   // Pointer to the IComponentData this object belongs to

// state variables for this window
	CContainerNode*		m_pSelectedContainerNode;	// scope item selection (MMCN_SHOW)
	CTreeNode*			m_pSelectedNode;			// item selection (MMC_SELECT)
	DATA_OBJECT_TYPES	m_selectedType;				// matching m_pSelectedNode
};

inline void CComponentObject::SetIComponentData(CComponentDataObject* pData)
{
	TRACE(_T("CComponentObject::SetIComponentData()\n"));
    ASSERT(pData);
    ASSERT(m_pComponentData == NULL);
    LPUNKNOWN pUnk = pData->GetUnknown(); // does not addref
    HRESULT hr;

    hr = pUnk->QueryInterface(IID_IComponentData, reinterpret_cast<void**>(&m_pComponentData));

    ASSERT(hr == S_OK);
}


#define FREE_INTERNAL(pInternal) \
    ASSERT(pInternal != NULL); \
    do { if (pInternal != NULL) \
        GlobalFree(pInternal); } \
    while(0);

// This wrapper function required to make prefast shut up when we are 
// initializing a critical section in a constructor.

void ExceptionPropagatingInitializeCriticalSection(LPCRITICAL_SECTION critsec);

#endif //_COMPBASE_H