/* * 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; }