928 lines
24 KiB
C++
928 lines
24 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (C) 1997-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
ctvctl.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements TreeView OCX for Device Manager snapin
|
||
|
|
||
|
Author:
|
||
|
|
||
|
William Hsieh (williamh) created
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
// CTVCtl.cpp : Implementation of the CTVCtrl OLE control class.
|
||
|
#include "stdafx.h"
|
||
|
#include <afxcmn.h>
|
||
|
#include "ctv.h"
|
||
|
#include "CTVCtl.h"
|
||
|
#include "resource.h"
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
#define GET_X_LPARAM(lParam) (int)(short)LOWORD(lParam)
|
||
|
#define GET_Y_LPARAM(lParam) (int)(short)HIWORD(lParam)
|
||
|
|
||
|
IMPLEMENT_DYNCREATE(CTVCtrl, COleControl)
|
||
|
|
||
|
BEGIN_INTERFACE_MAP(CTVCtrl, COleControl)
|
||
|
INTERFACE_PART(CTVCtrl, IID_IDMTVOCX, DMTVOCX)
|
||
|
END_INTERFACE_MAP()
|
||
|
|
||
|
|
||
|
const IID IID_IDMTVOCX = {0x142525f2,0x59d8,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}};
|
||
|
const IID IID_ISnapinCallback = {0x8e0ba98a,0xd161,0x11d0,{0x83,0x53,0x00,0xa0,0xc9,0x06,0x40,0xbf}};
|
||
|
|
||
|
|
||
|
|
||
|
ULONG EXPORT CTVCtrl::XDMTVOCX::AddRef()
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->ExternalAddRef();
|
||
|
}
|
||
|
ULONG EXPORT CTVCtrl::XDMTVOCX::Release()
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->ExternalRelease();
|
||
|
}
|
||
|
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::QueryInterface(
|
||
|
REFIID iid,
|
||
|
void ** ppvObj
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->ExternalQueryInterface(&iid, ppvObj);
|
||
|
}
|
||
|
|
||
|
HTREEITEM EXPORT CTVCtrl::XDMTVOCX::InsertItem(
|
||
|
LPTV_INSERTSTRUCT pis
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->InsertItem(pis);
|
||
|
}
|
||
|
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::DeleteItem(
|
||
|
HTREEITEM hitem
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->DeleteItem(hitem);
|
||
|
}
|
||
|
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::DeleteAllItems(
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->DeleteAllItems();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HIMAGELIST EXPORT CTVCtrl::XDMTVOCX::SetImageList(
|
||
|
INT iImage,
|
||
|
HIMAGELIST himl
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->SetImageList(iImage, himl);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::SetItem(
|
||
|
TV_ITEM* pitem
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->SetItem(pitem);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::Expand(
|
||
|
UINT Flags,
|
||
|
HTREEITEM hitem
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->Expand(Flags, hitem);
|
||
|
}
|
||
|
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::SelectItem(
|
||
|
UINT Flags,
|
||
|
HTREEITEM hitem
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->SelectItem(Flags, hitem);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::SetStyle(
|
||
|
DWORD dwStyle
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->SetStyle(dwStyle);
|
||
|
}
|
||
|
|
||
|
HWND EXPORT CTVCtrl::XDMTVOCX::GetWindowHandle(
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->GetWindowHandle();
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::GetItem(
|
||
|
TV_ITEM* pti
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->GetItem(pti);
|
||
|
}
|
||
|
|
||
|
HTREEITEM EXPORT CTVCtrl::XDMTVOCX::GetNextItem(
|
||
|
UINT Flags,
|
||
|
HTREEITEM htiRef
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->GetNextItem(Flags, htiRef);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::SelectItem(
|
||
|
HTREEITEM hti
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->SelectItem(hti);
|
||
|
}
|
||
|
|
||
|
|
||
|
UINT EXPORT CTVCtrl::XDMTVOCX::GetCount(
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->GetCount();
|
||
|
}
|
||
|
|
||
|
HTREEITEM EXPORT CTVCtrl::XDMTVOCX::GetSelectedItem(
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->GetSelectedItem();
|
||
|
}
|
||
|
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::Connect(
|
||
|
IComponent* pIComponent,
|
||
|
MMC_COOKIE cookie
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->Connect(pIComponent, cookie);
|
||
|
}
|
||
|
HRESULT EXPORT CTVCtrl::XDMTVOCX::SetActiveConnection(
|
||
|
MMC_COOKIE cookie
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->SetActiveConnection(cookie);
|
||
|
}
|
||
|
MMC_COOKIE EXPORT CTVCtrl::XDMTVOCX::GetActiveConnection()
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->GetActiveConnection();
|
||
|
}
|
||
|
|
||
|
long EXPORT CTVCtrl::XDMTVOCX::SetRedraw(BOOL Redraw)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->SetRedraw(Redraw);
|
||
|
}
|
||
|
|
||
|
BOOL EXPORT CTVCtrl::XDMTVOCX::EnsureVisible(
|
||
|
HTREEITEM hitem
|
||
|
)
|
||
|
{
|
||
|
METHOD_PROLOGUE(CTVCtrl, DMTVOCX)
|
||
|
return pThis->EnsureVisible(hitem);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Message map
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CTVCtrl, COleControl)
|
||
|
//{{AFX_MSG_MAP(CTVCtrl)
|
||
|
ON_WM_DESTROY()
|
||
|
ON_WM_CONTEXTMENU()
|
||
|
//}}AFX_MSG_MAP
|
||
|
ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
|
||
|
ON_MESSAGE(OCM_NOTIFY, OnOcmNotify)
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Dispatch map
|
||
|
|
||
|
BEGIN_DISPATCH_MAP(CTVCtrl, COleControl)
|
||
|
//{{AFX_DISPATCH_MAP(CTVCtrl)
|
||
|
//}}AFX_DISPATCH_MAP
|
||
|
END_DISPATCH_MAP()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Event map
|
||
|
|
||
|
BEGIN_EVENT_MAP(CTVCtrl, COleControl)
|
||
|
//{{AFX_EVENT_MAP(CTVCtrl)
|
||
|
// NOTE - ClassWizard will add and remove event map entries
|
||
|
// DO NOT EDIT what you see in these blocks of generated code !
|
||
|
//}}AFX_EVENT_MAP
|
||
|
END_EVENT_MAP()
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Initialize class factory and guid
|
||
|
|
||
|
IMPLEMENT_OLECREATE_EX(CTVCtrl, "CTREEVIEW.CTreeViewCtrl.1",
|
||
|
0xcd6c7868, 0x5864, 0x11d0, 0xab, 0xf0, 0, 0x20, 0xaf, 0x6b, 0xb, 0x7a)
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Type library ID and version
|
||
|
|
||
|
IMPLEMENT_OLETYPELIB(CTVCtrl, _tlid, _wVerMajor, _wVerMinor)
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Interface IDs
|
||
|
|
||
|
const IID BASED_CODE IID_DTV =
|
||
|
{ 0xcd6c7866, 0x5864, 0x11d0, { 0xab, 0xf0, 0, 0x20, 0xaf, 0x6b, 0xb, 0x7a}};
|
||
|
const IID BASED_CODE IID_DTVEvents =
|
||
|
{ 0xcd6c7867, 0x5864, 0x11d0, { 0xab, 0xf0, 0, 0x20, 0xaf, 0x6b, 0xb, 0x7a}};
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Control type information
|
||
|
|
||
|
static const DWORD BASED_CODE _dwTVOleMisc =
|
||
|
OLEMISC_ACTIVATEWHENVISIBLE |
|
||
|
OLEMISC_SETCLIENTSITEFIRST |
|
||
|
OLEMISC_INSIDEOUT |
|
||
|
OLEMISC_CANTLINKINSIDE |
|
||
|
OLEMISC_RECOMPOSEONRESIZE;
|
||
|
|
||
|
IMPLEMENT_OLECTLTYPE(CTVCtrl, IDS_TV, _dwTVOleMisc)
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVCtrl::CTVCtrlFactory::UpdateRegistry -
|
||
|
// Adds or removes system registry entries for CTVCtrl
|
||
|
|
||
|
BOOL CTVCtrl::CTVCtrlFactory::UpdateRegistry(BOOL bRegister)
|
||
|
{
|
||
|
// TODO: Verify that your control follows apartment-model threading rules.
|
||
|
// Refer to MFC TechNote 64 for more information.
|
||
|
// If your control does not conform to the apartment-model rules, then
|
||
|
// you must modify the code below, changing the 6th parameter from
|
||
|
// afxRegApartmentThreading to 0.
|
||
|
|
||
|
if (bRegister)
|
||
|
return AfxOleRegisterControlClass(
|
||
|
AfxGetInstanceHandle(),
|
||
|
m_clsid,
|
||
|
m_lpszProgID,
|
||
|
IDS_TV,
|
||
|
IDB_TV,
|
||
|
afxRegApartmentThreading,
|
||
|
_dwTVOleMisc,
|
||
|
_tlid,
|
||
|
_wVerMajor,
|
||
|
_wVerMinor);
|
||
|
else
|
||
|
return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVCtrl::CTVCtrl - Constructor
|
||
|
|
||
|
CTVCtrl::CTVCtrl()
|
||
|
{
|
||
|
InitializeIIDs(&IID_DTV, &IID_DTVEvents);
|
||
|
|
||
|
m_nConnections = 0;
|
||
|
m_pIComponent = NULL;
|
||
|
m_pISnapinCallback = NULL;
|
||
|
m_Destroyed = FALSE;
|
||
|
// TODO: Initialize your control's instance data here.
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVCtrl::~CTVCtrl - Destructor
|
||
|
|
||
|
CTVCtrl::~CTVCtrl()
|
||
|
{
|
||
|
// TODO: Cleanup your control's instance data here.
|
||
|
|
||
|
if (m_pISnapinCallback)
|
||
|
m_pISnapinCallback->Release();
|
||
|
if (m_pIComponent)
|
||
|
m_pIComponent->Release();
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVCtrl::OnDraw - Drawing function
|
||
|
|
||
|
void CTVCtrl::OnDraw(
|
||
|
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
|
||
|
{
|
||
|
DoSuperclassPaint(pdc, rcBounds);
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVCtrl::DoPropExchange - Persistence support
|
||
|
|
||
|
void CTVCtrl::DoPropExchange(CPropExchange* pPX)
|
||
|
{
|
||
|
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
|
||
|
COleControl::DoPropExchange(pPX);
|
||
|
|
||
|
// TODO: Call PX_ functions for each persistent custom property.
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVCtrl::OnResetState - Reset control to default state
|
||
|
|
||
|
void CTVCtrl::OnResetState()
|
||
|
{
|
||
|
COleControl::OnResetState(); // Resets defaults found in DoPropExchange
|
||
|
|
||
|
// TODO: Reset any other control state here.
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVCtrl::PreCreateWindow - Modify parameters for CreateWindowEx
|
||
|
|
||
|
BOOL CTVCtrl::PreCreateWindow(CREATESTRUCT& cs)
|
||
|
{
|
||
|
cs.lpszClass = _T("SysTreeView32");
|
||
|
// Turn off WS_EX_NOPARENTNOTIFY style bit so that our parents
|
||
|
// receive mouse clicks on our window. I do not know why MFC
|
||
|
// fundation class turns this on for an OCX.
|
||
|
cs.dwExStyle &= ~(WS_EX_NOPARENTNOTIFY);
|
||
|
return COleControl::PreCreateWindow(cs);
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVCtrl::IsSubclassedControl - This is a subclassed control
|
||
|
|
||
|
BOOL CTVCtrl::IsSubclassedControl()
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVCtrl::OnOcmCommand - Handle command messages
|
||
|
|
||
|
LRESULT CTVCtrl::OnOcmCommand(WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
#ifdef _WIN32
|
||
|
WORD wNotifyCode = HIWORD(wParam);
|
||
|
#else
|
||
|
WORD wNotifyCode = HIWORD(lParam);
|
||
|
#endif
|
||
|
|
||
|
// TODO: Switch on wNotifyCode here.
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CTVCtrl message handlers
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////
|
||
|
///
|
||
|
/// Tree View functions
|
||
|
///
|
||
|
|
||
|
HRESULT
|
||
|
CTVCtrl::Connect(
|
||
|
IComponent* pIComponent,
|
||
|
MMC_COOKIE cookie
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if (0 == m_nConnections) {
|
||
|
ASSERT(NULL == m_pIComponent);
|
||
|
|
||
|
m_pIComponent = pIComponent;
|
||
|
m_pIComponent->AddRef();
|
||
|
hr = m_pIComponent->QueryInterface(IID_ISnapinCallback,
|
||
|
reinterpret_cast<void**>(&m_pISnapinCallback)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// A single snapin may have multiple nodes that uses us as result pane
|
||
|
// display media, therefore, we may be connected mutlple times.
|
||
|
// However, we get created only when MMC creates a new snapin instance.
|
||
|
// This means, every connection call must provide the same
|
||
|
// pIComponent and pConsole.
|
||
|
//
|
||
|
ASSERT(m_pIComponent == pIComponent);
|
||
|
|
||
|
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
m_nConnections++;
|
||
|
hr = SetActiveConnection(cookie);
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CTVCtrl::SetActiveConnection(
|
||
|
MMC_COOKIE cookie
|
||
|
)
|
||
|
{
|
||
|
m_ActiveCookie = cookie;
|
||
|
return S_OK;
|
||
|
}
|
||
|
MMC_COOKIE
|
||
|
CTVCtrl::GetActiveConnection()
|
||
|
{
|
||
|
return m_ActiveCookie;
|
||
|
}
|
||
|
|
||
|
HTREEITEM CTVCtrl::InsertItem(
|
||
|
LPTV_INSERTSTRUCT pis
|
||
|
)
|
||
|
{
|
||
|
return(HTREEITEM)SendMessage(TVM_INSERTITEM, 0, (LPARAM)pis);
|
||
|
}
|
||
|
|
||
|
HRESULT CTVCtrl::DeleteItem(
|
||
|
HTREEITEM hitem
|
||
|
)
|
||
|
{
|
||
|
if (SendMessage(TVM_DELETEITEM, 0, (LPARAM)hitem))
|
||
|
return S_OK;
|
||
|
else
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
HRESULT CTVCtrl::DeleteAllItems()
|
||
|
{
|
||
|
return DeleteItem((HTREEITEM)TVI_ROOT);
|
||
|
|
||
|
}
|
||
|
HIMAGELIST CTVCtrl::SetImageList(
|
||
|
INT iImage,
|
||
|
HIMAGELIST hmil
|
||
|
)
|
||
|
{
|
||
|
return(HIMAGELIST)SendMessage(TVM_SETIMAGELIST, (WPARAM)iImage, (LPARAM)hmil);
|
||
|
}
|
||
|
|
||
|
HRESULT CTVCtrl::SetItem(
|
||
|
TV_ITEM* pitem
|
||
|
)
|
||
|
{
|
||
|
if (SendMessage(TVM_SETITEM, 0, (LPARAM)pitem))
|
||
|
return S_OK;
|
||
|
else
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
HRESULT CTVCtrl::Expand(
|
||
|
UINT Flags,
|
||
|
HTREEITEM hitem
|
||
|
)
|
||
|
{
|
||
|
if (SendMessage(TVM_EXPAND, (WPARAM) Flags, (LPARAM)hitem))
|
||
|
return S_OK;
|
||
|
else
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
HRESULT CTVCtrl::SelectItem(
|
||
|
UINT Flags,
|
||
|
HTREEITEM hitem
|
||
|
)
|
||
|
{
|
||
|
if (SendMessage(TVM_SELECTITEM, (WPARAM)Flags, (LPARAM)hitem))
|
||
|
return S_OK;
|
||
|
else
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
HRESULT CTVCtrl::SetStyle(
|
||
|
DWORD dwStyle
|
||
|
)
|
||
|
{
|
||
|
if (ModifyStyle(0, dwStyle))
|
||
|
return S_OK;
|
||
|
else
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
HWND CTVCtrl::GetWindowHandle(
|
||
|
)
|
||
|
{
|
||
|
return m_hWnd;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CTVCtrl::GetItem(
|
||
|
TV_ITEM* pti
|
||
|
)
|
||
|
{
|
||
|
if (SendMessage(TVM_GETITEM, 0, (LPARAM)pti))
|
||
|
return S_OK;
|
||
|
else
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
}
|
||
|
|
||
|
HTREEITEM CTVCtrl::GetNextItem(
|
||
|
UINT Flags,
|
||
|
HTREEITEM htiRef
|
||
|
)
|
||
|
{
|
||
|
return(HTREEITEM) SendMessage(TVM_GETNEXTITEM, (WPARAM)Flags, (LPARAM)htiRef);
|
||
|
}
|
||
|
|
||
|
HRESULT CTVCtrl::SelectItem(
|
||
|
HTREEITEM hti
|
||
|
)
|
||
|
{
|
||
|
if (SendMessage(TVM_SELECTITEM, 0, (LPARAM) hti))
|
||
|
return S_OK;
|
||
|
|
||
|
else
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
UINT CTVCtrl::GetCount(
|
||
|
)
|
||
|
{
|
||
|
return(UINT)SendMessage(TVM_GETCOUNT, 0, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
HTREEITEM CTVCtrl::HitTest(
|
||
|
LONG x,
|
||
|
LONG y,
|
||
|
UINT* pFlags
|
||
|
)
|
||
|
{
|
||
|
POINT pt;
|
||
|
pt.x = x;
|
||
|
pt.y = y;
|
||
|
|
||
|
ScreenToClient(&pt);
|
||
|
|
||
|
TV_HITTESTINFO tvhti;
|
||
|
tvhti.pt = pt;
|
||
|
|
||
|
HTREEITEM hti = (HTREEITEM)SendMessage(TVM_HITTEST, 0, (LPARAM)&tvhti);
|
||
|
|
||
|
if (hti && pFlags)
|
||
|
*pFlags = tvhti.flags;
|
||
|
|
||
|
return hti;
|
||
|
}
|
||
|
HTREEITEM CTVCtrl::GetSelectedItem(
|
||
|
)
|
||
|
{
|
||
|
return(HTREEITEM)SendMessage(TVM_GETNEXTITEM, TVGN_CARET, 0);
|
||
|
}
|
||
|
|
||
|
HRESULT CTVCtrl::SetRedraw(
|
||
|
BOOL Redraw
|
||
|
)
|
||
|
{
|
||
|
if (Redraw)
|
||
|
Invalidate();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
BOOL CTVCtrl::EnsureVisible(
|
||
|
HTREEITEM hitem
|
||
|
)
|
||
|
{
|
||
|
return(BOOL)SendMessage(TVM_ENSUREVISIBLE, 0, (LPARAM)hitem);
|
||
|
}
|
||
|
|
||
|
LRESULT
|
||
|
CTVCtrl::OnOcmNotify(
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam
|
||
|
)
|
||
|
{
|
||
|
|
||
|
LPARAM param, arg;
|
||
|
MMC_COOKIE cookie = 0;
|
||
|
|
||
|
HRESULT hr = S_FALSE;
|
||
|
TV_NOTIFY_CODE NotifyCode;
|
||
|
TV_ITEM TI;
|
||
|
|
||
|
NotifyCode = TV_NOTIFY_CODE_UNKNOWN;
|
||
|
|
||
|
switch (((NMHDR*)lParam)->code) {
|
||
|
|
||
|
case NM_RCLICK:
|
||
|
case NM_RDBLCLK:
|
||
|
case NM_CLICK:
|
||
|
case NM_DBLCLK:
|
||
|
NotifyCode = DoMouseNotification(((NMHDR*)lParam)->code, &cookie,
|
||
|
&arg, ¶m);
|
||
|
break;
|
||
|
|
||
|
case TVN_KEYDOWN:
|
||
|
TI.hItem = GetSelectedItem();
|
||
|
TI.mask = TVIF_PARAM;
|
||
|
if (TI.hItem && SUCCEEDED(GetItem(&TI))) {
|
||
|
cookie = (MMC_COOKIE)TI.lParam;
|
||
|
NotifyCode = TV_NOTIFY_CODE_KEYDOWN;
|
||
|
param = ((TV_KEYDOWN*)lParam)->wVKey;
|
||
|
arg = (LPARAM)TI.hItem;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case NM_SETFOCUS:
|
||
|
TI.hItem = GetSelectedItem();
|
||
|
TI.mask = TVIF_PARAM;
|
||
|
if (TI.hItem && SUCCEEDED(GetItem(&TI))) {
|
||
|
cookie = (MMC_COOKIE)TI.lParam;
|
||
|
NotifyCode = TV_NOTIFY_CODE_FOCUSCHANGED;
|
||
|
param = 1;
|
||
|
arg = (LPARAM)TI.hItem;
|
||
|
}
|
||
|
break;
|
||
|
#if 0
|
||
|
|
||
|
case TVN_GETDISPINFOA:
|
||
|
case TVN_GETDISPINFOW:
|
||
|
TI.hItem = ((TV_DISPINFO*)lParam)->item.hItem;
|
||
|
TI.mask = TVIF_PARAM;
|
||
|
if (TI.hItem && SUCCEEDED(GetItem(&TI))) {
|
||
|
NotifyCode = TV_NOTIFY_CODE_GETDISPINFO;
|
||
|
arg = (LPARAM)TI.hItem;
|
||
|
cookie = (MMC_COOKIE)TI.lParam;
|
||
|
param = (LPARAM)&((TV_DISPINFO*)lParam)->item;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case TVN_SELCHANGINGA:
|
||
|
case TVN_SELCHANGINGW:
|
||
|
NotifyCode = TV_NOTIFY_CODE_SELCHANGING;
|
||
|
arg = (LPARAM)((NM_TREEVIEW*)lParam)->itemNew.hItem;
|
||
|
cookie = (MMC_COOKIE)((NM_TREEVIEW*)lParam)->itemNew.lParam;
|
||
|
param = (LPARAM)((NM_TREEVIEW*)lParam)->action;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case TVN_ITEMEXPANDINGA:
|
||
|
case TVN_ITEMEXPANDINGW:
|
||
|
NotifyCode = TV_NOTIFY_CODE_EXPANDING;
|
||
|
arg = (LPARAM)((NM_TREEVIEW*)lParam)->itemNew.hItem;
|
||
|
cookie = (MMC_COOKIE)((NM_TREEVIEW*)lParam)->itemNew.lParam;
|
||
|
param = (LPARAM)((NM_TREEVIEW*)lParam)->action;
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
case TVN_SELCHANGEDA:
|
||
|
case TVN_SELCHANGEDW:
|
||
|
NotifyCode = TV_NOTIFY_CODE_SELCHANGED;
|
||
|
arg = (LPARAM)((NM_TREEVIEW*)lParam)->itemNew.hItem;
|
||
|
cookie = (MMC_COOKIE)((NM_TREEVIEW*)lParam)->itemNew.lParam;
|
||
|
param = (LPARAM)((NM_TREEVIEW*)lParam)->action;
|
||
|
break;
|
||
|
|
||
|
case TVN_ITEMEXPANDEDA:
|
||
|
case TVN_ITEMEXPANDEDW:
|
||
|
NotifyCode = TV_NOTIFY_CODE_EXPANDED;
|
||
|
arg = (LPARAM)((NM_TREEVIEW*)lParam)->itemNew.hItem;
|
||
|
cookie = (MMC_COOKIE)((NM_TREEVIEW*)lParam)->itemNew.lParam;
|
||
|
param = (LPARAM)((NM_TREEVIEW*)lParam)->action;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
NotifyCode = TV_NOTIFY_CODE_UNKNOWN;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (TV_NOTIFY_CODE_UNKNOWN != NotifyCode && m_pISnapinCallback) {
|
||
|
|
||
|
hr = m_pISnapinCallback->tvNotify(*this, cookie, NotifyCode, arg, param);
|
||
|
|
||
|
if (S_FALSE == hr) {
|
||
|
//
|
||
|
// Translate RCLICK to context menu
|
||
|
//
|
||
|
if (TV_NOTIFY_CODE_RCLICK == NotifyCode) {
|
||
|
|
||
|
SendMessage(WM_CONTEXTMENU, (WPARAM)m_hWnd, GetMessagePos());
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Translate Shift-F10 or VK_APPS to context menu
|
||
|
//
|
||
|
else if (TV_NOTIFY_CODE_KEYDOWN == NotifyCode &&
|
||
|
(VK_F10 == param && GetKeyState(VK_SHIFT) < 0) ||
|
||
|
(VK_APPS == param)) {
|
||
|
|
||
|
RECT rect;
|
||
|
*((HTREEITEM*)&rect) = (HTREEITEM)arg;
|
||
|
|
||
|
if (SendMessage(TVM_GETITEMRECT, TRUE, (LPARAM)&rect)) {
|
||
|
|
||
|
POINT pt;
|
||
|
pt.x = (rect.left + rect.right) / 2;
|
||
|
pt.y = (rect.top + rect.bottom) / 2;
|
||
|
ClientToScreen(&pt);
|
||
|
SendMessage(WM_CONTEXTMENU, (WPARAM)m_hWnd, MAKELPARAM(pt.x, pt.y));
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// On a TVN_KEYDOWN we should always return 0, otherwise the treeview
|
||
|
// control gets confused.
|
||
|
//
|
||
|
if (((NMHDR*)lParam)->code == TVN_KEYDOWN) {
|
||
|
|
||
|
hr = S_FALSE;
|
||
|
}
|
||
|
|
||
|
ASSERT(S_OK == hr || S_FALSE == hr);
|
||
|
|
||
|
if (S_OK == hr) {
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
TV_NOTIFY_CODE
|
||
|
CTVCtrl::DoMouseNotification(
|
||
|
UINT Code,
|
||
|
MMC_COOKIE* pcookie,
|
||
|
LPARAM* parg,
|
||
|
LPARAM* pparam
|
||
|
)
|
||
|
{
|
||
|
DWORD MsgPos;
|
||
|
POINT point;
|
||
|
|
||
|
ASSERT(pparam && parg && pcookie);
|
||
|
*pparam = 0;
|
||
|
*parg = 0;
|
||
|
MsgPos = GetMessagePos();
|
||
|
point.x = GET_X_LPARAM(MsgPos);
|
||
|
point.y = GET_Y_LPARAM(MsgPos);
|
||
|
UINT htFlags;
|
||
|
HTREEITEM hti = HitTest(point.x, point.y, &htFlags);
|
||
|
|
||
|
TV_NOTIFY_CODE NotifyCode = TV_NOTIFY_CODE_UNKNOWN;
|
||
|
|
||
|
if (hti && (htFlags & TVHT_ONITEM)) {
|
||
|
|
||
|
TV_ITEM TI;
|
||
|
TI.hItem = hti;
|
||
|
TI.mask = TVIF_PARAM;
|
||
|
|
||
|
if (SUCCEEDED(GetItem(&TI))) {
|
||
|
|
||
|
switch (Code) {
|
||
|
|
||
|
case NM_RCLICK:
|
||
|
NotifyCode = TV_NOTIFY_CODE_RCLICK;
|
||
|
break;
|
||
|
|
||
|
case NM_RDBLCLK:
|
||
|
NotifyCode = TV_NOTIFY_CODE_RDBLCLK;
|
||
|
break;
|
||
|
|
||
|
case NM_CLICK:
|
||
|
NotifyCode = TV_NOTIFY_CODE_CLICK;
|
||
|
break;
|
||
|
|
||
|
case NM_DBLCLK:
|
||
|
NotifyCode = TV_NOTIFY_CODE_DBLCLK;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
NotifyCode = TV_NOTIFY_CODE_UNKNOWN;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (TV_NOTIFY_CODE_UNKNOWN != NotifyCode) {
|
||
|
|
||
|
*parg = (LPARAM)hti;
|
||
|
*pparam = htFlags;
|
||
|
*pcookie = (MMC_COOKIE)TI.lParam;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NotifyCode;
|
||
|
}
|
||
|
|
||
|
// OnDestroy may be called on two occasions:
|
||
|
// (1). We are the current active result pane window and MMC
|
||
|
// is destroying our parent window(MDI client). Note that
|
||
|
// if we are not the active result pane window, this function
|
||
|
// will not get called until (2).
|
||
|
// (2). our reference count has reached zero.
|
||
|
//
|
||
|
// When (1) happens, the snapin may be still holding reference to us
|
||
|
// thus, even though our window has been destroyed (2) still happens
|
||
|
// (unless PostNcDestory is done which MFC reset m_hWnd)and we end up
|
||
|
// destoying the window twice.
|
||
|
// So, we keep an eye on OnDestroy and do nothing after it has been called.
|
||
|
// We can not wait for PostNcDestroy because we have no idea when it would
|
||
|
// come.
|
||
|
//
|
||
|
void CTVCtrl::OnDestroy()
|
||
|
{
|
||
|
if (!m_Destroyed) {
|
||
|
COleControl::OnDestroy();
|
||
|
m_Destroyed = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CTVCtrl::OnContextMenu(CWnd* pWnd, CPoint point)
|
||
|
{
|
||
|
// TODO: Add your message handler code here
|
||
|
POINT pt = point;
|
||
|
UINT htFlags;
|
||
|
HTREEITEM hti = HitTest(pt.x, pt.y, &htFlags);
|
||
|
|
||
|
if (hti) {
|
||
|
TV_ITEM TI;
|
||
|
TI.hItem = hti;
|
||
|
TI.mask = TVIF_PARAM;
|
||
|
if (SUCCEEDED(GetItem(&TI))) {
|
||
|
m_pISnapinCallback->tvNotify(*this, (MMC_COOKIE)TI.lParam,
|
||
|
TV_NOTIFY_CODE_CONTEXTMENU,
|
||
|
(LPARAM)hti, (LPARAM)&point );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The upmost frame window may have its own accelerator table and may take
|
||
|
// away certain key combinations we really need.
|
||
|
BOOL CTVCtrl::PreTranslateMessage(MSG* pMsg)
|
||
|
{
|
||
|
// TODO: Add your specialized code here and/or call the base class
|
||
|
if (WM_KEYDOWN == pMsg->message &&
|
||
|
(VK_DELETE == pMsg->wParam ||
|
||
|
VK_RETURN == pMsg->wParam)) {
|
||
|
OnKeyDown((UINT)pMsg->wParam, LOWORD(pMsg->lParam), HIWORD(pMsg->lParam));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
else if (WM_SYSKEYDOWN == pMsg->message && VK_F10 == pMsg->wParam &&
|
||
|
GetKeyState(VK_SHIFT) < 0) {
|
||
|
// Shift-F10 will be translated to WM_CONTEXTMENU
|
||
|
OnSysKeyDown((UINT)pMsg->wParam, LOWORD(pMsg->lParam), HIWORD(pMsg->lParam));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return COleControl::PreTranslateMessage(pMsg);
|
||
|
}
|