You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
759 lines
16 KiB
C++
759 lines
16 KiB
C++
2 years ago
|
// XTPShellPidl.cpp : implementation file
|
||
|
//
|
||
|
// This file is a part of the XTREME CONTROLS MFC class library.
|
||
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
||
|
//
|
||
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
||
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
||
|
// CONSENT OF CODEJOCK SOFTWARE.
|
||
|
//
|
||
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
||
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
||
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
||
|
// SINGLE COMPUTER.
|
||
|
//
|
||
|
// CONTACT INFORMATION:
|
||
|
// support@codejock.com
|
||
|
// http://www.codejock.com
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
#include "Common/XTPVC80Helpers.h" // Visual Studio 2005 helper functions
|
||
|
#include "Common/XTPResourceManager.h"
|
||
|
|
||
|
#include "XTPShellPidl.h"
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
CXTPShellPidl::CShellSpecialFolder::CShellSpecialFolder(int nFolder)
|
||
|
{
|
||
|
m_lpFolder = NULL;
|
||
|
|
||
|
if (FAILED(::SHGetDesktopFolder(&m_lpFolder)))
|
||
|
{
|
||
|
m_lpFolder = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (nFolder != CSIDL_DESKTOP)
|
||
|
{
|
||
|
CXTPShellPidl::CShellMalloc lpMalloc;
|
||
|
LPSHELLFOLDER lpFolder = NULL;
|
||
|
|
||
|
if (lpMalloc)
|
||
|
{
|
||
|
LPITEMIDLIST pidlFolder = NULL;
|
||
|
if (SUCCEEDED(::SHGetSpecialFolderLocation(NULL, nFolder, &pidlFolder)))
|
||
|
{
|
||
|
m_lpFolder->BindToObject(pidlFolder, 0, IID_IShellFolder, (LPVOID*)&lpFolder);
|
||
|
|
||
|
lpMalloc.Free(pidlFolder);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_lpFolder->Release();
|
||
|
m_lpFolder = lpFolder;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CXTPShellPidl
|
||
|
|
||
|
CXTPShellPidl::CXTPShellPidl()
|
||
|
: m_bShowShellLinkIcons(TRUE)
|
||
|
, m_ulSFGAOFlags(0)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
CXTPShellPidl::~CXTPShellPidl()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Functions that deal with PIDLs
|
||
|
|
||
|
LPITEMIDLIST CXTPShellPidl::IDLFromPath(LPCTSTR strPath)
|
||
|
{
|
||
|
IShellFolder *psfDeskTop = NULL;
|
||
|
LPITEMIDLIST pidlPath = NULL;
|
||
|
|
||
|
if (FAILED(::SHGetDesktopFolder(&psfDeskTop)))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Get the folders IDL
|
||
|
psfDeskTop->ParseDisplayName(NULL, NULL,
|
||
|
(LPOLESTR)XTP_CT2CW(strPath), NULL, &pidlPath, NULL);
|
||
|
|
||
|
psfDeskTop->Release();
|
||
|
|
||
|
return pidlPath;
|
||
|
}
|
||
|
|
||
|
LPITEMIDLIST CXTPShellPidl::OneUpPIDL(LPITEMIDLIST pidlPath)
|
||
|
{
|
||
|
if (pidlPath)
|
||
|
{
|
||
|
// Get the last item
|
||
|
LPITEMIDLIST pidlLast = GetLastITEM(pidlPath);
|
||
|
// if not a NULL
|
||
|
if (pidlLast)
|
||
|
{
|
||
|
// don't attempt to go any lower than 1 IDL
|
||
|
if (pidlLast == pidlPath) return pidlPath;
|
||
|
// set its cb to 0
|
||
|
pidlLast->mkid.cb = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pidlPath;
|
||
|
}
|
||
|
CString CXTPShellPidl::OneUpPATH(const CString& path)
|
||
|
{
|
||
|
// Make a string buffer
|
||
|
TCHAR newPath[MAX_PATH];
|
||
|
ZeroMemory(newPath, sizeof(newPath));
|
||
|
|
||
|
if (path.GetLength())
|
||
|
{
|
||
|
LPITEMIDLIST pidlPath = IDLFromPath(path);
|
||
|
if (OneUpPIDL(pidlPath))
|
||
|
{
|
||
|
SHGetPathFromIDList(pidlPath, newPath);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return CString(newPath);
|
||
|
|
||
|
}
|
||
|
LPITEMIDLIST CXTPShellPidl::GetLastITEM(LPITEMIDLIST pidl)
|
||
|
{
|
||
|
LPSTR lpMem = NULL;
|
||
|
LPITEMIDLIST pidlLast = NULL;
|
||
|
if (pidl)
|
||
|
{
|
||
|
lpMem = (LPSTR)pidl;
|
||
|
// walk the list until we find a null
|
||
|
while (*lpMem != 0)
|
||
|
{
|
||
|
if (LPITEMIDLIST(lpMem)->mkid.cb == 0) break;// maybe ?
|
||
|
|
||
|
pidlLast = (LPITEMIDLIST)lpMem;
|
||
|
lpMem += LPITEMIDLIST(lpMem)->mkid.cb;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pidlLast;
|
||
|
}
|
||
|
|
||
|
LPITEMIDLIST CXTPShellPidl::CopyPidlItem(LPITEMIDLIST pidl, UINT nItem)
|
||
|
{
|
||
|
if (!pidl)
|
||
|
return NULL;
|
||
|
|
||
|
while (nItem--)
|
||
|
{
|
||
|
if (pidl->mkid.cb == 0)
|
||
|
return NULL;
|
||
|
|
||
|
pidl = GetNextPidlItem(pidl);
|
||
|
}
|
||
|
|
||
|
int nSize = pidl->mkid.cb + sizeof(pidl->mkid.cb);
|
||
|
LPITEMIDLIST pidlCopy = CreatePidl(CShellMalloc(), nSize);
|
||
|
|
||
|
if (pidlCopy)
|
||
|
{
|
||
|
ZeroMemory(pidlCopy, nSize);
|
||
|
MEMCPY_S(pidlCopy, pidl, pidl->mkid.cb);
|
||
|
}
|
||
|
|
||
|
return pidlCopy;
|
||
|
}
|
||
|
|
||
|
LPITEMIDLIST CXTPShellPidl::CopyIDList(LPITEMIDLIST pidl)
|
||
|
{
|
||
|
LPITEMIDLIST pidlCopy = NULL;
|
||
|
UINT bytes = 0;
|
||
|
bytes = GetPidlItemCount(pidl);
|
||
|
pidlCopy = CreatePidl(CShellMalloc(), bytes);
|
||
|
|
||
|
if (pidlCopy)
|
||
|
{
|
||
|
ZeroMemory(pidlCopy, bytes);
|
||
|
MEMCPY_S(pidlCopy, pidl, bytes);
|
||
|
}
|
||
|
|
||
|
return pidlCopy;
|
||
|
}
|
||
|
|
||
|
LPITEMIDLIST CXTPShellPidl::GetNextPidlItem(LPCITEMIDLIST pidl)
|
||
|
{
|
||
|
LPSTR lpMem = (LPSTR)pidl;
|
||
|
lpMem += pidl->mkid.cb;
|
||
|
return (LPITEMIDLIST)lpMem;
|
||
|
}
|
||
|
|
||
|
UINT CXTPShellPidl::GetPidlCount(LPCITEMIDLIST pidl)
|
||
|
{
|
||
|
UINT nCount = 0;
|
||
|
if (pidl)
|
||
|
{
|
||
|
while (pidl->mkid.cb)
|
||
|
{
|
||
|
++nCount;
|
||
|
pidl = GetNextPidlItem(pidl);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nCount;
|
||
|
}
|
||
|
|
||
|
UINT CXTPShellPidl::GetPidlItemCount(LPCITEMIDLIST pidl)
|
||
|
{
|
||
|
UINT cbTotal = 0;
|
||
|
if (pidl)
|
||
|
{
|
||
|
cbTotal += sizeof(pidl->mkid.cb); // Null terminator
|
||
|
while (pidl->mkid.cb)
|
||
|
{
|
||
|
cbTotal += pidl->mkid.cb;
|
||
|
pidl = GetNextPidlItem(pidl);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return cbTotal;
|
||
|
}
|
||
|
|
||
|
LPITEMIDLIST CXTPShellPidl::CreatePidl(LPMALLOC lpMalloc, UINT cbSize)
|
||
|
{
|
||
|
if (!lpMalloc)
|
||
|
return NULL;
|
||
|
|
||
|
// zero-init for external task allocate
|
||
|
LPITEMIDLIST pidl = (LPITEMIDLIST)lpMalloc->Alloc(cbSize);
|
||
|
if (pidl)
|
||
|
{
|
||
|
memset(pidl, 0, cbSize);
|
||
|
}
|
||
|
|
||
|
return pidl;
|
||
|
}
|
||
|
|
||
|
void CXTPShellPidl::FreePidl(LPITEMIDLIST pidl)
|
||
|
{
|
||
|
if (!pidl)
|
||
|
return;
|
||
|
|
||
|
CShellMalloc lpMalloc;
|
||
|
|
||
|
if (lpMalloc)
|
||
|
{
|
||
|
lpMalloc.Free(pidl);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellPidl::ComparePidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, LPSHELLFOLDER pShellFolder /*NULL*/)
|
||
|
{
|
||
|
if (pidl1 == NULL || pidl2 == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
BOOL bLPCreated = FALSE;
|
||
|
if (pShellFolder == NULL)
|
||
|
{
|
||
|
if (FAILED(::SHGetDesktopFolder(&pShellFolder)))
|
||
|
return FALSE;
|
||
|
bLPCreated = TRUE;
|
||
|
}
|
||
|
|
||
|
HRESULT hr = pShellFolder->CompareIDs(0, pidl1, pidl2);
|
||
|
|
||
|
if (bLPCreated)
|
||
|
{
|
||
|
pShellFolder->Release();
|
||
|
}
|
||
|
|
||
|
return ((short)hr) == 0;
|
||
|
}
|
||
|
|
||
|
LPITEMIDLIST CXTPShellPidl::ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
||
|
{
|
||
|
return ConcatPidls(CShellMalloc(), pidl1, pidl2);
|
||
|
}
|
||
|
|
||
|
LPITEMIDLIST CXTPShellPidl::ConcatPidls(LPMALLOC lpMalloc, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
||
|
{
|
||
|
LPITEMIDLIST pidlNew;
|
||
|
UINT cb1;
|
||
|
UINT cb2;
|
||
|
|
||
|
// May be NULL
|
||
|
if (pidl1)
|
||
|
{
|
||
|
cb1 = GetPidlItemCount(pidl1) - sizeof(pidl1->mkid.cb);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cb1 = 0;
|
||
|
}
|
||
|
|
||
|
cb2 = GetPidlItemCount(pidl2);
|
||
|
pidlNew = CreatePidl(lpMalloc, cb1 + cb2);
|
||
|
|
||
|
if (pidlNew)
|
||
|
{
|
||
|
if (pidl1)
|
||
|
{
|
||
|
MEMCPY_S(pidlNew, pidl1, cb1);
|
||
|
}
|
||
|
|
||
|
MEMCPY_S(((LPSTR)pidlNew) + cb1, pidl2, cb2);
|
||
|
}
|
||
|
|
||
|
return pidlNew;
|
||
|
}
|
||
|
|
||
|
LPITEMIDLIST CXTPShellPidl::DuplicateItem(LPMALLOC lpMalloc, LPITEMIDLIST lpi)
|
||
|
{
|
||
|
LPITEMIDLIST lpiTemp = (LPITEMIDLIST)lpMalloc->Alloc(lpi->mkid.cb + sizeof(lpi->mkid.cb));
|
||
|
|
||
|
MEMCPY_S((PVOID)lpiTemp, (CONST VOID *)lpi, lpi->mkid.cb + sizeof(lpi->mkid.cb));
|
||
|
|
||
|
return lpiTemp;
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellPidl::GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi, DWORD dwFlags, CString& strFriendlyName)
|
||
|
{
|
||
|
STRRET str;
|
||
|
if (lpsf->GetDisplayNameOf(lpi, dwFlags, &str) == NOERROR)
|
||
|
{
|
||
|
switch (str.uType)
|
||
|
{
|
||
|
case STRRET_WSTR:
|
||
|
{
|
||
|
strFriendlyName = str.pOleStr;
|
||
|
|
||
|
CShellMalloc pMalloc;
|
||
|
if (pMalloc) pMalloc.Free(str.pOleStr);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case STRRET_OFFSET:
|
||
|
{
|
||
|
LPSTR lpszOffset = (LPSTR)lpi + str.uOffset;
|
||
|
strFriendlyName = lpszOffset;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case STRRET_CSTR:
|
||
|
strFriendlyName = (LPSTR)str.cStr;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
LPITEMIDLIST CXTPShellPidl::GetFullyQualPidl(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi)
|
||
|
{
|
||
|
CString strBuff;
|
||
|
LPSHELLFOLDER lpsfDeskTop;
|
||
|
LPITEMIDLIST lpifq;
|
||
|
ULONG ulEaten, ulAttribs;
|
||
|
|
||
|
if (!GetName(lpsf, lpi, SHGDN_FORPARSING, strBuff))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (FAILED(::SHGetDesktopFolder(&lpsfDeskTop)))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (FAILED(lpsfDeskTop->ParseDisplayName(NULL, NULL, (LPOLESTR)XTP_CT2CW(strBuff),
|
||
|
&ulEaten, &lpifq, &ulAttribs)))
|
||
|
{
|
||
|
lpsfDeskTop->Release();
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
lpsfDeskTop->Release();
|
||
|
return lpifq;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG CXTPShellPidl::GetAttributes(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi, ULONG uFlags) const
|
||
|
{
|
||
|
if (!lpsf || !lpi)
|
||
|
return 0;
|
||
|
|
||
|
if ((uFlags & SFGAO_DISPLAYATTRMASK) == 0)
|
||
|
{
|
||
|
lpsf->GetAttributesOf(1, (LPCITEMIDLIST*)&lpi, &uFlags);
|
||
|
return uFlags;
|
||
|
}
|
||
|
|
||
|
ULONG ulAttrs = SFGAO_REMOVABLE;
|
||
|
lpsf->GetAttributesOf(1, (LPCITEMIDLIST*)&lpi, &ulAttrs);
|
||
|
|
||
|
if ((ulAttrs & SFGAO_REMOVABLE) != 0)
|
||
|
return SFGAO_REMOVABLE | SFGAO_HASSUBFOLDER | SFGAO_FOLDER;
|
||
|
|
||
|
lpsf->GetAttributesOf(1, (LPCITEMIDLIST*)&lpi, &uFlags);
|
||
|
return uFlags;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Static variables used for passing data to the subclassing wndProc
|
||
|
WNDPROC CXTPShellPidl::m_pOldWndProc = NULL; // regular window proc
|
||
|
LPCONTEXTMENU2 CXTPShellPidl::m_pIContext2 = NULL; // active shell context menu
|
||
|
|
||
|
BOOL CXTPShellPidl::ShowContextMenu(HWND hwnd, LPSHELLFOLDER lpsfParent, LPITEMIDLIST lpi, LPPOINT lppt)
|
||
|
{
|
||
|
return ShowContextMenu(hwnd, lpsfParent, (LPCITEMIDLIST*)&lpi, 1, lppt);
|
||
|
}
|
||
|
|
||
|
void CXTPShellPidl::OnShowContextMenu(int /*idCmd*/, CMINVOKECOMMANDINFO& /*cmi*/)
|
||
|
{
|
||
|
// handle in derived class.
|
||
|
}
|
||
|
|
||
|
BOOL CXTPShellPidl::ShowContextMenu(HWND hwnd, LPSHELLFOLDER lpsfParent, LPCITEMIDLIST* lpi, int nCount, LPPOINT lppt)
|
||
|
{
|
||
|
LPCONTEXTMENU lpcm;
|
||
|
CMINVOKECOMMANDINFO cmi;
|
||
|
BOOL bSuccess = TRUE;
|
||
|
int cmType; // "version" # of context menu
|
||
|
|
||
|
// assume that psfFolder and pidl are valid
|
||
|
HRESULT hr = GetSHContextMenu(lpsfParent, lpi, nCount, (void**)&lpcm, &cmType);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
HMENU hMenu = ::CreatePopupMenu();
|
||
|
|
||
|
if (hMenu != NULL)
|
||
|
{
|
||
|
hr = lpcm->QueryContextMenu(hMenu, 0, 1, 0x7fff, CMF_EXPLORE);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// install the subclassing "hook", for versions 2 or 3
|
||
|
if (cmType > 1)
|
||
|
{
|
||
|
m_pOldWndProc = (WNDPROC)
|
||
|
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)HookWndProc);
|
||
|
m_pIContext2 = (LPCONTEXTMENU2)lpcm; // cast ok for ICMv3
|
||
|
}
|
||
|
else
|
||
|
m_pOldWndProc = NULL;
|
||
|
|
||
|
int idCmd = ::TrackPopupMenu(hMenu,
|
||
|
TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
|
||
|
lppt->x, lppt->y, 0, hwnd, NULL);
|
||
|
|
||
|
if (m_pOldWndProc) // restore old wndProc
|
||
|
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)m_pOldWndProc);
|
||
|
|
||
|
if (idCmd != 0)
|
||
|
{
|
||
|
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
|
||
|
cmi.fMask = 0;
|
||
|
cmi.hwnd = hwnd;
|
||
|
cmi.lpVerb = (LPCSTR)MAKEINTRESOURCE(idCmd-1);
|
||
|
cmi.lpParameters = NULL;
|
||
|
cmi.lpDirectory = NULL;
|
||
|
cmi.nShow = SW_SHOWNORMAL;
|
||
|
cmi.dwHotKey = 0;
|
||
|
cmi.hIcon = NULL;
|
||
|
|
||
|
if (SUCCEEDED(lpcm->InvokeCommand(&cmi)))
|
||
|
{
|
||
|
OnShowContextMenu(idCmd-1, cmi);
|
||
|
}
|
||
|
}
|
||
|
m_pIContext2 = NULL; // prevents accidental use
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bSuccess = FALSE;
|
||
|
}
|
||
|
|
||
|
::DestroyMenu(hMenu);
|
||
|
}
|
||
|
else
|
||
|
bSuccess = FALSE;
|
||
|
|
||
|
lpcm->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CString strMessage;
|
||
|
strMessage.Format(_T("GetUIObjectOf failed! hr=%lx"), hr);
|
||
|
AfxMessageBox(strMessage);
|
||
|
bSuccess = FALSE;
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
int CXTPShellPidl::GetItemIcon(LPITEMIDLIST lpi, UINT uFlags) const
|
||
|
{
|
||
|
SHFILEINFO sfi;
|
||
|
::SHGetFileInfo((TCHAR*)lpi, 0, &sfi, sizeof(SHFILEINFO), uFlags);
|
||
|
|
||
|
return sfi.iIcon;
|
||
|
}
|
||
|
|
||
|
HIMAGELIST CXTPShellPidl::GetSystemImageList(UINT uFlags) const
|
||
|
{
|
||
|
SHFILEINFO sfi;
|
||
|
|
||
|
for (TCHAR cDrive = _T('C'); cDrive <= _T('Z'); cDrive++)
|
||
|
{
|
||
|
if (GetDriveType(CString(cDrive) + _T(":")) == DRIVE_FIXED)
|
||
|
{
|
||
|
return (HIMAGELIST)::SHGetFileInfo(CString(cDrive) + _T(":\\"), 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | uFlags);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
HRESULT CXTPShellPidl::GetSHContextMenu(LPSHELLFOLDER psfFolder, LPCITEMIDLIST* localPidl, int nCount, void** ppCM, int* pcmType)
|
||
|
{
|
||
|
*ppCM = NULL;
|
||
|
LPCONTEXTMENU pICv1 = NULL; // plain version
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
// try to obtain the lowest possible IContextMenu
|
||
|
if (nCount == 0)
|
||
|
{
|
||
|
hr = psfFolder->CreateViewObject(NULL, IID_IContextMenu, (void**)&pICv1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = psfFolder->GetUIObjectOf(NULL, nCount, localPidl, IID_IContextMenu, NULL, (void**)&pICv1);
|
||
|
}
|
||
|
|
||
|
// try to obtain a higher level pointer, first 3 then 2
|
||
|
if (pICv1)
|
||
|
{
|
||
|
hr = pICv1->QueryInterface(IID_IContextMenu3, ppCM);
|
||
|
|
||
|
if (NOERROR == hr)
|
||
|
*pcmType = 3;
|
||
|
|
||
|
else
|
||
|
{
|
||
|
hr = pICv1->QueryInterface(IID_IContextMenu2, ppCM);
|
||
|
if (NOERROR == hr) *pcmType = 2;
|
||
|
}
|
||
|
|
||
|
// free initial "v1.0" interface
|
||
|
if (*ppCM)
|
||
|
pICv1->Release();
|
||
|
|
||
|
// no higher version supported
|
||
|
else
|
||
|
{
|
||
|
*pcmType = 1;
|
||
|
*ppCM = pICv1;
|
||
|
hr = NOERROR; // never mind the query failures, this'll do
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
LRESULT CALLBACK CXTPShellPidl::HookWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||
|
{
|
||
|
UINT uItem;
|
||
|
TCHAR szBuf[MAX_PATH];
|
||
|
|
||
|
switch (msg)
|
||
|
{
|
||
|
case WM_DRAWITEM:
|
||
|
case WM_MEASUREITEM:
|
||
|
{
|
||
|
if (wp)
|
||
|
break; // not menu related
|
||
|
}
|
||
|
|
||
|
case WM_INITMENUPOPUP:
|
||
|
{
|
||
|
m_pIContext2->HandleMenuMsg(msg, wp, lp);
|
||
|
return (msg == WM_INITMENUPOPUP ? 0 : TRUE); // handled
|
||
|
}
|
||
|
|
||
|
case WM_MENUSELECT:
|
||
|
{
|
||
|
// if this is a shell item, get it's descriptive text
|
||
|
uItem = (UINT) LOWORD(wp);
|
||
|
|
||
|
if (0 == (MF_POPUP & HIWORD(wp)) && uItem >= 1 && uItem <= 0x7fff)
|
||
|
{
|
||
|
CFrameWnd * pWnd = ((CFrameWnd*)(AfxGetApp()->m_pMainWnd));
|
||
|
if (!pWnd)
|
||
|
return 0;
|
||
|
|
||
|
szBuf[0] = 0;
|
||
|
|
||
|
// set the status bar text
|
||
|
if (SUCCEEDED(m_pIContext2->GetCommandString(uItem-1, GCS_HELPTEXT,
|
||
|
NULL, (LPSTR)szBuf, _countof(szBuf))))
|
||
|
|
||
|
{
|
||
|
pWnd->SetMessageText(szBuf);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pWnd->SetMessageText(_T(""));
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// for all untreated messages, call the original wndproc
|
||
|
return ::CallWindowProc(m_pOldWndProc, hWnd, msg, wp, lp);
|
||
|
}
|
||
|
|
||
|
int CXTPShellPidl::TreeViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
|
||
|
{
|
||
|
if (!lParam1 || !lParam2)
|
||
|
return 0;
|
||
|
|
||
|
XTP_TVITEMDATA* lptvid1 = (XTP_TVITEMDATA*)lParam1;
|
||
|
XTP_TVITEMDATA* lptvid2 = (XTP_TVITEMDATA*)lParam2;
|
||
|
|
||
|
BOOL bAsc = (lParamSort > 0); // positive - ascending, negative - descending
|
||
|
int iIndex = abs((int)lParamSort) - 1; // remove sort flag from index
|
||
|
|
||
|
HRESULT hr = lptvid1->lpsfParent->CompareIDs(
|
||
|
MAKELPARAM(LOWORD(iIndex), HIWORD(SHCIDS_ALLFIELDS)),
|
||
|
bAsc? lptvid1->lpi: lptvid2->lpi,
|
||
|
bAsc? lptvid2->lpi: lptvid1->lpi);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return (short)SCODE_CODE(GetScode(hr));
|
||
|
}
|
||
|
|
||
|
int CXTPShellPidl::ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
|
||
|
{
|
||
|
if (!lParam1 || !lParam2)
|
||
|
return 0;
|
||
|
|
||
|
XTP_LVITEMDATA* lplvid1 = (XTP_LVITEMDATA*)lParam1;
|
||
|
XTP_LVITEMDATA* lplvid2 = (XTP_LVITEMDATA*)lParam2;
|
||
|
|
||
|
BOOL bAsc = (lParamSort > 0); // positive - ascending, negative - descending
|
||
|
int iIndex = abs((int)lParamSort) - 1; // remove sort flag from index
|
||
|
|
||
|
HRESULT hr = lplvid1->lpsfParent->CompareIDs(
|
||
|
MAKELPARAM(LOWORD(iIndex), HIWORD(SHCIDS_ALLFIELDS)),
|
||
|
bAsc ? lplvid1->lpi : lplvid2->lpi,
|
||
|
bAsc ? lplvid2->lpi : lplvid1->lpi);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return (short)SCODE_CODE(GetScode(hr));
|
||
|
}
|
||
|
|
||
|
void CXTPShellPidl::MapShellFlagsToItemAttributes(CTreeCtrl* pTreeCtrl, HTREEITEM hItem, DWORD dwAttributes)
|
||
|
{
|
||
|
// Display with 'cut' feedback if the item is ghosted (about to be moved to a different location or a hidden one)
|
||
|
if (dwAttributes & SFGAO_GHOSTED)
|
||
|
{
|
||
|
pTreeCtrl->SetItemState(hItem, TVIS_CUT, TVIS_CUT);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pTreeCtrl->SetItemState(hItem, 0, TVIS_CUT);
|
||
|
}
|
||
|
|
||
|
UINT nImage; // assign proper overlay image (link, share)
|
||
|
if ((dwAttributes & SFGAO_LINK) && m_bShowShellLinkIcons)
|
||
|
{
|
||
|
nImage = INDEXTOOVERLAYMASK(2);
|
||
|
}
|
||
|
else
|
||
|
if (dwAttributes & SFGAO_SHARE)
|
||
|
{
|
||
|
nImage = INDEXTOOVERLAYMASK(1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nImage = 0; // no overlay
|
||
|
}
|
||
|
// NB: we use here TVIS_OVERLAYMASK (as for the tree control) though
|
||
|
// the list view control also calls this function and LVIS_OVERLAYMASK
|
||
|
// should be used in that case. Reason for that is both of them refer
|
||
|
// to results of INDEXTOOVERLAYMASK macro and hence they have to be the same,
|
||
|
// namely INDEXTOOVERLAYMASK(15)
|
||
|
pTreeCtrl->SetItemState(hItem, nImage, TVIS_OVERLAYMASK);
|
||
|
}
|
||
|
|
||
|
void CXTPShellPidl::MapShellFlagsToItemAttributes(CListCtrl* pListCtrl, int iItem, DWORD dwAttributes)
|
||
|
{
|
||
|
// Display with 'cut' feedback if the item is ghosted (about to be moved to a different location or a hidden one)
|
||
|
if (dwAttributes & SFGAO_GHOSTED)
|
||
|
{
|
||
|
pListCtrl->SetItemState(iItem, LVIS_CUT, LVIS_CUT);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pListCtrl->SetItemState(iItem, 0, LVIS_CUT);
|
||
|
}
|
||
|
|
||
|
UINT nImage; // assign proper overlay image (link, share)
|
||
|
if ((dwAttributes & SFGAO_LINK) && m_bShowShellLinkIcons)
|
||
|
{
|
||
|
nImage = INDEXTOOVERLAYMASK(2);
|
||
|
}
|
||
|
else
|
||
|
if (dwAttributes & SFGAO_SHARE)
|
||
|
{
|
||
|
nImage = INDEXTOOVERLAYMASK(1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nImage = 0; // no overlay
|
||
|
}
|
||
|
// NB: we use here TVIS_OVERLAYMASK (as for the tree control) though
|
||
|
// the list view control also calls this function and LVIS_OVERLAYMASK
|
||
|
// should be used in that case. Reason for that is both of them refer
|
||
|
// to results of INDEXTOOVERLAYMASK macro and hence they have to be the same,
|
||
|
// namely INDEXTOOVERLAYMASK(15)
|
||
|
pListCtrl->SetItemState(iItem, nImage, TVIS_OVERLAYMASK);
|
||
|
}
|