base
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
// ShellContextMenu.cpp: implementation of the CShellContextMenu class.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ShellContextMenu.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
BOOL CShellContextMenu::InvokeCommand(UINT nCmdID)
|
||||
{
|
||||
if (!IsValid() || !IsCommandInRange(nCmdID))
|
||||
return FALSE;
|
||||
|
||||
CMINVOKECOMMANDINFO cmi;
|
||||
ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
|
||||
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
|
||||
cmi.hwnd = m_pOwner->GetSafeHwnd();
|
||||
cmi.lpVerb = MAKEINTRESOURCE(nCmdID - m_nCmdFirstID);
|
||||
cmi.nShow = SW_SHOWNORMAL;
|
||||
|
||||
return (NOERROR == m_pCtxMenu->InvokeCommand(&cmi));
|
||||
}
|
||||
|
||||
BOOL CShellContextMenu::FillMenu(CMenu *pMenu, UINT nStartIndex, UINT nCmdFirstID, UINT nCmdLastID, UINT nFlags)
|
||||
{
|
||||
if (!IsValid())
|
||||
return FALSE;
|
||||
|
||||
m_nCmdFirstID = nCmdFirstID;
|
||||
m_nCmdLastID = nCmdLastID;
|
||||
|
||||
UINT nDefID = pMenu->GetDefaultItem(GMDI_USEDISABLED, TRUE);
|
||||
|
||||
HRESULT hr = m_pCtxMenu->QueryContextMenu(pMenu->GetSafeHmenu(),
|
||||
nStartIndex, m_nCmdFirstID, m_nCmdLastID, nFlags);
|
||||
|
||||
if (nFlags & CMF_NODEFAULT)
|
||||
pMenu->SetDefaultItem(nDefID, TRUE);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
m_nCmdLastID = m_nCmdFirstID = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_nCmdLastID = m_nCmdFirstID + HRESULT_CODE(hr) - 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CShellContextMenu::HandleMenuMessage(UINT message, WPARAM wParam, LPARAM lParam, LRESULT *pLResult)
|
||||
{
|
||||
if (!IsValid())
|
||||
return FALSE;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_MENUSELECT:
|
||||
{
|
||||
// look for a parent frame, to update its status bar
|
||||
if (m_pOwner == NULL)
|
||||
return FALSE;
|
||||
CFrameWnd* pFrame = m_pOwner->GetTopLevelFrame();
|
||||
if (pFrame == NULL)
|
||||
return FALSE;
|
||||
|
||||
// provide status bar text
|
||||
*pLResult = 0;
|
||||
CString sStatusText;
|
||||
|
||||
UINT uItem = (UINT) LOWORD(wParam);
|
||||
UINT fuFlags = (UINT) HIWORD(wParam);
|
||||
|
||||
if (fuFlags == 0xFFFF) // menu was closed
|
||||
return FALSE;
|
||||
|
||||
// get the first item of submenu, if popup item
|
||||
if (fuFlags & MF_POPUP)
|
||||
uItem = ::GetMenuItemID(::GetSubMenu((HMENU)lParam, uItem), 0);
|
||||
|
||||
// check if it's a valid item
|
||||
if (!(fuFlags & MF_SEPARATOR)
|
||||
&& (uItem == 0 || !IsCommandInRange(uItem)))
|
||||
return FALSE;
|
||||
|
||||
// get description
|
||||
if (!(fuFlags & MF_SEPARATOR))
|
||||
GetCommandDescription(uItem, sStatusText);
|
||||
|
||||
// update status text, even if empty
|
||||
pFrame->SetMessageText(sStatusText);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_INITMENUPOPUP: // initialize sub-menus
|
||||
case WM_MEASUREITEM: // handle owner-draw items
|
||||
case WM_DRAWITEM:
|
||||
{
|
||||
// prepare result in case we handle the message
|
||||
// (if we don't, it will be discarded)
|
||||
*pLResult = TRUE;
|
||||
if (message == WM_INITMENUPOPUP)
|
||||
*pLResult = 0;
|
||||
|
||||
// check if it's a menu message
|
||||
if (message == WM_MEASUREITEM
|
||||
&& ((LPMEASUREITEMSTRUCT)lParam)->CtlType != ODT_MENU)
|
||||
return FALSE;
|
||||
if (message == WM_DRAWITEM
|
||||
&& ((LPDRAWITEMSTRUCT)lParam)->CtlType != ODT_MENU)
|
||||
return FALSE;
|
||||
|
||||
// these messages need interface version 2
|
||||
SContextMenu2Ptr pCtxMenu2(m_pCtxMenu);
|
||||
if (!pCtxMenu2.IsValid())
|
||||
return FALSE;
|
||||
|
||||
return (NOERROR == pCtxMenu2->HandleMenuMsg(message, wParam, lParam));
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CShellContextMenu::GetCommandDescription(UINT nCmdID, CString& rText)
|
||||
{
|
||||
if (!IsValid() || !IsCommandInRange(nCmdID))
|
||||
return FALSE;
|
||||
|
||||
// make a buffer large enough to hold either a Unicode or Ansi
|
||||
// string and initialize it to zeroes, because some shell
|
||||
// extensions return success even when they don't copy anything
|
||||
// to the buffer. Conversion is achieved by a CString object.
|
||||
WCHAR szHelpText[MAX_PATH];
|
||||
ZeroMemory(szHelpText, sizeof(WCHAR)*MAX_PATH);
|
||||
|
||||
// try with Unicode first (it seems Explorer does so)
|
||||
HRESULT hr = m_pCtxMenu->GetCommandString(nCmdID - m_nCmdFirstID,
|
||||
GCS_HELPTEXTW, NULL, (LPSTR)szHelpText, MAX_PATH);
|
||||
if (*(LPWSTR)szHelpText != 0) // buffer was used
|
||||
rText = (LPWSTR)szHelpText;
|
||||
else
|
||||
{
|
||||
// otherwise try with Ansi
|
||||
hr = m_pCtxMenu->GetCommandString(nCmdID - m_nCmdFirstID,
|
||||
GCS_HELPTEXTA, NULL, (LPSTR)szHelpText, MAX_PATH);
|
||||
if (*(LPSTR)szHelpText != 0) // buffer was used
|
||||
rText = (LPSTR)szHelpText;
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
BOOL CShellContextMenu::Create(IShellFolder *pParentFolder, LPCITEMIDLIST pidl)
|
||||
{
|
||||
m_pCtxMenu = SContextMenuPtr(pParentFolder, pidl);
|
||||
return m_pCtxMenu.IsValid();
|
||||
}
|
||||
|
||||
// a NULL pointer to unsubclass
|
||||
void CShellContextMenu::SetOwner(CWnd *pOwner)
|
||||
{
|
||||
if (m_pOwner != NULL || pOwner == NULL)
|
||||
UnsubclassOwner();
|
||||
|
||||
m_pOwner = pOwner;
|
||||
if (m_pOwner != NULL)
|
||||
SubclassOwner();
|
||||
}
|
||||
|
||||
const LPCTSTR SH_CTXMENU_OBJ = _T("ShellContextMenu");
|
||||
|
||||
void CShellContextMenu::SubclassOwner()
|
||||
{
|
||||
ASSERT(::IsWindow(m_pOwner->GetSafeHwnd()));
|
||||
|
||||
m_oldWndProc = (WNDPROC)::GetWindowLong(*m_pOwner, GWL_WNDPROC);
|
||||
::SetProp(*m_pOwner, SH_CTXMENU_OBJ, (HANDLE)this);
|
||||
::SetWindowLong(*m_pOwner, GWL_WNDPROC, (LONG)WindowProc);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK CShellContextMenu::WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CShellContextMenu *pThis =
|
||||
(CShellContextMenu*)::GetProp(hwnd, SH_CTXMENU_OBJ);
|
||||
|
||||
LRESULT lResult;
|
||||
if (pThis->HandleMenuMessage(message, wParam, lParam, &lResult))
|
||||
return lResult; // success, no default processing
|
||||
|
||||
if (message == WM_DESTROY)
|
||||
pThis->UnsubclassOwner();
|
||||
|
||||
return ::CallWindowProc(pThis->m_oldWndProc, hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void CShellContextMenu::UnsubclassOwner()
|
||||
{
|
||||
ASSERT(::IsWindow(m_pOwner->GetSafeHwnd()));
|
||||
|
||||
::RemoveProp(*m_pOwner, SH_CTXMENU_OBJ);
|
||||
::SetWindowLong(*m_pOwner, GWL_WNDPROC, (LONG)m_oldWndProc);
|
||||
m_pOwner = NULL;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// ShellContextMenu.h: interface for the CShellContextMenu class.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_SHELLCONTEXTMENU_H__B690453B_A97A_4D33_A6A5_0A0BDE5EB1A4__INCLUDED_)
|
||||
#define AFX_SHELLCONTEXTMENU_H__B690453B_A97A_4D33_A6A5_0A0BDE5EB1A4__INCLUDED_
|
||||
|
||||
#include <shlobj.h>
|
||||
#include "ShellWrappers.h"
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
class CShellContextMenu
|
||||
{
|
||||
protected:
|
||||
SContextMenuPtr m_pCtxMenu;
|
||||
UINT m_nCmdFirstID;
|
||||
UINT m_nCmdLastID;
|
||||
CWnd* m_pOwner; // NULL means no owner (no subclassing in act)
|
||||
WNDPROC m_oldWndProc;
|
||||
|
||||
public:
|
||||
BOOL Create(IShellFolder* pParentFolder, LPCITEMIDLIST pidl);
|
||||
CShellContextMenu();
|
||||
virtual ~CShellContextMenu();
|
||||
|
||||
BOOL InvokeCommand(UINT nCmdID);
|
||||
|
||||
BOOL FillMenu(CMenu *pMenu, UINT nStartIndex = 0, UINT nCmdFirstID = 1, UINT nCmdLastID = 0x7FFF, UINT nFlags = 0);
|
||||
|
||||
BOOL HandleMenuMessage(UINT message, WPARAM wParam, LPARAM lParam, LRESULT *pLResult);
|
||||
|
||||
BOOL GetCommandDescription(UINT nCmdID, CString& rText);
|
||||
|
||||
BOOL IsValid();
|
||||
|
||||
// commands
|
||||
void GetCommandRange(UINT& nCmdFirstID, UINT& nCmdLastID);
|
||||
BOOL IsCommandInRange(UINT nCmdID);
|
||||
|
||||
// owner
|
||||
void SetOwner(CWnd *pOwner);
|
||||
CWnd* GetOwner();
|
||||
|
||||
protected:
|
||||
void SubclassOwner();
|
||||
void UnsubclassOwner();
|
||||
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
};
|
||||
|
||||
// inline functions
|
||||
|
||||
inline CShellContextMenu::CShellContextMenu()
|
||||
{
|
||||
m_nCmdFirstID = 0;
|
||||
m_nCmdLastID = 0;
|
||||
m_pOwner = NULL;
|
||||
m_oldWndProc = NULL;
|
||||
}
|
||||
|
||||
inline CShellContextMenu::~CShellContextMenu()
|
||||
{
|
||||
if (m_pOwner != NULL)
|
||||
UnsubclassOwner();
|
||||
}
|
||||
|
||||
inline BOOL CShellContextMenu::IsValid()
|
||||
{
|
||||
return (m_pCtxMenu.IsValid());
|
||||
}
|
||||
|
||||
inline void CShellContextMenu::GetCommandRange(UINT &nCmdFirstID, UINT &nCmdLastID)
|
||||
{
|
||||
nCmdFirstID = m_nCmdFirstID;
|
||||
nCmdLastID = m_nCmdLastID;
|
||||
}
|
||||
|
||||
inline BOOL CShellContextMenu::IsCommandInRange(UINT nCmdID)
|
||||
{
|
||||
return IsValid() && (nCmdID >= m_nCmdFirstID && nCmdID <= m_nCmdLastID);
|
||||
}
|
||||
|
||||
inline CWnd* CShellContextMenu::GetOwner()
|
||||
{
|
||||
return m_pOwner;
|
||||
}
|
||||
|
||||
#endif // !defined(AFX_SHELLCONTEXTMENU_H__B690453B_A97A_4D33_A6A5_0A0BDE5EB1A4__INCLUDED_)
|
||||
@@ -0,0 +1,231 @@
|
||||
// ShellPidl.cpp: implementation of the CShellPidl class.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <afxpriv.h>
|
||||
#include "ShellPidl.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Static Functions
|
||||
|
||||
// does not include terminating zero
|
||||
// NULL objects get a zero length
|
||||
UINT CShellPidl::ILGetLength(LPCITEMIDLIST pidl)
|
||||
{
|
||||
if (pidl == NULL)
|
||||
return 0;
|
||||
|
||||
UINT length = 0, cb;
|
||||
do
|
||||
{
|
||||
cb = pidl->mkid.cb;
|
||||
pidl = (LPCITEMIDLIST)((LPBYTE)pidl + cb);
|
||||
length += cb;
|
||||
}
|
||||
while (cb != 0);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
LPCITEMIDLIST CShellPidl::ILGetNext(LPCITEMIDLIST pidl)
|
||||
{
|
||||
if (pidl == NULL)
|
||||
return NULL;
|
||||
|
||||
// Get the size of the specified item identifier.
|
||||
int cb = pidl->mkid.cb;
|
||||
|
||||
// If the size is zero, it is the end of the list.
|
||||
if (cb == 0)
|
||||
return NULL;
|
||||
|
||||
// Add cb to pidl (casting to increment by bytes).
|
||||
pidl = (LPCITEMIDLIST)((LPBYTE)pidl + cb);
|
||||
|
||||
// Return NULL if we reached the terminator, or a pidl otherwise.
|
||||
return (pidl->mkid.cb == 0) ? NULL : pidl;
|
||||
}
|
||||
|
||||
LPCITEMIDLIST CShellPidl::ILGetLast(LPCITEMIDLIST pidl)
|
||||
{
|
||||
LPCITEMIDLIST pidlLast = pidl, tmp = ILGetNext(pidl);
|
||||
while (tmp != NULL)
|
||||
{
|
||||
pidlLast = tmp;
|
||||
tmp = ILGetNext(tmp);
|
||||
}
|
||||
|
||||
return pidlLast;
|
||||
}
|
||||
|
||||
LPITEMIDLIST CShellPidl::ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
||||
{
|
||||
// check arguments
|
||||
if (pidl1 == NULL && pidl2 == NULL)
|
||||
return NULL;
|
||||
|
||||
// Get the size of the resulting item identifier list
|
||||
UINT cb1 = ILGetLength(pidl1);
|
||||
UINT cb2 = ILGetLength(pidl2);
|
||||
|
||||
// Allocate a new item identifier list
|
||||
SMallocPtr pMalloc;
|
||||
LPITEMIDLIST pidlNew = (LPITEMIDLIST)pMalloc->Alloc(cb1 + cb2 + sizeof(USHORT));
|
||||
LPITEMIDLIST pidlEnd = pidlNew;
|
||||
if (pidlNew != NULL)
|
||||
{
|
||||
// Copy the first item identifier list and terminating 0
|
||||
if (cb1 > 0)
|
||||
{
|
||||
CopyMemory(pidlEnd, pidl1, cb1);
|
||||
pidlEnd = (LPITEMIDLIST)((LPBYTE)pidlEnd + cb1);
|
||||
}
|
||||
|
||||
// Copy the second item identifier list and terminating 0
|
||||
if (cb2 > 0)
|
||||
{
|
||||
CopyMemory(pidlEnd, pidl2, cb2);
|
||||
pidlEnd = (LPITEMIDLIST)((LPBYTE)pidlEnd + cb2);
|
||||
}
|
||||
|
||||
// Append a terminating zero.
|
||||
pidlEnd->mkid.cb = 0;
|
||||
}
|
||||
return pidlNew;
|
||||
}
|
||||
|
||||
LPITEMIDLIST CShellPidl::ILCloneFirst(LPCITEMIDLIST pidl)
|
||||
{
|
||||
LPITEMIDLIST pidlNew = NULL;
|
||||
|
||||
if (pidl != NULL)
|
||||
{
|
||||
// Get the size of the first item identifier.
|
||||
int cb = pidl->mkid.cb;
|
||||
|
||||
// Allocate a new item identifier list.
|
||||
SMallocPtr pMalloc;
|
||||
pidlNew = (LPITEMIDLIST)pMalloc->Alloc(cb + sizeof(USHORT));
|
||||
|
||||
if (pidlNew != NULL)
|
||||
{
|
||||
// Copy the specified item identifier.
|
||||
CopyMemory(pidlNew, pidl, cb);
|
||||
|
||||
// Append a terminating zero.
|
||||
((LPITEMIDLIST)((LPBYTE)pidlNew + cb))->mkid.cb = 0;
|
||||
}
|
||||
}
|
||||
return pidlNew;
|
||||
}
|
||||
|
||||
LPITEMIDLIST CShellPidl::ILCloneParent(LPCITEMIDLIST pidl)
|
||||
{
|
||||
// Get the size of the parent item identifier.
|
||||
UINT cb = (UINT)ILGetLast(pidl) - (UINT)pidl;
|
||||
|
||||
SMallocPtr pMalloc;
|
||||
LPITEMIDLIST pidlNew = (LPITEMIDLIST)pMalloc->Alloc(cb + sizeof(USHORT));
|
||||
|
||||
if (pidlNew != NULL)
|
||||
{
|
||||
// Copy the specified item identifier.
|
||||
CopyMemory(pidlNew, pidl, cb);
|
||||
|
||||
// Append a terminating zero.
|
||||
((LPITEMIDLIST)((LPBYTE)pidlNew + cb))->mkid.cb = 0;
|
||||
}
|
||||
return pidlNew;
|
||||
}
|
||||
|
||||
LPITEMIDLIST CShellPidl::ILFromPath(LPCTSTR pszPath, HWND hOwner)
|
||||
{
|
||||
USES_CONVERSION;
|
||||
|
||||
ULONG count = 0;
|
||||
LPITEMIDLIST pidlNew = NULL;
|
||||
|
||||
SDesktopFolderPtr pDesktopFolder;
|
||||
pDesktopFolder->ParseDisplayName(hOwner, NULL,
|
||||
T2OLE(pszPath), &count, &pidlNew, NULL);
|
||||
|
||||
return pidlNew;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Member Functions
|
||||
|
||||
// debug
|
||||
|
||||
#ifdef _DEBUG
|
||||
void CShellPidl::Dump(CDumpContext& dc) const
|
||||
{
|
||||
dc << "addr = " << (void*)m_pObj << "\n";
|
||||
if (m_pObj == NULL)
|
||||
return;
|
||||
|
||||
dc << "[structure]\n";
|
||||
|
||||
LPCITEMIDLIST pidl = m_pObj;
|
||||
while (pidl != NULL)
|
||||
{
|
||||
dc << " " << pidl->mkid.cb;
|
||||
pidl = ILGetNext(pidl);
|
||||
}
|
||||
dc << "\n";
|
||||
}
|
||||
#endif //_DEBUG
|
||||
|
||||
int CShellPidl::CompareItemID(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
|
||||
{
|
||||
if(pidl1 == pidl2)
|
||||
return 0;
|
||||
if(!pidl1 || !pidl2)
|
||||
return -1;
|
||||
if(GetItemIDSize(pidl1) != GetItemIDSize(pidl2))
|
||||
return -1;
|
||||
return memcmp(pidl1,pidl2,GetItemIDSize(pidl1));
|
||||
}
|
||||
|
||||
|
||||
int CShellPidl::GetItemIDSize(LPCITEMIDLIST pidl)
|
||||
{
|
||||
if(!pidl)
|
||||
return 0;
|
||||
int nSize = 0;
|
||||
while(pidl -> mkid.cb)
|
||||
{
|
||||
nSize += pidl -> mkid.cb;
|
||||
pidl = (LPCITEMIDLIST)(((LPBYTE)pidl) + pidl -> mkid.cb);
|
||||
}
|
||||
return nSize;
|
||||
}
|
||||
|
||||
LPITEMIDLIST CShellPidl::GetObject()
|
||||
{
|
||||
return this -> m_pObj;
|
||||
}
|
||||
|
||||
int CShellPidl::CompareItemID(int nSpecialFolder)
|
||||
{
|
||||
CShellPidl compareID(nSpecialFolder);
|
||||
return CompareItemID(m_pObj, compareID);
|
||||
}
|
||||
|
||||
int CShellPidl::CompareItemID(LPITEMIDLIST cmpid)
|
||||
{
|
||||
return CompareItemID(m_pObj, cmpid);
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
// ShellPidl.h: interface for the CShellPidl class.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_SHELLPIDL_H__98F90381_3F3A_4DF6_948D_B9BB960E7A96__INCLUDED_)
|
||||
#define AFX_SHELLPIDL_H__98F90381_3F3A_4DF6_948D_B9BB960E7A96__INCLUDED_
|
||||
|
||||
#include <shlobj.h>
|
||||
#include "ShellWrappers.h"
|
||||
|
||||
#include <shlwapi.h>
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
class CShellPidl : public TSharedObject<ITEMIDLIST>
|
||||
{
|
||||
protected:
|
||||
static LPCITEMIDLIST ILGetLast(LPCITEMIDLIST pidl);
|
||||
// manage PIDLs
|
||||
static UINT ILGetLength(LPCITEMIDLIST pidl);
|
||||
static LPCITEMIDLIST ILGetNext(LPCITEMIDLIST pidl);
|
||||
static LPITEMIDLIST ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
|
||||
static LPITEMIDLIST ILClone(LPCITEMIDLIST pidl);
|
||||
static LPITEMIDLIST ILCloneFirst(LPCITEMIDLIST pidl);
|
||||
static LPITEMIDLIST ILCloneParent(LPCITEMIDLIST pidl);
|
||||
static LPITEMIDLIST ILFromPath(LPCTSTR pszPath, HWND hOwner = NULL);
|
||||
|
||||
public:
|
||||
int CompareItemID(LPITEMIDLIST);
|
||||
int CompareItemID(int);
|
||||
LPITEMIDLIST GetObject();
|
||||
int CompareItemID(LPCITEMIDLIST,LPCITEMIDLIST);
|
||||
CShellPidl(LPCTSTR pszPath, HWND hOwner = NULL);
|
||||
CShellPidl(UINT nSpecialFolder, HWND hOwner = NULL);
|
||||
CShellPidl(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlRel);
|
||||
CShellPidl(LPCITEMIDLIST pidl);
|
||||
CShellPidl();
|
||||
virtual ~CShellPidl();
|
||||
|
||||
int GetIconIndex(UINT uFlags = SHGFI_SMALLICON) const;
|
||||
BOOL IsRoot() const;
|
||||
|
||||
void Combine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
|
||||
void CloneLastParent(LPCITEMIDLIST pidl);
|
||||
void CloneLastChild(LPCITEMIDLIST pidl);
|
||||
void CloneFirstParent(LPCITEMIDLIST pidl);
|
||||
void CloneFirstChild(LPCITEMIDLIST pidl);
|
||||
|
||||
LPCITEMIDLIST GetFirstChild();
|
||||
LPCITEMIDLIST GetLastChild();
|
||||
|
||||
CString GetPath() const;
|
||||
|
||||
// debug support
|
||||
#ifdef _DEBUG
|
||||
void Dump(CDumpContext& dc) const;
|
||||
#endif //_DEBUG
|
||||
private:
|
||||
int GetItemIDSize(LPCITEMIDLIST);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Inline Member Functions
|
||||
|
||||
inline CShellPidl::CShellPidl()
|
||||
{
|
||||
}
|
||||
|
||||
inline CShellPidl::~CShellPidl()
|
||||
{
|
||||
}
|
||||
|
||||
inline CShellPidl::CShellPidl(LPCITEMIDLIST pidl)
|
||||
{
|
||||
m_pObj = ILClone(pidl);
|
||||
}
|
||||
|
||||
inline CShellPidl::CShellPidl(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlRel)
|
||||
{
|
||||
m_pObj = ILCombine(pidlParent, pidlRel);
|
||||
}
|
||||
|
||||
inline CShellPidl::CShellPidl(UINT nSpecialFolder, HWND hOwner)
|
||||
{
|
||||
SHGetSpecialFolderLocation(hOwner, nSpecialFolder, &m_pObj);
|
||||
}
|
||||
|
||||
inline CShellPidl::CShellPidl(LPCTSTR pszPath, HWND hOwner)
|
||||
{
|
||||
m_pObj = ILFromPath(pszPath, hOwner);
|
||||
}
|
||||
|
||||
inline BOOL CShellPidl::IsRoot() const
|
||||
{
|
||||
return (m_pObj != NULL) && (m_pObj->mkid.cb == 0);
|
||||
}
|
||||
|
||||
inline CString CShellPidl::GetPath() const
|
||||
{
|
||||
CString path;
|
||||
BOOL bSuccess = SHGetPathFromIDList(m_pObj, path.GetBuffer(MAX_PATH));
|
||||
path.ReleaseBuffer();
|
||||
if (!bSuccess)
|
||||
path.Empty();
|
||||
return path;
|
||||
}
|
||||
|
||||
inline int CShellPidl::GetIconIndex(UINT uFlags) const
|
||||
{
|
||||
SHFILEINFO sfi;
|
||||
ZeroMemory(&sfi, sizeof(SHFILEINFO));
|
||||
uFlags |= SHGFI_PIDL | SHGFI_SYSICONINDEX;
|
||||
SHGetFileInfo((LPCTSTR)m_pObj, 0, &sfi, sizeof(SHFILEINFO), uFlags);
|
||||
return sfi.iIcon;
|
||||
}
|
||||
|
||||
inline void CShellPidl::Combine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
||||
{
|
||||
Destroy();
|
||||
Attach(ILCombine(pidl1, pidl2));
|
||||
}
|
||||
|
||||
// get the first ancestor
|
||||
inline void CShellPidl::CloneFirstParent(LPCITEMIDLIST pidl)
|
||||
{
|
||||
Destroy();
|
||||
Attach(ILCloneFirst(pidl));
|
||||
}
|
||||
|
||||
inline void CShellPidl::CloneFirstChild(LPCITEMIDLIST pidl)
|
||||
{
|
||||
Destroy();
|
||||
Attach(ILClone(ILGetNext(pidl)));
|
||||
}
|
||||
|
||||
inline LPCITEMIDLIST CShellPidl::GetFirstChild()
|
||||
{
|
||||
return ILGetNext(m_pObj);
|
||||
}
|
||||
|
||||
// get the immediate parent
|
||||
inline void CShellPidl::CloneLastParent(LPCITEMIDLIST pidl)
|
||||
{
|
||||
Destroy();
|
||||
Attach(ILCloneParent(pidl));
|
||||
}
|
||||
|
||||
inline void CShellPidl::CloneLastChild(LPCITEMIDLIST pidl)
|
||||
{
|
||||
Destroy();
|
||||
Attach(ILClone(ILGetLast(pidl)));
|
||||
}
|
||||
|
||||
inline LPCITEMIDLIST CShellPidl::GetLastChild()
|
||||
{
|
||||
return ILGetLast(m_pObj);
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Inline Static Functions
|
||||
|
||||
inline LPITEMIDLIST CShellPidl::ILClone(LPCITEMIDLIST pidl)
|
||||
{
|
||||
return ILCombine(NULL, pidl);
|
||||
}
|
||||
|
||||
|
||||
#endif // !defined(AFX_SHELLPIDL_H__98F90381_3F3A_4DF6_948D_B9BB960E7A96__INCLUDED_)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// ShellString.cpp: implementation of the CShellString class.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ShellString.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CShellString::Destroy()
|
||||
{
|
||||
SMallocPtr pMalloc;
|
||||
if (m_str.uType == STRRET_WSTR && m_str.pOleStr != NULL)
|
||||
{
|
||||
pMalloc->Free(m_str.pOleStr);
|
||||
m_str.pOleStr = NULL;
|
||||
}
|
||||
ZeroMemory(&m_str, sizeof(STRRET));
|
||||
}
|
||||
|
||||
STRRET* CShellString::GetPointer(LPCITEMIDLIST pidl, UINT uDesiredType)
|
||||
{
|
||||
// reset the object
|
||||
Destroy();
|
||||
// init object
|
||||
m_pidl = pidl;
|
||||
ASSERT(m_pidl.IsValid());
|
||||
m_str.uType = uDesiredType;
|
||||
|
||||
return &m_str;
|
||||
}
|
||||
|
||||
CShellString::operator CString() const
|
||||
{
|
||||
CString string;
|
||||
switch (m_str.uType)
|
||||
{
|
||||
case STRRET_WSTR:
|
||||
string = m_str.pOleStr;
|
||||
break;
|
||||
case STRRET_CSTR:
|
||||
string = m_str.cStr;
|
||||
break;
|
||||
case STRRET_OFFSET:
|
||||
string = ((LPBYTE)(LPCITEMIDLIST)m_pidl + m_str.uOffset);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// ShellString.h: interface for the CShellString class.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_SHELLSTRING_H__1E9F6E1A_5076_4264_8747_713C53BAD6FE__INCLUDED_)
|
||||
#define AFX_SHELLSTRING_H__1E9F6E1A_5076_4264_8747_713C53BAD6FE__INCLUDED_
|
||||
|
||||
#include <shlobj.h>
|
||||
#include "ShellWrappers.h"
|
||||
#include "ShellPidl.h"
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
class CShellString
|
||||
{
|
||||
protected:
|
||||
CShellPidl m_pidl;
|
||||
STRRET m_str;
|
||||
|
||||
public:
|
||||
CShellString();
|
||||
virtual ~CShellString();
|
||||
|
||||
// obtain an empty object by pointer
|
||||
STRRET* GetPointer(LPCITEMIDLIST pidl, UINT uDesiredType = STRRET_WSTR);
|
||||
|
||||
operator CString() const;
|
||||
|
||||
protected:
|
||||
|
||||
void Destroy();
|
||||
};
|
||||
|
||||
// inline functions
|
||||
|
||||
inline CShellString::CShellString()
|
||||
{
|
||||
ZeroMemory(&m_str, sizeof(STRRET));
|
||||
}
|
||||
|
||||
inline CShellString::~CShellString()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
#endif // !defined(AFX_SHELLSTRING_H__1E9F6E1A_5076_4264_8747_713C53BAD6FE__INCLUDED_)
|
||||
@@ -0,0 +1,414 @@
|
||||
// ShellTreeCtrl.cpp : implementation file
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ShellTreeCtrl.h"
|
||||
#include ".\shelltreectrl.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define new DEBUG_NEW
|
||||
#undef THIS_FILE
|
||||
static char THIS_FILE[] = __FILE__;
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CShellTreeCtrl
|
||||
|
||||
CShellTreeCtrl::CShellTreeCtrl()
|
||||
{
|
||||
m_nCallbackMask = 0;
|
||||
}
|
||||
|
||||
CShellTreeCtrl::~CShellTreeCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CShellTreeCtrl, CWaitingTreeCtrl)
|
||||
//{{AFX_MSG_MAP(CShellTreeCtrl)
|
||||
ON_NOTIFY_REFLECT(TVN_DELETEITEM, OnDeleteItem)
|
||||
ON_NOTIFY_REFLECT(TVN_GETDISPINFO, OnGetDispInfo)
|
||||
//}}AFX_MSG_MAP
|
||||
// ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnTvnSelchanged)
|
||||
// ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnTvnItemexpanded)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CShellTreeCtrl message handlers
|
||||
|
||||
BOOL CShellTreeCtrl::PopulateItem(HTREEITEM hParent)
|
||||
{
|
||||
if (hParent == TVI_ROOT)
|
||||
{
|
||||
// not handled yet, do nothing in Release builds
|
||||
ASSERT(FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
TVITEMDATA* pData = (TVITEMDATA*)GetItemData(hParent);
|
||||
if (pData == NULL)
|
||||
return TRUE; // invalid shell item, ignore it silently
|
||||
|
||||
// get parent pidl
|
||||
ASSERT(pData->IsValid());
|
||||
CShellPidl& pidlParent = pData->pidlAbs;
|
||||
|
||||
if (!EnumFolderItems(hParent, pidlParent, pData->nFlags))
|
||||
return TRUE; // failed, won't try anymore!
|
||||
|
||||
// TODO: change this method!!
|
||||
|
||||
// do not check for children if parent is a removable media
|
||||
// (just try: if it's a filesystem object, it has a path)
|
||||
TCHAR path[MAX_PATH];
|
||||
if (SHGetPathFromIDList(pidlParent, path))
|
||||
{
|
||||
path[3] = 0;
|
||||
UINT type = GetDriveType(path);
|
||||
if (type != DRIVE_FIXED)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CShellTreeCtrl::PreSubclassWindow()
|
||||
{
|
||||
InitializeControl();
|
||||
|
||||
CWaitingTreeCtrl::PreSubclassWindow();
|
||||
}
|
||||
|
||||
void CShellTreeCtrl::InitializeControl()
|
||||
{
|
||||
// Attach to the system image list
|
||||
CShellPidl pidl((UINT)CSIDL_DESKTOP, m_hWnd);
|
||||
|
||||
SHFILEINFO sfi;
|
||||
ZeroMemory(&sfi, sizeof(SHFILEINFO));
|
||||
HIMAGELIST hSysImageList = (HIMAGELIST) SHGetFileInfo((LPCTSTR)(LPCITEMIDLIST)pidl,
|
||||
0, &sfi, sizeof(SHFILEINFO), SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
|
||||
|
||||
//TreeView_SetImageList(m_hWnd, hSysImageList, TVSIL_NORMAL);
|
||||
// postpone imagelist attaching
|
||||
// (seems it doesn't like a sendmessage when dynamically created
|
||||
// maybe because it has not received the WM_CREATE message yet?)
|
||||
PostMessage(TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hSysImageList);
|
||||
}
|
||||
|
||||
void CShellTreeCtrl::AddRootFolderContent(LPCITEMIDLIST pidlFolder, UINT nFlags)
|
||||
{
|
||||
if (pidlFolder == NULL)
|
||||
{
|
||||
CShellPidl pidl((UINT)CSIDL_DESKTOP, m_hWnd);
|
||||
InsertSubItem(TVI_ROOT, m_pDesktopFolder, NULL, pidl, nFlags);
|
||||
//HTREEITEM root = GetRootItem();
|
||||
//Expand(root, TVE_EXPAND);
|
||||
//AfxMessageBox(GetItemText(GetChildItem(root)));
|
||||
//PopulateItem(GetRootItem());
|
||||
//Expand(GetRootItem(), 1);
|
||||
return;
|
||||
}
|
||||
|
||||
SetRedraw(FALSE);
|
||||
EnumFolderItems(TVI_ROOT, pidlFolder, nFlags);
|
||||
SetRedraw(TRUE);
|
||||
}
|
||||
|
||||
|
||||
int CALLBACK CShellTreeCtrl::CompareFunc(LPARAM lParam1,
|
||||
LPARAM lParam2, LPARAM /*lParamSort*/)
|
||||
{
|
||||
TVITEMDATA* pData1 = (TVITEMDATA*)lParam1;
|
||||
TVITEMDATA* pData2 = (TVITEMDATA*)lParam2;
|
||||
ASSERT(pData1->IsValid() && pData2->IsValid());
|
||||
|
||||
// TODO: parent folders should be checked some day
|
||||
SShellFolderPtr pParentFolder = pData2->pParentFolder;
|
||||
|
||||
HRESULT hr = pParentFolder->CompareIDs(0,
|
||||
pData1->pidlAbs.GetLastChild(),
|
||||
pData2->pidlAbs.GetLastChild() );
|
||||
if (FAILED(hr))
|
||||
return 0; // error, don't sort
|
||||
|
||||
short ret = (short)HRESULT_CODE(hr);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
if (ret > 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CShellTreeCtrl::FillItem(TVITEM& item)
|
||||
{
|
||||
DWORD dwAttributes;
|
||||
|
||||
// get item data
|
||||
TVITEMDATA* pData = (TVITEMDATA*)item.lParam;
|
||||
ASSERT(pData->IsValid());
|
||||
|
||||
// get a relative pidl
|
||||
LPCITEMIDLIST pidlRel = pData->pidlAbs.GetLastChild();
|
||||
|
||||
if (item.mask & TVIF_TEXT)
|
||||
{
|
||||
// get display name
|
||||
CString sName;
|
||||
CShellString str;
|
||||
|
||||
if (pData->nFlags & STCF_SHOWPATH)
|
||||
{
|
||||
// use an absolute or relative path, if possible
|
||||
sName = pData->pidlAbs.GetPath();
|
||||
if (!sName.IsEmpty() && !(pData->nFlags & STCF_SHOWFULLNAME))
|
||||
sName = sName.Right(sName.ReverseFind(_T('\\')));
|
||||
}
|
||||
if (sName.IsEmpty())
|
||||
{
|
||||
// use a global or contextual displayname
|
||||
DWORD uDisplayFlags = SHGDN_INFOLDER;
|
||||
if (pData->nFlags & STCF_SHOWFULLNAME)
|
||||
uDisplayFlags = SHGDN_NORMAL;
|
||||
|
||||
// pData->pParentFolder->GetDisplayNameOf(pidlRel, uDisplayFlags
|
||||
// | SHGDN_INCLUDE_NONFILESYS, str.GetPointer(pidlRel));
|
||||
pData->pParentFolder->GetDisplayNameOf(pidlRel, uDisplayFlags, str.GetPointer(pidlRel));
|
||||
sName = str; // copy to string
|
||||
}
|
||||
// set item text
|
||||
lstrcpyn(item.pszText, (LPCTSTR)sName, item.cchTextMax);
|
||||
}
|
||||
|
||||
if (item.mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE))
|
||||
{
|
||||
// get some attributes
|
||||
dwAttributes = SFGAO_FOLDER | SFGAO_LINK | SFGAO_SHARE | SFGAO_GHOSTED;
|
||||
pData->pParentFolder->GetAttributesOf(1, &pidlRel, &dwAttributes);
|
||||
|
||||
// set correct icon
|
||||
if (dwAttributes & SFGAO_GHOSTED)
|
||||
{
|
||||
item.mask |= LVIF_STATE;
|
||||
item.stateMask |= LVIS_CUT;
|
||||
item.state |= LVIS_CUT;
|
||||
}
|
||||
if (dwAttributes & SFGAO_SHARE)
|
||||
{
|
||||
item.mask |= LVIF_STATE;
|
||||
item.state &= ~LVIS_OVERLAYMASK;
|
||||
item.state |= INDEXTOOVERLAYMASK(1);
|
||||
item.stateMask |= LVIS_OVERLAYMASK;
|
||||
}
|
||||
else if (dwAttributes & SFGAO_LINK)
|
||||
{
|
||||
item.mask |= LVIF_STATE;
|
||||
item.state &= ~LVIS_OVERLAYMASK;
|
||||
item.state |= INDEXTOOVERLAYMASK(2);
|
||||
item.stateMask |= LVIS_OVERLAYMASK;
|
||||
}
|
||||
if (item.mask & TVIF_IMAGE)
|
||||
{
|
||||
item.iImage = pData->pidlAbs.GetIconIndex(SHGFI_SMALLICON);
|
||||
item.iSelectedImage = item.iImage;
|
||||
}
|
||||
if ((item.mask & TVIF_SELECTEDIMAGE)
|
||||
&& (dwAttributes & SFGAO_FOLDER))
|
||||
{
|
||||
item.iSelectedImage = pData->pidlAbs.GetIconIndex(SHGFI_SMALLICON
|
||||
|SHGFI_OPENICON);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.mask & TVIF_CHILDREN)
|
||||
{
|
||||
// get some attributes
|
||||
dwAttributes = SFGAO_FOLDER;
|
||||
pData->pParentFolder->GetAttributesOf(1, &pidlRel, &dwAttributes);
|
||||
|
||||
// get children
|
||||
item.cChildren = 0;
|
||||
if (dwAttributes & SFGAO_FOLDER)
|
||||
{
|
||||
if (pData->nFlags & STCF_INCLUDEFILES)
|
||||
item.cChildren = 1;
|
||||
else if (dwAttributes & SFGAO_REMOVABLE)
|
||||
item.cChildren = 1;
|
||||
else
|
||||
{
|
||||
dwAttributes = SFGAO_HASSUBFOLDER;
|
||||
pData->pParentFolder->GetAttributesOf(1, &pidlRel, &dwAttributes);
|
||||
|
||||
item.cChildren = (dwAttributes & SFGAO_HASSUBFOLDER) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CShellTreeCtrl::OnDeleteItem(NMHDR* pNMHDR, LRESULT* pResult)
|
||||
{
|
||||
TVITEM& item = ((LPNMTREEVIEW)pNMHDR)->itemOld;
|
||||
|
||||
// free item data, ignore invalid shell items
|
||||
if (item.lParam != 0)
|
||||
delete (TVITEMDATA*)item.lParam;
|
||||
|
||||
*pResult = 0;
|
||||
}
|
||||
|
||||
void CShellTreeCtrl::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
|
||||
{
|
||||
TVITEM& item = ((LPNMTVDISPINFO)pNMHDR)->item;
|
||||
|
||||
// use the provided buffer for text
|
||||
FillItem(item);
|
||||
|
||||
*pResult = 0;
|
||||
}
|
||||
|
||||
CShellPidl CShellTreeCtrl::GetItemIDList(HTREEITEM hItem)
|
||||
{
|
||||
TVITEMDATA* pData = (TVITEMDATA*)GetItemData(hItem);
|
||||
if (pData != NULL)
|
||||
{
|
||||
ASSERT(pData->IsValid());
|
||||
return pData->pidlAbs;
|
||||
}
|
||||
return CShellPidl(); // invalid pidl
|
||||
}
|
||||
|
||||
void CShellTreeCtrl::InsertSubItem(HTREEITEM hParent, LPSHELLFOLDER pParentFolder, LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidl, UINT nFlags)
|
||||
{
|
||||
TVINSERTSTRUCT tvis;
|
||||
ZeroMemory(&tvis, sizeof(TVINSERTSTRUCT));
|
||||
tvis.hParent = hParent;
|
||||
tvis.hInsertAfter = TVI_LAST;
|
||||
|
||||
// provide a buffer for the item text
|
||||
TCHAR szText[MAX_PATH];
|
||||
tvis.item.pszText = szText;
|
||||
tvis.item.cchTextMax = MAX_PATH;
|
||||
|
||||
// used fields
|
||||
const UINT nTVIFlags = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE
|
||||
| TVIF_CHILDREN | TVIF_PARAM;
|
||||
|
||||
// prepare item data
|
||||
TVITEMDATA* pData = new TVITEMDATA;
|
||||
pData->pidlAbs.Combine(pidlParent, pidl);
|
||||
pData->pParentFolder = pParentFolder;
|
||||
pData->nFlags = nFlags;
|
||||
|
||||
// set item data
|
||||
ASSERT(pData->IsValid());
|
||||
tvis.item.lParam = (LPARAM)pData;
|
||||
|
||||
// fill with pidl, text, icons and children - handle callbacks
|
||||
tvis.item.mask = nTVIFlags & ~m_nCallbackMask;
|
||||
FillItem(tvis.item);
|
||||
|
||||
if (m_nCallbackMask & TVIF_IMAGE)
|
||||
tvis.item.iImage = I_IMAGECALLBACK;
|
||||
if (m_nCallbackMask & TVIF_SELECTEDIMAGE)
|
||||
tvis.item.iSelectedImage = I_IMAGECALLBACK;
|
||||
if (m_nCallbackMask & TVIF_TEXT)
|
||||
tvis.item.pszText = LPSTR_TEXTCALLBACK;
|
||||
if (m_nCallbackMask & TVIF_CHILDREN)
|
||||
tvis.item.cChildren = I_CHILDRENCALLBACK;
|
||||
tvis.item.mask |= nTVIFlags;
|
||||
|
||||
// then insert new item
|
||||
InsertItem(&tvis);
|
||||
}
|
||||
|
||||
void CShellTreeCtrl::AddRootItem(LPCITEMIDLIST pidlRoot, UINT nFlags)
|
||||
{
|
||||
// not needed if pParentFolder is an argument
|
||||
CShellPidl pidlParent;
|
||||
pidlParent.CloneLastParent(pidlRoot);
|
||||
SShellFolderPtr pParentFolder(m_pDesktopFolder, pidlParent);
|
||||
|
||||
InsertSubItem(TVI_ROOT, pParentFolder, NULL, pidlRoot, nFlags);
|
||||
}
|
||||
|
||||
BOOL CShellTreeCtrl::EnumFolderItems(HTREEITEM hParent, LPCITEMIDLIST pidlParent, UINT nFlags)
|
||||
{
|
||||
// get parent shell folder
|
||||
SShellFolderPtr pParentFolder(m_pDesktopFolder, pidlParent);
|
||||
|
||||
// not a valid folder object
|
||||
if (!pParentFolder.IsValid())
|
||||
return FALSE; // failed!
|
||||
|
||||
// enum child pidls
|
||||
SEnumIDListPtr pEnumIDList(pParentFolder, SHCONTF_FOLDERS
|
||||
| ((nFlags & STCF_INCLUDEFILES) ? SHCONTF_NONFOLDERS : 0)
|
||||
| ((nFlags & STCF_INCLUDEHIDDEN) ? SHCONTF_INCLUDEHIDDEN : 0), m_hWnd);
|
||||
|
||||
if (pEnumIDList.IsValid())
|
||||
{
|
||||
SetPopulationCount(0);
|
||||
|
||||
CShellPidl pidl;
|
||||
while (NOERROR == pEnumIDList->Next(1, pidl.GetPointer(), NULL))
|
||||
{
|
||||
// add child item, inherit some flags (inclusion)
|
||||
InsertSubItem(hParent, pParentFolder, pidlParent, pidl,
|
||||
nFlags & STCF_INCLUDEMASK);
|
||||
|
||||
// notify progress
|
||||
IncreasePopulation();
|
||||
}
|
||||
}
|
||||
|
||||
if (GetPopulationCount() > 0)
|
||||
{
|
||||
// sort items
|
||||
TVSORTCB tvscb;
|
||||
tvscb.hParent = hParent;
|
||||
tvscb.lpfnCompare = CompareFunc;
|
||||
// tvscb.lParam = 0; // not meaningful yet
|
||||
SortChildrenCB(&tvscb);
|
||||
}
|
||||
|
||||
// notify progress
|
||||
SetPopulationCount(1,1);
|
||||
|
||||
// success!
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CShellTreeCtrl::GetItemContextMenu(HTREEITEM hItem, CShellContextMenu& rCtxMenu)
|
||||
{
|
||||
TVITEMDATA* pData = (TVITEMDATA*)GetItemData(hItem);
|
||||
if (!pData->IsValid())
|
||||
return FALSE;
|
||||
|
||||
return rCtxMenu.Create(pData->pParentFolder,
|
||||
pData->pidlAbs.GetLastChild());
|
||||
}
|
||||
|
||||
void CShellTreeCtrl::SetCallbackMask(UINT nMask)
|
||||
{
|
||||
m_nCallbackMask = nMask &
|
||||
(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN);
|
||||
}
|
||||
|
||||
UINT CShellTreeCtrl::GetCallbackMask()
|
||||
{
|
||||
return m_nCallbackMask;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#if !defined(AFX_SHELLTREECTRL_H__98BDBB7B_E2C3_4145_A5D5_693274C6B99B__INCLUDED_)
|
||||
#define AFX_SHELLTREECTRL_H__98BDBB7B_E2C3_4145_A5D5_693274C6B99B__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
// ShellTreeCtrl.h : header file
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "WaitingTreeCtrl.h"
|
||||
#include "ShellPidl.h"
|
||||
#include "ShellString.h"
|
||||
#include "ShellContextMenu.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CShellTreeCtrl window
|
||||
|
||||
// item flags
|
||||
#define STCF_DEFAULT 0x00
|
||||
#define STCF_INCLUDEFILES 0x01
|
||||
#define STCF_INCLUDEHIDDEN 0x02
|
||||
#define STCF_INCLUDEALL (STCF_INCLUDEFILES|STCF_INCLUDEHIDDEN)
|
||||
#define STCF_INCLUDEMASK 0x0F
|
||||
#define STCF_SHOWFULLNAME 0x10
|
||||
#define STCF_SHOWPATH 0x20
|
||||
#define STCF_SHOWFULLPATH (STCF_SHOWPATH|STCF_SHOWFULLNAME)
|
||||
#define STCF_SHOWMASK 0xF0
|
||||
//#define STCF_DEFERLINKS 0x100
|
||||
|
||||
class CShellTreeCtrl : public CWaitingTreeCtrl
|
||||
{
|
||||
private:
|
||||
struct TVITEMDATA
|
||||
{
|
||||
SShellFolderPtr pParentFolder;
|
||||
CShellPidl pidlAbs;
|
||||
UINT nFlags;
|
||||
|
||||
BOOL IsValid()
|
||||
{
|
||||
return (this != NULL)
|
||||
&& pParentFolder.IsValid() && pidlAbs.IsValid();
|
||||
}
|
||||
};
|
||||
|
||||
SDesktopFolderPtr m_pDesktopFolder;
|
||||
UINT m_nCallbackMask;
|
||||
|
||||
private:
|
||||
// generic
|
||||
void InitializeControl();
|
||||
|
||||
BOOL EnumFolderItems(HTREEITEM hParent, LPCITEMIDLIST pidlParent, UINT nFlags);
|
||||
void InsertSubItem(HTREEITEM hParent, LPSHELLFOLDER pParentFolder, LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidl, UINT nFlags);
|
||||
void FillItem(TVITEM& item);
|
||||
|
||||
static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
|
||||
|
||||
protected:
|
||||
virtual BOOL PopulateItem(HTREEITEM hParent);
|
||||
|
||||
// Construction
|
||||
public:
|
||||
CShellTreeCtrl();
|
||||
virtual ~CShellTreeCtrl();
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
|
||||
// Operations
|
||||
public:
|
||||
|
||||
// Overrides
|
||||
// ClassWizard generated virtual function overrides
|
||||
//{{AFX_VIRTUAL(CShellTreeCtrl)
|
||||
protected:
|
||||
virtual void PreSubclassWindow();
|
||||
//}}AFX_VIRTUAL
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
UINT GetCallbackMask();
|
||||
void SetCallbackMask(UINT nMask);
|
||||
void AddRootItem(LPCITEMIDLIST pidl, UINT nFlags = STCF_DEFAULT);
|
||||
void AddRootFolderContent(LPCITEMIDLIST pidl, UINT nFlags = STCF_DEFAULT);
|
||||
CShellPidl GetItemIDList(HTREEITEM hItem);
|
||||
BOOL GetItemContextMenu(HTREEITEM hItem, CShellContextMenu &rCtxMenu);
|
||||
|
||||
// Generated message map functions
|
||||
protected:
|
||||
//{{AFX_MSG(CShellTreeCtrl)
|
||||
afx_msg void OnDeleteItem(NMHDR* pNMHDR, LRESULT* pResult);
|
||||
afx_msg void OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult);
|
||||
//}}AFX_MSG
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_SHELLTREECTRL_H__98BDBB7B_E2C3_4145_A5D5_693274C6B99B__INCLUDED_)
|
||||
@@ -0,0 +1,217 @@
|
||||
// SmartInterfacePtr.h: interface for the TInterfacePtr class.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_SHELLWRAPPERS_H__B0E1BBE7_A5D8_4A80_9A36_ED5553FE74F6__INCLUDED_)
|
||||
#define AFX_SHELLWRAPPERS_H__B0E1BBE7_A5D8_4A80_9A36_ED5553FE74F6__INCLUDED_
|
||||
|
||||
#include <shlobj.h>
|
||||
#include "SmartInterfacePtr.h"
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
class SMallocPtr : public TStaticInterfacePtr<IMalloc>
|
||||
{
|
||||
public:
|
||||
SMallocPtr()
|
||||
{
|
||||
if (m_pIface == NULL)
|
||||
SHGetMalloc(&m_pIface);
|
||||
else
|
||||
m_pIface->AddRef();
|
||||
}
|
||||
};
|
||||
|
||||
class SDesktopFolderPtr : public TStaticInterfacePtr<IShellFolder>
|
||||
{
|
||||
public:
|
||||
SDesktopFolderPtr()
|
||||
{
|
||||
if (m_pIface == NULL)
|
||||
SHGetDesktopFolder(&m_pIface);
|
||||
else
|
||||
m_pIface->AddRef();
|
||||
}
|
||||
};
|
||||
|
||||
class SShellFolderPtr : public TInterfacePtr<IShellFolder>
|
||||
{
|
||||
public:
|
||||
SShellFolderPtr() {}
|
||||
|
||||
SShellFolderPtr(IShellFolder* pFolder) { Copy(pFolder); }
|
||||
SShellFolderPtr(IShellFolder* pParentFolder, LPCITEMIDLIST pidlRel)
|
||||
{
|
||||
if (pidlRel != NULL && pidlRel->mkid.cb == 0)
|
||||
{
|
||||
// it's a root element, copy the parent folder
|
||||
Copy(pParentFolder);
|
||||
}
|
||||
else
|
||||
{
|
||||
pParentFolder->BindToObject(pidlRel,
|
||||
NULL, IID_IShellFolder, (LPVOID*)&m_pIface);
|
||||
}
|
||||
}
|
||||
|
||||
SShellFolderPtr(LPCITEMIDLIST pidlAbs)
|
||||
{
|
||||
SDesktopFolderPtr pDesktopFolder;
|
||||
if (pidlAbs != NULL && pidlAbs->mkid.cb == 0)
|
||||
{
|
||||
// it's a root element, copy the parent folder
|
||||
Copy(pDesktopFolder);
|
||||
}
|
||||
else
|
||||
{
|
||||
pDesktopFolder->BindToObject(pidlAbs,
|
||||
NULL, IID_IShellFolder, (LPVOID*)&m_pIface);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SEnumIDListPtr : public TInterfacePtr<IEnumIDList>
|
||||
{
|
||||
public:
|
||||
SEnumIDListPtr(IShellFolder* pParentFolder, UINT nFlags, HWND hOwner = NULL)
|
||||
{
|
||||
pParentFolder->EnumObjects(hOwner, nFlags, &m_pIface);
|
||||
}
|
||||
};
|
||||
|
||||
class SContextMenuPtr : public TInterfacePtr<IContextMenu>
|
||||
{
|
||||
public:
|
||||
SContextMenuPtr() {}
|
||||
|
||||
SContextMenuPtr(IShellFolder* pParentFolder, LPCITEMIDLIST pidlRel, HWND hOwner = NULL)
|
||||
{
|
||||
pParentFolder->GetUIObjectOf(hOwner, 1, &pidlRel,
|
||||
IID_IContextMenu, NULL, (LPVOID*)&m_pIface);
|
||||
}
|
||||
};
|
||||
|
||||
class SContextMenu2Ptr : public TInterfacePtr<IContextMenu2>
|
||||
{
|
||||
public:
|
||||
SContextMenu2Ptr(IContextMenu* pIface)
|
||||
{
|
||||
if (pIface != NULL)
|
||||
pIface->QueryInterface(IID_IContextMenu2, (LPVOID*)&m_pIface);
|
||||
}
|
||||
};
|
||||
|
||||
// templates
|
||||
|
||||
template <class TYPE>
|
||||
class TSharedObject
|
||||
{
|
||||
public:
|
||||
~TSharedObject()
|
||||
{ Destroy(); }
|
||||
|
||||
protected:
|
||||
TYPE* m_pObj;
|
||||
|
||||
TSharedObject()
|
||||
{ m_pObj = NULL; }
|
||||
|
||||
TSharedObject(const TSharedObject& shobj)
|
||||
{ Copy(shobj); }
|
||||
|
||||
void Copy(const TSharedObject& shobj);
|
||||
|
||||
public:
|
||||
operator const TYPE * () const
|
||||
{ return m_pObj; }
|
||||
|
||||
const TSharedObject& operator = (const TSharedObject& shobj)
|
||||
{
|
||||
Destroy();
|
||||
Copy(shobj);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOL IsValid() const
|
||||
{ return m_pObj != NULL; }
|
||||
|
||||
void Attach(TYPE* pObj)
|
||||
{
|
||||
ASSERT(m_pObj == NULL); // can't attach two times!
|
||||
m_pObj = pObj;
|
||||
}
|
||||
|
||||
TYPE* Detach()
|
||||
{
|
||||
TYPE* ret = m_pObj;
|
||||
m_pObj = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// obtain a void object by pointer
|
||||
TYPE** GetPointer()
|
||||
{
|
||||
Destroy();
|
||||
return &m_pObj;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
void DumpRaw(CDumpContext& dc) const
|
||||
{
|
||||
dc << "addr = " << (void*)m_pObj << "\n";
|
||||
if (m_pObj == NULL)
|
||||
return;
|
||||
|
||||
SMallocPtr pMalloc;
|
||||
ULONG size = pMalloc->GetSize((void*)m_pObj);
|
||||
cd << "[hex dump]\n";
|
||||
dc.HexDump(".", (BYTE*)m_pObj, (int)size, 16);
|
||||
dc << "\n";
|
||||
}
|
||||
#endif //_DEBUG
|
||||
|
||||
protected:
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
SMallocPtr pMalloc;
|
||||
pMalloc->Free(Detach());
|
||||
}
|
||||
};
|
||||
|
||||
template <class TYPE>
|
||||
void TSharedObject<TYPE>::Copy(const TSharedObject& shobj)
|
||||
{
|
||||
m_pObj = NULL;
|
||||
if (shobj.m_pObj == NULL)
|
||||
return;
|
||||
|
||||
// obj to copy must have been allocated this way
|
||||
SMallocPtr pMalloc;
|
||||
ULONG size = (ULONG)pMalloc->GetSize((void*)shobj.m_pObj);
|
||||
ASSERT(size > 0);
|
||||
|
||||
if (shobj.m_pObj != NULL)
|
||||
{
|
||||
m_pObj = (TYPE*)pMalloc->Alloc(size);
|
||||
CopyMemory(m_pObj, shobj.m_pObj, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //!defined(AFX_SHELLWRAPPERS_H__B0E1BBE7_A5D8_4A80_9A36_ED5553FE74F6__INCLUDED_)
|
||||
@@ -0,0 +1,126 @@
|
||||
// SmartInterfacePtr.h: interface for the TInterfacePtr class.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_SMARTINTERFACEPTR_H__A0E1BBE7_A5D8_4A80_9A36_ED5553FE74F6__INCLUDED_)
|
||||
#define AFX_SMARTINTERFACEPTR_H__A0E1BBE7_A5D8_4A80_9A36_ED5553FE74F6__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
template <class TYPE>
|
||||
class TInterfacePtr
|
||||
{
|
||||
public:
|
||||
~TInterfacePtr()
|
||||
{ Free(); }
|
||||
|
||||
BOOL IsValid() const
|
||||
{ return m_pIface != NULL; }
|
||||
|
||||
TYPE * operator -> ()
|
||||
{ return m_pIface; }
|
||||
|
||||
const TYPE * operator -> () const
|
||||
{ return m_pIface; }
|
||||
|
||||
operator TYPE * ()
|
||||
{ return m_pIface; }
|
||||
|
||||
protected:
|
||||
TYPE * m_pIface;
|
||||
|
||||
// must derive from this class
|
||||
TInterfacePtr()
|
||||
{ m_pIface = NULL; }
|
||||
|
||||
TInterfacePtr(const TInterfacePtr& obj)
|
||||
{ Copy(obj.m_pIface); }
|
||||
|
||||
const TInterfacePtr& operator = (const TInterfacePtr& obj)
|
||||
{
|
||||
Free();
|
||||
Copy(obj.m_pIface);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Copy(TYPE * pIface);
|
||||
void Free();
|
||||
};
|
||||
|
||||
template <class TYPE>
|
||||
inline void TInterfacePtr<TYPE>::Copy(TYPE * pIface)
|
||||
{
|
||||
m_pIface = pIface;
|
||||
if (m_pIface != NULL)
|
||||
m_pIface->AddRef();
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline void TInterfacePtr<TYPE>::Free()
|
||||
{
|
||||
if (m_pIface != NULL)
|
||||
{
|
||||
m_pIface->Release();
|
||||
m_pIface = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// static storage
|
||||
|
||||
template <class TYPE>
|
||||
class TStaticInterfacePtr
|
||||
{
|
||||
public:
|
||||
~TStaticInterfacePtr()
|
||||
{ Free(); }
|
||||
|
||||
BOOL IsValid() const
|
||||
{ return m_pIface != NULL; }
|
||||
|
||||
TYPE * operator -> ()
|
||||
{ return m_pIface; }
|
||||
|
||||
const TYPE * operator -> () const
|
||||
{ return m_pIface; }
|
||||
|
||||
operator TYPE * ()
|
||||
{ return m_pIface; }
|
||||
|
||||
protected:
|
||||
static TYPE * m_pIface;
|
||||
|
||||
TStaticInterfacePtr() {}
|
||||
// cannot copy - use another instance
|
||||
TStaticInterfacePtr(const TStaticInterfacePtr&) {}
|
||||
const TStaticInterfacePtr& operator = (const TStaticInterfacePtr&) {}
|
||||
|
||||
void Free();
|
||||
};
|
||||
|
||||
template <class TYPE>
|
||||
TYPE * TStaticInterfacePtr<TYPE>::m_pIface = NULL;
|
||||
|
||||
template <class TYPE>
|
||||
inline void TStaticInterfacePtr<TYPE>::Free()
|
||||
{
|
||||
if (m_pIface != NULL)
|
||||
if (0 == m_pIface->Release())
|
||||
m_pIface = NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif // !defined(AFX_SMARTINTERFACEPTR_H__A0E1BBE7_A5D8_4A80_9A36_ED5553FE74F6__INCLUDED_)
|
||||
@@ -0,0 +1,450 @@
|
||||
// WaitingTreeCtrl.cpp : implementation file
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "WaitingTreeCtrl.h"
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201)
|
||||
#include <mmsystem.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#pragma comment(lib, "winmm.lib")
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define new DEBUG_NEW
|
||||
#undef THIS_FILE
|
||||
static char THIS_FILE[] = __FILE__;
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CWaitingTreeCtrl
|
||||
|
||||
CWaitingTreeCtrl::CWaitingTreeCtrl()
|
||||
{
|
||||
m_bDrawSnapshot = FALSE;
|
||||
|
||||
m_sWaitMsg = _T("Loading...");
|
||||
m_bShowWaitMsg = FALSE;
|
||||
m_hIconMsg = NULL; // default: blank icon
|
||||
m_nTimerDelay = 0; // default: no timer
|
||||
|
||||
m_hRedrawEvent = NULL;
|
||||
m_hTimerEvent = NULL;
|
||||
m_hThread = NULL;
|
||||
}
|
||||
|
||||
CWaitingTreeCtrl::~CWaitingTreeCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CWaitingTreeCtrl, CTreeCtrl)
|
||||
//{{AFX_MSG_MAP(CWaitingTreeCtrl)
|
||||
ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemExpanding)
|
||||
ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnItemExpanded)
|
||||
ON_WM_ERASEBKGND()
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CWaitingTreeCtrl message handlers
|
||||
|
||||
void CWaitingTreeCtrl::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
|
||||
{
|
||||
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
|
||||
|
||||
if (pNMTreeView->action & TVE_EXPAND)
|
||||
PreExpandItem(pNMTreeView->itemNew.hItem);
|
||||
|
||||
*pResult = 0;
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::OnItemExpanded(NMHDR* pNMHDR, LRESULT* pResult)
|
||||
{
|
||||
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
|
||||
|
||||
if (pNMTreeView->action & TVE_EXPAND)
|
||||
ExpandItem(pNMTreeView->itemNew.hItem);
|
||||
else if (pNMTreeView->action & TVE_COLLAPSE)
|
||||
{
|
||||
if (WantsRefresh(pNMTreeView->itemNew.hItem))
|
||||
{
|
||||
// delete child items
|
||||
DeleteChildren(pNMTreeView->itemNew.hItem);
|
||||
}
|
||||
}
|
||||
|
||||
*pResult = 0;
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::PreAnimation(HTREEITEM hItemMsg)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hItemMsg);
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::PostAnimation()
|
||||
{
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::DoAnimation(BOOL bTimerEvent, int iMaxSteps, int iStep)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(bTimerEvent);
|
||||
UNREFERENCED_PARAMETER(iMaxSteps);
|
||||
UNREFERENCED_PARAMETER(iStep);
|
||||
}
|
||||
|
||||
int CWaitingTreeCtrl::GetPopulationCount(int *piMaxSubItems)
|
||||
{
|
||||
if (piMaxSubItems != NULL)
|
||||
*piMaxSubItems = m_iItemCount;
|
||||
return m_iItemIndex;
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::SetPopulationCount(int iMaxSubItems, int iFirstSubItem)
|
||||
{
|
||||
m_iItemCount = iMaxSubItems;
|
||||
m_iItemIndex = iFirstSubItem;
|
||||
|
||||
SetEvent(m_hRedrawEvent);
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::UpdatePopulation(int iSubItems)
|
||||
{
|
||||
m_iItemIndex = iSubItems;
|
||||
|
||||
SetEvent(m_hRedrawEvent);
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::IncreasePopulation(int iSubItemsToAdd)
|
||||
{
|
||||
m_iItemIndex += iSubItemsToAdd;
|
||||
|
||||
SetEvent(m_hRedrawEvent);
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::SetAnimationDelay(UINT nMilliseconds)
|
||||
{
|
||||
// if greater than zero, periodic DoAnimation() will be called
|
||||
m_nTimerDelay = nMilliseconds;
|
||||
}
|
||||
|
||||
DWORD WINAPI CWaitingTreeCtrl::AnimationThreadProc(LPVOID pThis)
|
||||
{
|
||||
CWaitingTreeCtrl* me = (CWaitingTreeCtrl*)pThis;
|
||||
|
||||
HANDLE events[2] = { me->m_hTimerEvent, me->m_hRedrawEvent };
|
||||
|
||||
while (!me->m_bAbortAnimation)
|
||||
{
|
||||
DWORD wait = WaitForMultipleObjects(2, events, FALSE, INFINITE);
|
||||
|
||||
if (me->m_bAbortAnimation || wait == WAIT_FAILED)
|
||||
break;
|
||||
|
||||
if (wait == WAIT_OBJECT_0) // timer event
|
||||
me->DoAnimation(TRUE, me->m_iItemCount, me->m_iItemIndex);
|
||||
else // redraw event
|
||||
me->DoAnimation(FALSE, me->m_iItemCount, me->m_iItemIndex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::StartAnimation()
|
||||
{
|
||||
// user-defined setup
|
||||
PreAnimation(m_hItemMsg);
|
||||
|
||||
// animation can go
|
||||
m_bAbortAnimation = FALSE;
|
||||
// automatic reset events, signaled
|
||||
m_hTimerEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
|
||||
m_hRedrawEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
|
||||
// start animation thread
|
||||
DWORD dwThreadID = 0;
|
||||
m_hThread = CreateThread(NULL, 0, AnimationThreadProc, this,
|
||||
THREAD_PRIORITY_HIGHEST, &dwThreadID);
|
||||
// setup timer, if specified
|
||||
if (m_nTimerDelay > 0)
|
||||
m_nTimerID = (UINT)timeSetEvent(m_nTimerDelay, 5, (LPTIMECALLBACK)m_hTimerEvent,
|
||||
0, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET);
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::StopAnimation()
|
||||
{
|
||||
// stop and destroy timer
|
||||
timeKillEvent(m_nTimerID);
|
||||
// signal thread to terminate
|
||||
m_bAbortAnimation = TRUE;
|
||||
SetEvent(m_hRedrawEvent); // make sure it can see the signal
|
||||
// wait thread termination
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
// clean up
|
||||
CloseHandle(m_hTimerEvent);
|
||||
m_hTimerEvent = NULL;
|
||||
CloseHandle(m_hRedrawEvent);
|
||||
m_hRedrawEvent = NULL;
|
||||
CloseHandle(m_hThread);
|
||||
m_hThread = NULL;
|
||||
|
||||
// user-defined cleanup
|
||||
PostAnimation();
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::PopulateRoot()
|
||||
{
|
||||
PreExpandItem(TVI_ROOT);
|
||||
ExpandItem(TVI_ROOT);
|
||||
// force update, don't scroll
|
||||
SetRedraw(FALSE);
|
||||
SCROLLINFO si;
|
||||
GetScrollInfo(SB_HORZ, &si);
|
||||
EnsureVisible(GetChildItem(TVI_ROOT));
|
||||
SetScrollInfo(SB_HORZ, &si, FALSE);
|
||||
SetRedraw();
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::PreExpandItem(HTREEITEM hItem)
|
||||
{
|
||||
if (!NeedsChildren(hItem))
|
||||
{
|
||||
if (WantsRefresh(hItem))
|
||||
{
|
||||
// delete child items before populating
|
||||
DeleteChildren(hItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
// doesn't want new items
|
||||
m_hItemToPopulate = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if it wants new child items, go on
|
||||
m_hItemToPopulate = hItem;
|
||||
|
||||
// fix redraw when expanded programatically
|
||||
UpdateWindow();
|
||||
// hide changes until it's expanded
|
||||
SetRedraw(FALSE);
|
||||
// add wait msg, to allow item expansion
|
||||
m_hItemMsg = InsertItem(m_sWaitMsg, m_hItemToPopulate);
|
||||
// zero progress
|
||||
m_iItemCount = 1;
|
||||
m_iItemIndex = 0;
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::ExpandItem(HTREEITEM hItem)
|
||||
{
|
||||
if (m_hItemToPopulate == NULL)
|
||||
return; // just expand, doesn't want new items
|
||||
|
||||
ASSERT(hItem == m_hItemToPopulate); // should never fail!!!
|
||||
|
||||
if (m_bShowWaitMsg)
|
||||
{
|
||||
// display wait msg now, make sure it's visible
|
||||
SetRedraw();
|
||||
EnsureVisible(m_hItemMsg);
|
||||
UpdateWindow();
|
||||
}
|
||||
// setup animation thread, call PreAnimation
|
||||
StartAnimation();
|
||||
// draw icon
|
||||
if (m_bShowWaitMsg)
|
||||
DrawUserIcon();
|
||||
// delay redraw after populating
|
||||
SetRedraw(FALSE);
|
||||
// take a snapshot of the background
|
||||
TakeSnapshot();
|
||||
// del temporary item (wait msg still shown)
|
||||
DeleteItem(m_hItemMsg);
|
||||
// fill in with sub items
|
||||
BOOL bCheckChildren = PopulateItem(hItem);
|
||||
// clean up animation thread, call PostAnimation
|
||||
StopAnimation();
|
||||
// change parent to reflect current children number
|
||||
if (hItem != TVI_ROOT)
|
||||
{
|
||||
TVITEM item;
|
||||
item.hItem = hItem;
|
||||
item.mask = TVIF_HANDLE | TVIF_CHILDREN;
|
||||
item.cChildren = NeedsChildren(hItem) ? 0 : 1;
|
||||
if (bCheckChildren)
|
||||
SetItem(&item);
|
||||
else if (item.cChildren == 0)
|
||||
// restore item's plus button if no children inserted
|
||||
SetItemState(hItem, 0, TVIS_EXPANDED);
|
||||
}
|
||||
// clean up snapshot
|
||||
DestroySnapshot();
|
||||
// redraw now
|
||||
SetRedraw(TRUE);
|
||||
// scroll like in a standard expansion
|
||||
HTREEITEM hChild = GetChildItem(hItem);
|
||||
while (hChild != NULL && GetFirstVisibleItem() != hItem)
|
||||
{
|
||||
// EnsureVisible(hChild);
|
||||
hChild = GetNextSiblingItem(hChild);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CWaitingTreeCtrl::WantsRefresh(HTREEITEM hItem)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hItem);
|
||||
|
||||
// default implementation, no refresh
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CWaitingTreeCtrl::GetItemImageRect(HTREEITEM hItem, LPRECT pRect)
|
||||
{
|
||||
if (GetImageList(TVSIL_NORMAL) == NULL)
|
||||
return FALSE; // no images
|
||||
|
||||
CRect rc;
|
||||
// get item rect
|
||||
if (!GetItemRect(hItem, &rc, TRUE))
|
||||
return FALSE;
|
||||
|
||||
int cx = GetSystemMetrics(SM_CXSMICON);
|
||||
int cy = GetSystemMetrics(SM_CYSMICON);
|
||||
|
||||
// move onto the icon space
|
||||
int margin = (rc.Height()-cy)/2;
|
||||
rc.OffsetRect(-cx-3 , margin);
|
||||
rc.right = rc.left + cx; // make it square
|
||||
rc.bottom = rc.top + cy; // make it square
|
||||
|
||||
*pRect = rc;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::DrawUserIcon()
|
||||
{
|
||||
// draw user defined icon
|
||||
|
||||
CRect rcIcon;
|
||||
if (!GetItemImageRect(m_hItemMsg, &rcIcon))
|
||||
return; // no image
|
||||
|
||||
// create background brush with current bg color (take rgb part only)
|
||||
HBRUSH hBrush = CreateSolidBrush(GetBkColor() & 0x00FFFFFF);
|
||||
|
||||
CClientDC dc(this);
|
||||
|
||||
if (m_hIconMsg != NULL)
|
||||
DrawIconEx(dc.GetSafeHdc(), rcIcon.left, rcIcon.top, m_hIconMsg,
|
||||
rcIcon.Width(), rcIcon.Height(), 0, hBrush, DI_NORMAL);
|
||||
else
|
||||
FillRect(dc.GetSafeHdc(), &rcIcon, hBrush);
|
||||
|
||||
DeleteObject(hBrush);
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::SetWaitMessage(LPCTSTR pszText, HICON hIcon)
|
||||
{
|
||||
m_sWaitMsg = pszText;
|
||||
m_hIconMsg = hIcon;
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::RefreshSubItems(HTREEITEM hParent)
|
||||
{
|
||||
if (hParent != TVI_ROOT && !ItemHasChildren(hParent))
|
||||
return;
|
||||
|
||||
SetRedraw(FALSE);
|
||||
DeleteChildren(hParent);
|
||||
if (hParent == TVI_ROOT)
|
||||
PopulateRoot();
|
||||
else
|
||||
{
|
||||
PreExpandItem(hParent);
|
||||
ExpandItem(hParent);
|
||||
}
|
||||
SetRedraw(TRUE);
|
||||
}
|
||||
|
||||
inline BOOL CWaitingTreeCtrl::NeedsChildren(HTREEITEM hParent)
|
||||
{
|
||||
return (GetChildItem(hParent) == NULL);
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::DeleteChildren(HTREEITEM hParent)
|
||||
{
|
||||
HTREEITEM hChild = GetChildItem(hParent);
|
||||
HTREEITEM hNext;
|
||||
|
||||
while (hChild != NULL)
|
||||
{
|
||||
hNext = GetNextSiblingItem(hChild);
|
||||
DeleteItem(hChild);
|
||||
hChild = hNext;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CWaitingTreeCtrl::OnEraseBkgnd(CDC* pDC)
|
||||
{
|
||||
if (!m_bDrawSnapshot)
|
||||
return CTreeCtrl::OnEraseBkgnd(pDC);
|
||||
|
||||
DrawSnapshot(pDC);
|
||||
SetEvent(m_hRedrawEvent);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::TakeSnapshot()
|
||||
{
|
||||
CClientDC dc(this);
|
||||
CRect rcClient;
|
||||
GetClientRect(&rcClient);
|
||||
int width = rcClient.Width(), height = rcClient.Height();
|
||||
|
||||
// create the snapshot
|
||||
CDC dcSnapshot;
|
||||
dcSnapshot.CreateCompatibleDC(&dc);
|
||||
m_bmpSnapshot.CreateCompatibleBitmap(&dc, width, height);
|
||||
// copy the control's background
|
||||
CBitmap* pOldBmp = dcSnapshot.SelectObject(&m_bmpSnapshot);
|
||||
dcSnapshot.BitBlt(0, 0, width, height, &dc, 0, 0, SRCCOPY);
|
||||
dcSnapshot.SelectObject(pOldBmp);
|
||||
|
||||
m_bDrawSnapshot = TRUE;
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::DrawSnapshot(CDC *pDC)
|
||||
{
|
||||
BITMAP bm;
|
||||
m_bmpSnapshot.GetBitmap(&bm);
|
||||
|
||||
// prepare the snapshot
|
||||
CDC dcSnapshot;
|
||||
dcSnapshot.CreateCompatibleDC(pDC);
|
||||
// copy to the control's background
|
||||
CBitmap* pOldBmp = dcSnapshot.SelectObject(&m_bmpSnapshot);
|
||||
pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcSnapshot, 0, 0, SRCCOPY);
|
||||
dcSnapshot.SelectObject(pOldBmp);
|
||||
}
|
||||
|
||||
void CWaitingTreeCtrl::DestroySnapshot()
|
||||
{
|
||||
m_bmpSnapshot.DeleteObject();
|
||||
|
||||
m_bDrawSnapshot = FALSE;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
// WaitingTreeCtrl.h : header file
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_WAITINGTREECTRL_H__80CBE29B_F1A6_41D5_9DF3_B725E73BCF0F__INCLUDED_)
|
||||
#define AFX_WAITINGTREECTRL_H__80CBE29B_F1A6_41D5_9DF3_B725E73BCF0F__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CWaitingTreeCtrl window
|
||||
|
||||
class CWaitingTreeCtrl : public CTreeCtrl
|
||||
{
|
||||
private:
|
||||
void DestroySnapshot();
|
||||
void DrawSnapshot(CDC* pDC);
|
||||
void TakeSnapshot();
|
||||
HANDLE m_hThread; // secondary thread for animations
|
||||
HANDLE m_hTimerEvent; // signaled at each timer period
|
||||
HANDLE m_hRedrawEvent; // signaled at each population update
|
||||
volatile BOOL m_bAbortAnimation; // request to terminate secondary thread
|
||||
BOOL m_bDrawSnapshot; // whether to draw background during populating
|
||||
CBitmap m_bmpSnapshot; // snapshot bitmap
|
||||
UINT m_nTimerID; // animation timer id
|
||||
UINT m_nTimerDelay; // animation timer period (ms)
|
||||
CString m_sWaitMsg; // text for the wait message
|
||||
HICON m_hIconMsg; // icon for the wait message
|
||||
BOOL m_bShowWaitMsg; // wether to show the wait message
|
||||
int m_iItemIndex; // population progress index
|
||||
int m_iItemCount; // population progress max index
|
||||
HTREEITEM m_hItemMsg; // wait message item
|
||||
HTREEITEM m_hItemToPopulate; // item being populated
|
||||
|
||||
// secondary thread entry point
|
||||
static DWORD WINAPI AnimationThreadProc(LPVOID pThis);
|
||||
|
||||
void StartAnimation(); // set up animation thread
|
||||
void StopAnimation(); // animation clean up
|
||||
|
||||
void PreExpandItem(HTREEITEM hItem); // before expanding
|
||||
void ExpandItem(HTREEITEM hItem); // after expanded
|
||||
|
||||
BOOL NeedsChildren(HTREEITEM hParent); // true if no child items
|
||||
void DeleteChildren(HTREEITEM hParent);
|
||||
|
||||
void DrawUserIcon(); // draw wait message icon
|
||||
|
||||
// Construction
|
||||
public:
|
||||
CWaitingTreeCtrl();
|
||||
virtual ~CWaitingTreeCtrl();
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
|
||||
// Operations
|
||||
public:
|
||||
|
||||
// Overrides
|
||||
// ClassWizard generated virtual function overrides
|
||||
//{{AFX_VIRTUAL(CWaitingTreeCtrl)
|
||||
public:
|
||||
//}}AFX_VIRTUAL
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
void RefreshSubItems(HTREEITEM hParent);
|
||||
void SetWaitMessage(LPCTSTR pszText, HICON hIcon = NULL);
|
||||
void ShowWaitMessage()
|
||||
{
|
||||
m_bShowWaitMsg = TRUE;
|
||||
};
|
||||
|
||||
protected:
|
||||
// animation functions (with timer)
|
||||
void SetAnimationDelay(UINT nMilliseconds);
|
||||
|
||||
// animation functions (with or without timer)
|
||||
virtual void PreAnimation(HTREEITEM hItemMsg);
|
||||
virtual void DoAnimation(BOOL bTimerEvent, int iMaxSteps, int iStep);
|
||||
virtual void PostAnimation();
|
||||
BOOL GetItemImageRect(HTREEITEM hItem, LPRECT pRect);
|
||||
|
||||
// tree content functions
|
||||
void PopulateRoot();
|
||||
virtual BOOL WantsRefresh(HTREEITEM hItem);
|
||||
virtual BOOL PopulateItem(HTREEITEM hParent) = 0; // must be implemented
|
||||
|
||||
// tree content functions (for animations without timer)
|
||||
int GetPopulationCount(int *piMaxSubItems = NULL);
|
||||
void SetPopulationCount(int iMaxSubItems, int iFirstSubItem = 0);
|
||||
void IncreasePopulation(int iSubItemsToAdd = 1);
|
||||
void UpdatePopulation(int iSubItems);
|
||||
|
||||
// Generated message map functions
|
||||
//{{AFX_MSG(CWaitingTreeCtrl)
|
||||
afx_msg void OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult);
|
||||
afx_msg void OnItemExpanded(NMHDR* pNMHDR, LRESULT* pResult);
|
||||
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
|
||||
//}}AFX_MSG
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_WAITINGTREECTRL_H__80CBE29B_F1A6_41D5_9DF3_B725E73BCF0F__INCLUDED_)
|
||||
Reference in New Issue
Block a user