ciderpress/util/Pidl.cpp
2007-03-27 17:47:10 +00:00

351 lines
7.5 KiB
C++

/*
* CiderPress
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* PIDL utility functions.
*/
#include "StdAfx.h"
#include "Pidl.h"
/*
* ==========================================================================
* PIDL functions
* ==========================================================================
*/
/*
* Return the next item in the PIDL.
*
* "pidl->mkid.cb" will be zero at the end of the list.
*/
LPITEMIDLIST
Pidl::Next(LPCITEMIDLIST pidl)
{
LPSTR lpMem = (LPSTR)pidl;
lpMem += pidl->mkid.cb;
return (LPITEMIDLIST)lpMem;
}
/*
* Compute the size in bytes of a PIDL.
*/
UINT
Pidl::GetSize(LPCITEMIDLIST pidl)
{
UINT cbTotal = 0;
if (pidl) {
cbTotal += sizeof(pidl->mkid.cb); // Null terminator
while (pidl->mkid.cb) {
cbTotal += pidl->mkid.cb;
pidl = Next(pidl);
}
}
return cbTotal;
}
/*
* Allocate a PIDL of the specified size.
*/
LPITEMIDLIST
Pidl::CreatePidl(UINT cbSize)
{
LPMALLOC lpMalloc;
HRESULT hr;
LPITEMIDLIST pidl = NULL;
hr=SHGetMalloc(&lpMalloc);
if (FAILED(hr))
return 0;
pidl = (LPITEMIDLIST)lpMalloc->Alloc(cbSize);
if (pidl)
memset(pidl, 0, cbSize); // zero-init for external task alloc
if (lpMalloc) lpMalloc->Release();
return pidl;
}
/*
* Concatenates two PIDLs. The PIDL returned is newly-allocated storage.
*
* "pidl1" may be NULL.
*/
LPITEMIDLIST
Pidl::ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
LPITEMIDLIST pidlNew;
UINT cb1;
UINT cb2;
if (pidl1)
cb1 = GetSize(pidl1) - sizeof(pidl1->mkid.cb);
else
cb1 = 0;
cb2 = GetSize(pidl2);
pidlNew = CreatePidl(cb1 + cb2);
if (pidlNew) {
if (pidl1)
memcpy(pidlNew, pidl1, cb1);
memcpy(((LPSTR)pidlNew) + cb1, pidl2, cb2);
}
return pidlNew;
}
/*
* Make a copy of a PIDL.
*
* The PIDL returned is newly-allocated storage.
*/
LPITEMIDLIST
Pidl::CopyITEMID(LPMALLOC lpMalloc, LPITEMIDLIST lpi)
{
LPITEMIDLIST lpiTemp;
lpiTemp = (LPITEMIDLIST)lpMalloc->Alloc(lpi->mkid.cb + sizeof(lpi->mkid.cb));
CopyMemory((PVOID)lpiTemp, (CONST VOID *)lpi,
lpi->mkid.cb + sizeof(lpi->mkid.cb));
return lpiTemp;
}
/*
* Get the display name of a file in a ShellFolder.
*
* "lpsf" is the ShellFolder that contains the file, "lpi" is the PIDL for
* the file, "dwFlags" is passed to GetDisplayNameOf and affects which
* name is returned, and "lpFriendlyName" is a buffer of at least MAX_PATH
* bytes.
*/
BOOL
Pidl::GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi, DWORD dwFlags,
LPSTR lpFriendlyName)
{
BOOL bSuccess=TRUE;
STRRET str;
if (NOERROR == lpsf->GetDisplayNameOf(lpi, dwFlags, &str))
{
switch (str.uType) {
case STRRET_WSTR:
WideCharToMultiByte(CP_ACP, // CodePage
0, // dwFlags
str.pOleStr, // lpWideCharStr
-1, // cchWideChar
lpFriendlyName, // lpMultiByteStr
MAX_PATH, // cchMultiByte
NULL, // lpDefaultChar,
NULL); // lpUsedDefaultChar
//Once the the function returns, the wide string
//should be freed. CoTaskMemFree(str.pOleStr) seems
//to do the job as well.
LPMALLOC pMalloc;
SHGetMalloc(&pMalloc);
pMalloc->Free (str.pOleStr);
pMalloc->Release();
break;
case STRRET_OFFSET:
lstrcpy(lpFriendlyName, (LPSTR)lpi+str.uOffset);
break;
case STRRET_CSTR:
lstrcpy(lpFriendlyName, (LPSTR)str.cStr);
break;
default:
bSuccess = FALSE;
break;
}
}
else
bSuccess = FALSE;
return bSuccess;
}
/*
* Get a fully qualified PIDL for a ShellFolder.
*
* This is a rather roundabout way of doing things (converting to a full
* display name and then converting that to a PIDL). However, there doesn't
* seem to be a way to just ask a ShellFolder for its fully qualified PIDL.
*
* Pass in the parent ShellFolder and the item's partial PIDL.
*/
LPITEMIDLIST
Pidl::GetFullyQualPidl(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi)
{
char szBuff[MAX_PATH];
OLECHAR szOleChar[MAX_PATH];
LPSHELLFOLDER lpsfDeskTop;
LPITEMIDLIST lpifq;
ULONG ulEaten, ulAttribs;
HRESULT hr;
if (!GetName(lpsf, lpi, SHGDN_FORPARSING, szBuff))
return NULL;
hr = SHGetDesktopFolder(&lpsfDeskTop);
if (FAILED(hr))
return NULL;
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szBuff, -1,
(USHORT *)szOleChar, sizeof(szOleChar));
hr = lpsfDeskTop->ParseDisplayName(NULL, NULL, szOleChar,
&ulEaten, &lpifq, &ulAttribs);
lpsfDeskTop->Release();
if (FAILED(hr))
return NULL;
return lpifq;
}
/*
* Convert a PIDL to a filesystem path.
*
* Returns TRUE on success, FALSE on failure.
*/
BOOL
Pidl::GetPath(LPCITEMIDLIST pidl, CString* pPath)
{
BOOL result;
char buf[MAX_PATH];
result = SHGetPathFromIDList(pidl, buf);
if (result)
*pPath = buf;
return result;
}
#if 0
/****************************************************************************
*
* FUNCTION: DoTheMenuThing(HWND hwnd,
* LPSHELLFOLDER lpsfParent,
* LPITEMIDLIST lpi,
* LPPOINT lppt)
*
* PURPOSE: Displays a popup context menu, given a parent shell folder,
* relative item id and screen location.
*
* PARAMETERS:
* hwnd - Parent window handle
* lpsfParent - Pointer to parent shell folder.
* lpi - Pointer to item id that is relative to lpsfParent
* lppt - Screen location of where to popup the menu.
*
* RETURN VALUE:
* Returns TRUE on success, FALSE on failure
*
****************************************************************************/
BOOL
Pidl::DoTheMenuThing(HWND hwnd, LPSHELLFOLDER lpsfParent,
LPITEMIDLIST lpi, LPPOINT lppt)
{
LPCONTEXTMENU lpcm;
HRESULT hr;
char szTemp[64];
CMINVOKECOMMANDINFO cmi;
// DWORD dwAttribs=0;
int idCmd;
HMENU hMenu;
BOOL bSuccess=TRUE;
hr=lpsfParent->GetUIObjectOf(hwnd,
1, //Number of objects to get attributes of
(const struct _ITEMIDLIST **)&lpi,
IID_IContextMenu,
0,
(LPVOID *)&lpcm);
if (SUCCEEDED(hr))
{
hMenu = CreatePopupMenu();
if (hMenu)
{
hr=lpcm->QueryContextMenu(hMenu, 0, 1, 0x7fff, CMF_EXPLORE);
if (SUCCEEDED(hr))
{
idCmd=TrackPopupMenu(hMenu,
TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
lppt->x, lppt->y, 0, hwnd, NULL);
if (idCmd)
{
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
cmi.fMask = 0;
cmi.hwnd = hwnd;
cmi.lpVerb = MAKEINTRESOURCE(idCmd-1);
cmi.lpParameters = NULL;
cmi.lpDirectory = NULL;
cmi.nShow = SW_SHOWNORMAL;
cmi.dwHotKey = 0;
cmi.hIcon = NULL;
hr=lpcm->InvokeCommand(&cmi);
if (!SUCCEEDED(hr))
{
wsprintf(szTemp, "InvokeCommand failed. hr=%lx", hr);
AfxMessageBox(szTemp);
}
}
}
else
bSuccess = FALSE;
DestroyMenu(hMenu);
}
else
bSuccess = FALSE;
lpcm->Release();
}
else
{
wsprintf(szTemp, "GetUIObjectOf failed! hr=%lx", hr);
AfxMessageBox(szTemp );
bSuccess = FALSE;
}
return bSuccess;
}
#endif
/*
* Get the index for an icon for a ShellFolder object.
*
* "lpi" is the fully-qualified PIDL for the object in question. "uFlags"
* specifies which of the object's icons to retrieve.
*/
int
Pidl::GetItemIcon(LPITEMIDLIST lpi, UINT uFlags)
{
SHFILEINFO sfi;
uFlags |= SHGFI_PIDL;
SHGetFileInfo((LPCSTR)lpi, 0, &sfi, sizeof(SHFILEINFO), uFlags);
return sfi.iIcon;
}