866 lines
19 KiB
C++
866 lines
19 KiB
C++
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
handlers.cpp
|
|
Implementation for non-threaded handlers and background
|
|
threaded handlers.
|
|
|
|
FILE HISTORY:
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "handlers.h"
|
|
|
|
/*---------------------------------------------------------------------------
|
|
ThreadHandler implementation
|
|
---------------------------------------------------------------------------*/
|
|
|
|
ThreadHandler::ThreadHandler()
|
|
: m_hThread(NULL),
|
|
m_hwndHidden(NULL),
|
|
m_cRef(1)
|
|
{
|
|
}
|
|
|
|
ThreadHandler::~ThreadHandler()
|
|
{
|
|
}
|
|
|
|
IMPLEMENT_ADDREF_RELEASE(ThreadHandler)
|
|
|
|
STDMETHODIMP ThreadHandler::QueryInterface(REFIID iid,void **ppv)
|
|
{
|
|
*ppv = 0;
|
|
if (iid == IID_IUnknown)
|
|
*ppv = (IUnknown *) this;
|
|
else if (iid == IID_ITFSThreadHandler)
|
|
*ppv = (ITFSThreadHandler *) this;
|
|
else
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
|
|
((IUnknown *) *ppv)->AddRef();
|
|
return hrOK;
|
|
}
|
|
|
|
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
ThreadHandler::StartBackgroundThread
|
|
-
|
|
Author:
|
|
---------------------------------------------------------------------------*/
|
|
BOOL
|
|
ThreadHandler::StartBackgroundThread(ITFSNode * pNode, HWND hWndHidden, ITFSQueryObject *pQuery)
|
|
{
|
|
CQueryObject * pquery = NULL;
|
|
HRESULT hr = hrOK;
|
|
BOOL bRes = TRUE;
|
|
CBackgroundThread * pThread;
|
|
|
|
// Store the node pointer
|
|
this->m_spNode.Set(pNode);
|
|
|
|
// Get the data for the hidden window
|
|
m_hwndHidden = hWndHidden;
|
|
Assert(m_hwndHidden);
|
|
Assert(::IsWindow(m_hwndHidden));
|
|
|
|
// First create the thread object (it hasn't started yet)
|
|
pThread = CreateThreadObject();
|
|
ASSERT(pThread != NULL);
|
|
|
|
// Now that we have everything allocated, register ourselves for msgs
|
|
m_uMsgBase = (INT)::SendMessage(m_hwndHidden, WM_HIDDENWND_REGISTER, TRUE, 0);
|
|
Assert(m_uMsgBase);
|
|
|
|
// Initialize and setup the query object
|
|
CORg( pQuery->Init(this, m_hwndHidden, m_uMsgBase) );
|
|
|
|
pThread->SetQueryObj(pQuery);
|
|
m_spQuery.Set(pQuery);
|
|
|
|
// phew, now start the thread
|
|
bRes = pThread->Start();
|
|
if (bRes)
|
|
{
|
|
if (pThread->m_hThread)
|
|
{
|
|
HANDLE hPseudohandle;
|
|
|
|
hPseudohandle = pThread->m_hThread;
|
|
BOOL bRet = DuplicateHandle(GetCurrentProcess(),
|
|
hPseudohandle,
|
|
GetCurrentProcess(),
|
|
&m_hThread,
|
|
SYNCHRONIZE,
|
|
FALSE,
|
|
DUPLICATE_SAME_ACCESS);
|
|
if (!bRet)
|
|
{
|
|
DWORD dwLastErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwLastErr);
|
|
}
|
|
|
|
// NOTE::: ericdav 10/23/97
|
|
// the thread is initially suspended so we can duplicate the handle
|
|
// if the query object exits very quickly, the background thread object
|
|
// may be destroyed before we can duplicate the handle.
|
|
pThread->ResumeThread();
|
|
}
|
|
else
|
|
{
|
|
m_hThread = NULL;
|
|
}
|
|
}
|
|
|
|
Error:
|
|
if (FHrFailed(hr) || (bRes == FALSE))
|
|
{
|
|
// Need to do some cleanup
|
|
|
|
ReleaseThreadHandler();
|
|
|
|
delete pThread;
|
|
|
|
bRes = FALSE;
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
ThreadHandler::ReleaseThreadHandler
|
|
-
|
|
Author:
|
|
---------------------------------------------------------------------------*/
|
|
void ThreadHandler::ReleaseThreadHandler()
|
|
{
|
|
if (m_hwndHidden)
|
|
{
|
|
Assert(m_uMsgBase);
|
|
::SendMessage(m_hwndHidden, WM_HIDDENWND_REGISTER, FALSE, m_uMsgBase);
|
|
m_hwndHidden = NULL;
|
|
m_uMsgBase = 0;
|
|
}
|
|
|
|
if (m_spQuery)
|
|
{
|
|
// Signal the thread to abort
|
|
m_spQuery->SetAbortEvent();
|
|
m_spQuery.Release();
|
|
}
|
|
|
|
if (m_spNode)
|
|
{
|
|
m_spNode.Release();
|
|
}
|
|
|
|
// Trace1("%X ReleaseThreadHandler() called\n", GetCurrentThreadId());
|
|
}
|
|
|
|
void ThreadHandler::WaitForThreadToExit()
|
|
{
|
|
//$ Review: kennt, should this be INFINITE?
|
|
// Ok, wait for 5 seconds, else just shutdown
|
|
// If we return, we can't do anything about the return value anyway
|
|
if (m_hThread)
|
|
{
|
|
if (WaitForSingleObjectEx(m_hThread, 10000, FALSE) != WAIT_OBJECT_0)
|
|
{
|
|
// Trace1("%X WaitForThreadToExit() Wait failed! \n", GetCurrentThreadId());
|
|
}
|
|
|
|
CloseHandle(m_hThread);
|
|
m_hThread = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
CBackgroundThread* ThreadHandler::CreateThreadObject()
|
|
{
|
|
return new CBackgroundThread; // override if need derived tipe of object
|
|
}
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CHandler);
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CHandler implementation
|
|
---------------------------------------------------------------------------*/
|
|
CHandler::CHandler(ITFSComponentData *pTFSCompData)
|
|
: CBaseHandler(pTFSCompData),
|
|
CBaseResultHandler(pTFSCompData),
|
|
m_cRef(1)
|
|
{
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CHandler);
|
|
|
|
m_nLockCount = 0;
|
|
m_nState = 0;
|
|
m_dwErr = 0;
|
|
|
|
m_bExpanded = FALSE;
|
|
}
|
|
|
|
CHandler::~CHandler()
|
|
{
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CHandler);
|
|
|
|
Assert(m_nLockCount == 0);
|
|
}
|
|
|
|
IMPLEMENT_ADDREF_RELEASE(CHandler)
|
|
|
|
STDMETHODIMP CHandler::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// Is the pointer bad?
|
|
if (ppv == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
// Place NULL in *ppv in case of failure
|
|
*ppv = NULL;
|
|
|
|
// This is the non-delegating IUnknown implementation
|
|
if (riid == IID_IUnknown)
|
|
*ppv = (LPVOID) this;
|
|
else if (riid == IID_ITFSResultHandler)
|
|
*ppv = (ITFSResultHandler *) this;
|
|
else if (riid == IID_ITFSNodeHandler)
|
|
*ppv = (ITFSNodeHandler *) this;
|
|
|
|
// If we're going to return an interface, AddRef it first
|
|
if (*ppv)
|
|
{
|
|
((LPUNKNOWN) *ppv)->AddRef();
|
|
return hrOK;
|
|
}
|
|
else
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
void
|
|
CHandler::Lock()
|
|
{
|
|
InterlockedIncrement(&m_nLockCount);
|
|
}
|
|
|
|
void
|
|
CHandler::Unlock()
|
|
{
|
|
InterlockedDecrement(&m_nLockCount);
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CHandler::UserNotify
|
|
Implememntation of ITFSNodeHandler::UserNotify
|
|
Author: KennT
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CHandler::UserNotify
|
|
(
|
|
ITFSNode * pNode,
|
|
LPARAM dwParam1,
|
|
LPARAM dwParam2
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
switch (dwParam1)
|
|
{
|
|
case TFS_MSG_CREATEPROPSHEET:
|
|
{
|
|
CPropertyPageHolderBase * pPropSheet =
|
|
reinterpret_cast<CPropertyPageHolderBase *>(dwParam2);
|
|
AddPropSheet(pPropSheet);
|
|
}
|
|
break;
|
|
|
|
case TFS_MSG_DELETEPROPSHEET:
|
|
{
|
|
CPropertyPageHolderBase * pPropSheet =
|
|
reinterpret_cast<CPropertyPageHolderBase *>(dwParam2);
|
|
RemovePropSheet(pPropSheet);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Panic1("Alert the troops!: invalid arg(%d) to CHandler::UserNotify\n",
|
|
dwParam1);
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CHandler::UserResultNotify
|
|
Implememntation of ITFSResultHandler::UserResultNotify
|
|
Author: KennT
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CHandler::UserResultNotify
|
|
(
|
|
ITFSNode * pNode,
|
|
LONG_PTR dwParam1,
|
|
LONG_PTR dwParam2
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
switch (dwParam1)
|
|
{
|
|
case TFS_MSG_CREATEPROPSHEET:
|
|
{
|
|
CPropertyPageHolderBase * pPropSheet =
|
|
reinterpret_cast<CPropertyPageHolderBase *>(dwParam2);
|
|
AddPropSheet(pPropSheet);
|
|
}
|
|
break;
|
|
|
|
case TFS_MSG_DELETEPROPSHEET:
|
|
{
|
|
CPropertyPageHolderBase * pPropSheet =
|
|
reinterpret_cast<CPropertyPageHolderBase *>(dwParam2);
|
|
RemovePropSheet(pPropSheet);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Panic1("Alert the troops!: invalid arg(%d) to CHandler::UserResultNotify\n",
|
|
dwParam1);
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CHandler::DestroyPropSheets
|
|
Implememntation of DestroyPropSheets
|
|
Author: KennT
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CHandler::DestroyPropSheets()
|
|
{
|
|
|
|
// Trace1("CHandler destructor - hander has %d prop sheets active\n", m_listPropSheets.GetCount());
|
|
while (!m_listPropSheets.IsEmpty())
|
|
{
|
|
// This handler still has some prop sheets up.
|
|
// Destroy them before we go away.
|
|
HANDLE hThread;
|
|
CPropertyPageHolderBase * pPropSheet;
|
|
|
|
pPropSheet = m_listPropSheets.RemoveHead();
|
|
hThread = pPropSheet->m_hThread;
|
|
pPropSheet->ForceDestroy();
|
|
|
|
DWORD dwReturn = WaitForSingleObject(hThread, 1000);
|
|
if (dwReturn == WAIT_OBJECT_0)
|
|
{
|
|
}
|
|
else
|
|
if (dwReturn == WAIT_TIMEOUT)
|
|
{
|
|
}
|
|
else
|
|
if (dwReturn == WAIT_ABANDONED)
|
|
{
|
|
}
|
|
else
|
|
if (dwReturn == WAIT_FAILED)
|
|
{
|
|
DWORD dwReturn = GetLastError();
|
|
}
|
|
|
|
CloseHandle(hThread);
|
|
}
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CHandler::HasPropSheets
|
|
Implememntation of CHandler::HasPropSheets
|
|
returns the # of prop sheets this node has open
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
int
|
|
CHandler::HasPropSheetsOpen()
|
|
{
|
|
return (int)m_listPropSheets.GetCount();
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CHandler::GetPropSheet
|
|
Implememntation of CHandler::GetPropSheet
|
|
returns the CPropPageHolderBase of the given index # (zero based)
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CHandler::GetOpenPropSheet
|
|
(
|
|
int nIndex,
|
|
CPropertyPageHolderBase ** ppPropSheet
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
if (ppPropSheet)
|
|
{
|
|
POSITION pos = m_listPropSheets.FindIndex(nIndex);
|
|
*ppPropSheet = m_listPropSheets.GetAt(pos);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CHandler::AddPropSheet
|
|
Implememntation of CHandler::AddPropSheet
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CHandler::AddPropSheet
|
|
(
|
|
CPropertyPageHolderBase * pPropSheet
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
m_listPropSheets.AddTail(pPropSheet);
|
|
// Trace1("CHandler::AddPropSheet - Added page holder %lx\n", pPropSheet);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CHandler::RemovePropSheet
|
|
Implememntation of CHandler::RemovePropSheet
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CHandler::RemovePropSheet
|
|
(
|
|
CPropertyPageHolderBase * pPropSheet
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
POSITION pos = m_listPropSheets.Find(pPropSheet);
|
|
if (pos)
|
|
{
|
|
m_listPropSheets.RemoveAt(pos);
|
|
}
|
|
// else
|
|
// {
|
|
// // prop sheet is not in the list
|
|
// Trace0("CHandler::RemovePropSheet - prop page holder not in list!\n");
|
|
// Assert(FALSE);
|
|
// }
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CHandler::OnRefresh
|
|
Default implementation for the refresh functionality
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CHandler::OnRefresh
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
/*
|
|
pNode->DeleteAllChildren();
|
|
Assert(GetChildCount() == 0);
|
|
|
|
OnEnumerate(pComponentData, pDataObject, bExtension);
|
|
|
|
AddCurrentChildrenToUI(pComponentData);
|
|
*/
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CHandler::BuildSelectedItemList
|
|
Builds a list of selected items in the result pane (can't do
|
|
multiple selection in the scope pane).
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CHandler::BuildSelectedItemList
|
|
(
|
|
ITFSComponent * pComponent,
|
|
CTFSNodeList * plistSelectedItems
|
|
)
|
|
{
|
|
RESULTDATAITEM resultDataItem;
|
|
HRESULT hr = hrOK;
|
|
|
|
ZeroMemory(&resultDataItem, sizeof(resultDataItem));
|
|
resultDataItem.nState = LVIS_SELECTED;
|
|
resultDataItem.nIndex = -1;
|
|
|
|
CTFSNodeList listSelectedNodes;
|
|
|
|
SPIResultData spResultData;
|
|
|
|
CORg ( pComponent->GetResultData(&spResultData) );
|
|
|
|
//
|
|
// Loop through and build a list of all selected items
|
|
//
|
|
while (TRUE)
|
|
{
|
|
//
|
|
// Gets the Selected items ID
|
|
//
|
|
resultDataItem.mask = RDI_STATE;
|
|
CORg (spResultData->GetNextItem(&resultDataItem));
|
|
if (hr == S_FALSE)
|
|
break;
|
|
|
|
//
|
|
// Now get the items lparam
|
|
//
|
|
//resultDataItem.mask = RDI_PARAM;
|
|
//CORg (spResultData->GetItem(&resultDataItem));
|
|
|
|
ITFSNode * pNode;
|
|
pNode = reinterpret_cast<ITFSNode *>(resultDataItem.lParam);
|
|
Assert(pNode != NULL);
|
|
|
|
pNode->AddRef();
|
|
|
|
plistSelectedItems->AddTail(pNode);
|
|
}
|
|
|
|
Error:
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CHandler::BuildVirtualSelectedItemList
|
|
Builds a list of selected items in the result pane (can't do
|
|
multiple selection in the scope pane).
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CHandler::BuildVirtualSelectedItemList
|
|
(
|
|
ITFSComponent * pComponent,
|
|
CVirtualIndexArray * parraySelectedItems
|
|
)
|
|
{
|
|
RESULTDATAITEM resultDataItem;
|
|
HRESULT hr = hrOK;
|
|
|
|
ZeroMemory(&resultDataItem, sizeof(resultDataItem));
|
|
resultDataItem.nState = LVIS_SELECTED;
|
|
resultDataItem.nIndex = -1;
|
|
|
|
SPIResultData spResultData;
|
|
|
|
CORg ( pComponent->GetResultData(&spResultData) );
|
|
|
|
//
|
|
// Loop through and build a list of all selected items
|
|
//
|
|
while (TRUE)
|
|
{
|
|
//
|
|
// Gets the Selected items ID
|
|
//
|
|
resultDataItem.mask = RDI_STATE;
|
|
CORg (spResultData->GetNextItem(&resultDataItem));
|
|
if (hr == S_FALSE)
|
|
break;
|
|
|
|
//
|
|
// The index of the selected item is in the resultDataItem struct
|
|
//
|
|
parraySelectedItems->Add(resultDataItem.nIndex);
|
|
}
|
|
|
|
Error:
|
|
return hr;
|
|
}
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CMTHandler);
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CMTHandler implementation
|
|
---------------------------------------------------------------------------*/
|
|
CMTHandler::CMTHandler(ITFSComponentData *pTFSCompData)
|
|
: CHandler(pTFSCompData),
|
|
m_cRef(1)
|
|
{
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CMTHandler);
|
|
}
|
|
|
|
CMTHandler::~CMTHandler()
|
|
{
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CMTHandler);
|
|
}
|
|
|
|
IMPLEMENT_ADDREF_RELEASE(CMTHandler)
|
|
|
|
STDMETHODIMP CMTHandler::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// Is the pointer bad?
|
|
if (ppv == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
// Place NULL in *ppv in case of failure
|
|
*ppv = NULL;
|
|
|
|
// This is the non-delegating IUnknown implementation
|
|
if (riid == IID_IUnknown)
|
|
*ppv = (LPVOID) this;
|
|
else if (riid == IID_ITFSResultHandler)
|
|
*ppv = (ITFSResultHandler *) this;
|
|
else if (riid == IID_ITFSNodeHandler)
|
|
*ppv = (ITFSNodeHandler *) this;
|
|
else if (riid == IID_ITFSThreadHandler)
|
|
*ppv = (ITFSThreadHandler *) this;
|
|
|
|
// If we're going to return an interface, AddRef it first
|
|
if (*ppv)
|
|
{
|
|
((LPUNKNOWN) *ppv)->AddRef();
|
|
return hrOK;
|
|
}
|
|
else
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CMTHandler::DestoryHandler
|
|
This gets called when the node for this handler is told to destroy.
|
|
Free up anything we may be holding onto here.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CMTHandler::DestroyHandler(ITFSNode *pNode)
|
|
{
|
|
ReleaseThreadHandler();
|
|
WaitForThreadToExit();
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CMTHandler::OnExpand
|
|
Default implementation for the refresh functionality
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CMTHandler::OnExpand
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
HRESULT hr = hrOK;
|
|
SPITFSNode spNode;
|
|
SPITFSNodeHandler spHandler;
|
|
ITFSQueryObject * pQuery = NULL;
|
|
|
|
if (m_bExpanded)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
Lock();
|
|
|
|
OnChangeState(pNode);
|
|
|
|
pQuery = OnCreateQuery(pNode);
|
|
Assert(pQuery);
|
|
|
|
// notify the UI to change icon, if needed
|
|
//Verify(SUCCEEDED(pComponentData->ChangeNode(this, SCOPE_PANE_CHANGE_ITEM_ICON)));
|
|
|
|
Verify(StartBackgroundThread(pNode, m_spTFSCompData->GetHiddenWnd(), pQuery));
|
|
|
|
pQuery->Release();
|
|
|
|
m_bExpanded = TRUE;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CMTHandler::OnRefresh
|
|
Default implementation for the refresh functionality
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CMTHandler::OnRefresh
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
if (m_bExpanded == FALSE)
|
|
{
|
|
// we cannot refresh/add items to a node that hasn't been expanded yet.
|
|
return hr;
|
|
}
|
|
|
|
BOOL bLocked = IsLocked();
|
|
if (bLocked)
|
|
{
|
|
// cannot do refresh on locked node, the UI should prevent this
|
|
return hr;
|
|
}
|
|
|
|
pNode->DeleteAllChildren(TRUE);
|
|
|
|
int nVisible, nTotal;
|
|
pNode->GetChildCount(&nVisible, &nTotal);
|
|
Assert(nVisible == 0);
|
|
Assert(nTotal == 0);
|
|
|
|
m_bExpanded = FALSE;
|
|
OnExpand(pNode, pDataObject, dwType, arg, param); // will spawn a thread to do enumeration
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CMTHandler::OnNotifyError
|
|
Implementation of ThreadHandler::OnNotifyError
|
|
Author: KennT
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CMTHandler::OnNotifyError
|
|
(
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
OnError((DWORD) lParam);
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CMTHandler::OnNotifyHaveData
|
|
-
|
|
Author: KennT
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CMTHandler::OnNotifyHaveData
|
|
(
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
// For these nodes, assume that the lParam is a CNodeQueryObject *
|
|
CNodeQueryObject * pQuery;
|
|
LPQUEUEDATA pQD;
|
|
ITFSNode * p;
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
pQuery = (CNodeQueryObject *) lParam;
|
|
Assert(pQuery);
|
|
|
|
if (pQuery)
|
|
pQuery->AddRef();
|
|
|
|
while (pQD = pQuery->RemoveFromQueue())
|
|
{
|
|
if (pQD->Type == QDATA_PNODE)
|
|
{
|
|
// this is the normal case. The handler just expects nodes
|
|
// to be handed back from the background thread
|
|
p = reinterpret_cast<ITFSNode *>(pQD->Data);
|
|
OnHaveData(m_spNode, p);
|
|
p->Release();
|
|
}
|
|
else
|
|
{
|
|
// custom case here. The user provided their own data
|
|
// type. Call the appropriate hander for this.
|
|
OnHaveData(m_spNode, pQD->Data, pQD->Type);
|
|
}
|
|
|
|
delete pQD;
|
|
}
|
|
|
|
if (pQuery)
|
|
pQuery->Release();
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CMTHandler::OnNotifyExiting
|
|
Implementation of ThreadHandler::OnNotifyExiting
|
|
Author: KennT
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CMTHandler::OnNotifyExiting
|
|
(
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
CNodeQueryObject * pQuery;
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
pQuery = (CNodeQueryObject *) lParam;
|
|
Assert(pQuery);
|
|
|
|
if (pQuery)
|
|
pQuery->AddRef();
|
|
|
|
OnChangeState(m_spNode);
|
|
|
|
ReleaseThreadHandler();
|
|
|
|
Unlock();
|
|
|
|
if (pQuery)
|
|
pQuery->Release();
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hrOK;
|
|
}
|
|
|