--- /dev/null
+//////////////////////////////////////\r
+// ShellWrapper.cpp\r
+\r
+#include "stdafx.h"\r
+#include "ShellWrapper.h"\r
+\r
+\r
+/////////////////////////////////////////////////////////////\r
+// Global function in the ShellWrapper namespace\r
+//\r
+\r
+namespace ShellWrapper\r
+{\r
+ ///////////////////////////////////\r
+ //global functionnct definitions (within this namespace)\r
+ BOOL GetFullFileName(LPCITEMIDLIST pidlFull, LPTSTR pszPathName)\r
+ {\r
+ if (!::SHGetPathFromIDList(pidlFull, pszPathName))\r
+ {\r
+ pszPathName[0] = _T('\0');\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ BOOL GetDisplayName(LPCITEMIDLIST pidlFull, LPTSTR pszDisplayName)\r
+ {\r
+ SHFILEINFO sfi;\r
+\r
+ // Get the display name of the item\r
+ if(!::SHGetFileInfo((LPCTSTR)pidlFull, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_DISPLAYNAME))\r
+ {\r
+ pszDisplayName[0] = _T('\0');\r
+ return FALSE;\r
+ }\r
+\r
+ ::lstrcpyn(pszDisplayName, sfi.szDisplayName, MAX_PATH -1);\r
+ return TRUE;\r
+ }\r
+\r
+\r
+ ///////////////////////////////////\r
+ //CContextMenu function definitions\r
+ CContextMenu::CContextMenu() : m_pIContextMenu(NULL)\r
+ {\r
+ }\r
+\r
+ CContextMenu::~CContextMenu()\r
+ {\r
+ if (m_pIContextMenu)\r
+ m_pIContextMenu->Release();\r
+ }\r
+\r
+ void CContextMenu::Attach(IContextMenu* pIContextMenu)\r
+ {\r
+ if (m_pIContextMenu)\r
+ m_pIContextMenu->Release();\r
+ m_pIContextMenu = pIContextMenu;\r
+ }\r
+\r
+ HRESULT CContextMenu::InvokeCommand(CMINVOKECOMMANDINFO& Ici)\r
+ {\r
+ HRESULT hr = m_pIContextMenu->InvokeCommand(&Ici);\r
+\r
+ if (hr != NOERROR)\r
+ {\r
+ TRACE(_T("CContextMenu::InvokeCommand failed\n"));\r
+ }\r
+ return hr;\r
+ }\r
+\r
+ HRESULT CContextMenu::QueryInterface(REFIID iid, CContextMenu2& ccm2)\r
+ {\r
+ HRESULT hr = 0;\r
+ if (IID_IContextMenu2 == iid)\r
+ {\r
+ IContextMenu2* pIContextMenu2 = NULL;\r
+ hr = m_pIContextMenu->QueryInterface(iid, (VOID**)&pIContextMenu2);\r
+ if (S_OK == hr)\r
+ ccm2.Attach(pIContextMenu2);\r
+ else\r
+ {\r
+ TRACE(_T("CContextMenu::QueryInterface failed\n"));\r
+ }\r
+ }\r
+ else\r
+ TRACE(_T("Not Implemented!\n"));\r
+\r
+ return hr;\r
+ }\r
+\r
+ HRESULT CContextMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)\r
+ {\r
+ HRESULT hr = m_pIContextMenu->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags) ;\r
+ if(hr & 0x80000000)\r
+ {\r
+ TRACE(_T("CContextMenu::QueryContextMenu failed\n"));\r
+ }\r
+ return hr;\r
+ }\r
+\r
+\r
+ ////////////////////////////////////\r
+ //CContextMenu2 function definitions\r
+ CContextMenu2::CContextMenu2() : m_pIContextMenu2(NULL)\r
+ {\r
+ }\r
+\r
+ CContextMenu2::~CContextMenu2()\r
+ {\r
+ if (m_pIContextMenu2)\r
+ m_pIContextMenu2->Release();\r
+ }\r
+\r
+ void CContextMenu2::Attach(IContextMenu2* pIContextMenu2)\r
+ {\r
+ if (m_pIContextMenu2)\r
+ m_pIContextMenu2->Release();\r
+ m_pIContextMenu2 = pIContextMenu2;\r
+ }\r
+\r
+ HRESULT CContextMenu2::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+ {\r
+ HRESULT hr = m_pIContextMenu2->HandleMenuMsg(uMsg, wParam, lParam);\r
+\r
+ if((hr != S_OK) && (hr !=E_NOTIMPL))\r
+ {\r
+ TRACE(_T("CContextMenu2::HandleMenuMsg failed\n"));\r
+ }\r
+\r
+ return hr;\r
+ }\r
+\r
+ void CContextMenu2::Release()\r
+ {\r
+ m_pIContextMenu2->Release();\r
+ m_pIContextMenu2 = 0;\r
+ }\r
+\r
+\r
+ ///////////////////////////////////\r
+ //CShellFolder function definitions\r
+ CShellFolder::CShellFolder() : m_IShellFolder(NULL)\r
+ {\r
+ }\r
+\r
+ CShellFolder::CShellFolder(const CShellFolder& csfSource) : m_IShellFolder(NULL)\r
+ {\r
+ Copy(csfSource);\r
+ }\r
+\r
+ void CShellFolder::operator=(const CShellFolder& csfSource)\r
+ {\r
+ Copy(csfSource);\r
+ }\r
+\r
+ CShellFolder::~CShellFolder()\r
+ {\r
+ Delete();\r
+ }\r
+\r
+ void CShellFolder::Attach(LPSHELLFOLDER IShellFolder)\r
+ //Converts SHELLFOLDER pointer to a CShellFolder object.\r
+ //The memory allocated for the SHELLFOLDER pointer is released\r
+ // in the destructor\r
+ {\r
+ Delete();\r
+ m_IShellFolder = IShellFolder;\r
+ }\r
+\r
+ HRESULT CShellFolder::BindToObject(const Cpidl& cpidl, LPBC pbc, REFIID riid, CShellFolder& NewFolder)\r
+ {\r
+ LPSHELLFOLDER FolderTemp;\r
+ LPITEMIDLIST pidl = cpidl.GetPidl();\r
+\r
+ HRESULT hr = m_IShellFolder->BindToObject(pidl, pbc, riid, (VOID**)&FolderTemp);\r
+ if(S_OK == hr)\r
+ NewFolder.Attach(FolderTemp);\r
+ else\r
+ {\r
+ TRACE(_T("CShellFolder::BindToObject failed\n"));\r
+ }\r
+\r
+ return hr;\r
+ }\r
+\r
+ HRESULT CShellFolder::CompareIDs(LPARAM lParam, const Cpidl& cpidl1, const Cpidl& cpidl2)\r
+ {\r
+ LPITEMIDLIST pidl1 = cpidl1.GetPidl();\r
+ LPITEMIDLIST pidl2 = cpidl2.GetPidl();\r
+ return m_IShellFolder->CompareIDs(lParam, pidl1, pidl2);\r
+ }\r
+\r
+ void CShellFolder::Copy(LPSHELLFOLDER Source)\r
+ //Assigns the value to the CShellFolder object.\r
+ {\r
+ Delete(); //Release the current m_IShellFolder\r
+ m_IShellFolder = Source;\r
+ if (Source) \r
+ AddRef();\r
+ }\r
+\r
+ void CShellFolder::Copy(const CShellFolder& Source)\r
+ //Assigns the value to the CShellFolder object.\r
+ {\r
+ Delete(); //Release the current m_IShellFolder\r
+ m_IShellFolder = Source.m_IShellFolder;\r
+ if (Source.m_IShellFolder)\r
+ AddRef();\r
+ }\r
+\r
+ HRESULT CShellFolder::CreateViewObject(HWND hwnd, REFIID riid, CContextMenu& ccm)\r
+ {\r
+ IContextMenu* pcm;\r
+ HRESULT hr = m_IShellFolder->CreateViewObject(hwnd, riid, (LPVOID*)&pcm);\r
+ if (S_OK == hr)\r
+ ccm.Attach(pcm);\r
+ else\r
+ {\r
+ TRACE(_T("CShellFolder::CreateViewObject failed\n"));\r
+ }\r
+ return hr;\r
+ }\r
+\r
+ HRESULT CShellFolder::EnumObjects(HWND hwndOwner, int grfFlags, CEnumIDList& cenumIDList)\r
+ {\r
+ LPENUMIDLIST pEnum;\r
+ HRESULT hr = 0;\r
+ if (m_IShellFolder)\r
+ {\r
+ hr = m_IShellFolder->EnumObjects(hwndOwner, grfFlags, &pEnum);\r
+ if (S_OK == hr)\r
+ cenumIDList.Attach(pEnum);\r
+ else\r
+ TRACE(_T("CShellFolder::EnumObjects failed\n"));\r
+ }\r
+ else\r
+ TRACE(_T("CShellFolder::EnumObjects failed\n"));\r
+\r
+ return hr;\r
+ }\r
+\r
+ HRESULT CShellFolder::GetAttributesOf(UINT cidl, const Cpidl& cpidl, ULONG& rgfInOut)\r
+ {\r
+ LPCITEMIDLIST pidl = cpidl.GetPidl();\r
+ HRESULT hr = m_IShellFolder->GetAttributesOf(cidl, &pidl, &rgfInOut);\r
+\r
+ if (hr != S_OK)\r
+ {\r
+ TRACE(_T("CShellFolder::GetAttributesOf failed\n"));\r
+ }\r
+ return hr;\r
+ }\r
+\r
+ HRESULT CShellFolder::SHGetDesktopFolder()\r
+ {\r
+ HRESULT hr = ::SHGetDesktopFolder(&m_IShellFolder);\r
+\r
+ if (hr != NOERROR)\r
+ {\r
+ TRACE(_T("CShellFolder::SHGetDesktopFolder failed\n"));\r
+ }\r
+ return hr;\r
+ }\r
+\r
+ HRESULT CShellFolder::GetUIObjectOf(HWND hwndOwner, UINT nItems, Cpidl* cpidlArray, REFIID riid, UINT rgfReserved, CContextMenu& cm)\r
+ //cpidlArray is either an array of Cpidl or a pointer to a single Cpidl\r
+ {\r
+ LPCITEMIDLIST* pPidlArray;\r
+ pPidlArray = (LPCITEMIDLIST*)::CoTaskMemAlloc(sizeof(LPITEMIDLIST) * nItems);\r
+ if(!pPidlArray) return 0;\r
+\r
+ for(UINT i = 0; i < nItems; i++)\r
+ pPidlArray[i] = cpidlArray[i].GetPidl();\r
+\r
+ IContextMenu* ppv;\r
+ HRESULT hr = m_IShellFolder->GetUIObjectOf(hwndOwner, nItems, pPidlArray, riid, &rgfReserved, (VOID**)&ppv);\r
+\r
+ if (S_OK == hr)\r
+ cm.Attach(ppv);\r
+ else\r
+ {\r
+ TRACE(_T("CShellFolder::GetUIObjectOf failed\n"));\r
+ }\r
+\r
+ CoTaskMemFree(pPidlArray);\r
+ return hr;\r
+ }\r
+\r
+ //Deletes the memory allocated for m_IShellFolder (if any)\r
+ void CShellFolder::Delete()\r
+ {\r
+ if (m_IShellFolder)\r
+ m_IShellFolder->Release();\r
+ m_IShellFolder = NULL;\r
+ }\r
+\r
+\r
+ //////////////////////////////////\r
+ //CEnumIDList function definitions\r
+ CEnumIDList::CEnumIDList() : m_pEnumIDList(NULL)\r
+ {\r
+ }\r
+\r
+ CEnumIDList::~CEnumIDList()\r
+ {\r
+ if (m_pEnumIDList)\r
+ m_pEnumIDList->Release();\r
+ }\r
+\r
+ //Converts a LPENUMIDLIST to a CEnumIDList object.\r
+ // The destructor will release memory allocated for the LPENUMIDLIST\r
+ void CEnumIDList::Attach(LPENUMIDLIST EnumList)\r
+ {\r
+ m_pEnumIDList = EnumList;\r
+ }\r
+\r
+ HRESULT CEnumIDList::Next(ULONG Elements, Cpidl& cpidl, ULONG& ulFetched)\r
+ {\r
+ LPITEMIDLIST pidl;\r
+ if (m_pEnumIDList)\r
+ {\r
+ HRESULT hr = m_pEnumIDList->Next(Elements, &pidl, &ulFetched);\r
+ if (NOERROR == hr)\r
+ cpidl.Attach(pidl);\r
+\r
+ if ((NOERROR != hr) && (S_FALSE != hr))\r
+ {\r
+ TRACE(_T("CEnumIDList::Next failed\n"));\r
+ }\r
+ return hr;\r
+ }\r
+ else\r
+ return S_FALSE;\r
+ }\r
+\r
+ //Cpidl function definitions\r
+ Cpidl::Cpidl() : m_pidl(NULL), m_pidlParent(NULL)\r
+ {\r
+ ::SHGetMalloc(&m_pMalloc);\r
+ }\r
+\r
+ Cpidl::Cpidl(const Cpidl& cpidlSource) : m_pidl(NULL), m_pidlParent(NULL)\r
+ {\r
+ ::SHGetMalloc(&m_pMalloc);\r
+ Copy(cpidlSource);\r
+ }\r
+\r
+ void Cpidl::operator= (const Cpidl& cpidlSource)\r
+ {\r
+ Copy(cpidlSource);\r
+ }\r
+\r
+ BOOL Cpidl::operator== (const Cpidl& cpidl)\r
+ {\r
+ return IsEqual(cpidl);\r
+ }\r
+\r
+ const Cpidl operator+ (const Cpidl& cpidlFull, const Cpidl& cpidlRel)\r
+ {\r
+ //Appends cpidlRel to cpidlFull.\r
+ //The order of the cpidls DOES matter.\r
+ //The fully qualified cpidl must come first.\r
+ Cpidl Temp;\r
+ Temp.Concatenate(cpidlFull, cpidlRel);\r
+ return Temp;\r
+ }\r
+\r
+ Cpidl::~Cpidl()\r
+ {\r
+ Delete();\r
+ if (m_pidlParent)\r
+ m_pMalloc->Free(m_pidlParent);\r
+\r
+ m_pMalloc->Release();\r
+ }\r
+\r
+ void Cpidl::Attach(LPCITEMIDLIST pidl)\r
+ //Converts a ITEMIDLIST pointer to a Cpidl object\r
+ //The memory allocated for the original pidl will be released\r
+ // in the destructor\r
+ {\r
+ Delete(); //Release the memory for m_pidl\r
+ m_pidl = (LPITEMIDLIST)pidl;\r
+ }\r
+\r
+ void Cpidl::Delete()\r
+ {\r
+ if (m_pidl)\r
+ m_pMalloc->Free(m_pidl);\r
+ m_pidl = NULL;\r
+ }\r
+\r
+ HRESULT Cpidl::SHGetSpecialFolderLocation(HWND hwnd, int csidl)\r
+ {\r
+ Delete(); //Release the memory for m_pidl\r
+ HRESULT hr = ::SHGetSpecialFolderLocation(hwnd, csidl, &m_pidl);\r
+ if (hr != S_OK)\r
+ {\r
+ TRACE(_T("Cpidl::SHGetSpecialFolderLocation failed\n"));\r
+ }\r
+ return hr;\r
+ }\r
+\r
+ DWORD_PTR Cpidl::SHGetFileInfo(DWORD dwFileAttributes, SHFILEINFO& sfi, UINT uFlags)\r
+ {\r
+ LPITEMIDLIST pidl = m_pidl;\r
+ return (DWORD_PTR)::SHGetFileInfo((LPCTSTR)pidl, dwFileAttributes, &sfi, sizeof(SHFILEINFO), uFlags);\r
+ }\r
+\r
+ void Cpidl::Copy(const Cpidl& cpidlSource)\r
+ //The Cpidl object stores a copy of the pidlSource's m_pidl.\r
+ {\r
+ Copy(cpidlSource.GetPidl());\r
+ }\r
+\r
+ void Cpidl::Copy(LPCITEMIDLIST pidlSource)\r
+ //The Cpidl object stores a copy of the pidlSource. The memory allocated to\r
+ // pidlSource is NOT released.\r
+ {\r
+ UINT cbSource;\r
+ Delete(); //Release the memory for m_pidl\r
+\r
+ if(NULL == pidlSource) return;\r
+\r
+ //Allocate memory for m_pidl\r
+ cbSource = GetSize(pidlSource);\r
+ m_pidl = (LPITEMIDLIST)m_pMalloc->Alloc(cbSource);\r
+ if (!m_pidl) return;\r
+\r
+ ::CopyMemory(m_pidl, pidlSource, cbSource);\r
+ }\r
+\r
+ LPITEMIDLIST Cpidl::GetParent()\r
+ {\r
+ // Delete m_pidlParent\r
+ UINT nSize = GetSize(m_pidl);\r
+ if (m_pidlParent)\r
+ m_pMalloc->Free(m_pidlParent);\r
+ m_pidlParent = NULL;\r
+\r
+ // Make sure it's a valid PIDL.\r
+ if (NULL == m_pidl)\r
+ return(NULL);\r
+\r
+ // Copy m_pidl to m_pidlParent\r
+ m_pidlParent = (LPITEMIDLIST)m_pMalloc->Alloc(nSize);\r
+ if (!m_pidlParent)\r
+ return NULL;\r
+\r
+ ::CopyMemory(m_pidlParent, m_pidl, nSize);\r
+\r
+ // Identify the last item's position\r
+ if (m_pidlParent->mkid.cb)\r
+ {\r
+ LPITEMIDLIST pidlNext = m_pidlParent;\r
+ LPITEMIDLIST pidlTemp = m_pidlParent;\r
+\r
+ while (pidlNext->mkid.cb)\r
+ {\r
+ pidlTemp = pidlNext;\r
+ pidlNext = GetNextItem(pidlTemp);\r
+ }\r
+ // Remove the last item, set it's size to 0.\r
+ pidlTemp->mkid.cb = 0;\r
+ }\r
+ return m_pidlParent;\r
+ }\r
+\r
+ LPITEMIDLIST Cpidl::GetRelative()\r
+ //Stores a copy of the relative pidl obtained from a fully qualified pidl source.\r
+ {\r
+ if(NULL == m_pidl) return NULL;\r
+\r
+ LPITEMIDLIST pidlNext = m_pidl;\r
+ LPITEMIDLIST pidlRel = m_pidl;\r
+\r
+ while( pidlNext->mkid.cb )\r
+ {\r
+ pidlNext = GetNextItem(pidlNext);\r
+ if (pidlNext->mkid.cb)\r
+ pidlRel = (LPITEMIDLIST)pidlNext;\r
+ }\r
+\r
+ UINT nPos = GetSize(m_pidl) - GetSize(pidlRel);\r
+ return (LPITEMIDLIST)((LPBYTE)m_pidl + nPos);\r
+ }\r
+\r
+ void Cpidl::Concatenate(const Cpidl& cpidlParent, const Cpidl& cpidlRel)\r
+ //Creates a new Cpidl object by concatenating (chain together)\r
+ // a parent and relative Cpidl.\r
+ {\r
+ Concatenate(cpidlParent.GetPidl(), cpidlRel.GetPidl());\r
+ }\r
+\r
+ void Cpidl::Concatenate(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlRel)\r
+ //Create a new fully qualified Cpidl object from a Parent pidl\r
+ // and a relative pidl.\r
+ {\r
+ UINT cb1 = 0;\r
+ UINT cb2;\r
+\r
+ Delete(); //Release the current m_pidl\r
+\r
+ if (!pidlRel) return; //pidlRel should not be NULL\r
+\r
+ // Calculate the size of pidlParent without the two bytes of NULL terminator.\r
+ // This size can be zero if pidlParent points to the desktop.\r
+ if(pidlParent)\r
+ cb1 = GetSize(pidlParent) - (2 * sizeof(BYTE));\r
+\r
+ cb2 = GetSize(pidlRel);\r
+\r
+ // Create a new ITEMIDLIST that is the size of both pidlParent and pidlRel,\r
+ // then copy pidlParent and pidlRel to the new list.\r
+ m_pidl = (LPITEMIDLIST)m_pMalloc->Alloc(cb1 + cb2);\r
+ if (m_pidl)\r
+ {\r
+ ::ZeroMemory(m_pidl, cb1 + cb2);\r
+ if (pidlParent)\r
+ ::CopyMemory(m_pidl, pidlParent, cb1);\r
+\r
+ ::CopyMemory(((LPBYTE)m_pidl) + cb1, pidlRel, cb2);\r
+ }\r
+ }\r
+\r
+ UINT Cpidl::GetSize(LPCITEMIDLIST pidl)\r
+ {\r
+ UINT cbTotal = 0;\r
+ if (!pidl) return 0;\r
+\r
+ while(pidl)\r
+ {\r
+ cbTotal += pidl->mkid.cb;\r
+ pidl = GetNextItem(pidl);\r
+ }\r
+\r
+ // Requires a 16 bit zero value for the NULL terminator\r
+ cbTotal += 2 * sizeof(BYTE);\r
+\r
+ return cbTotal;\r
+ }\r
+\r
+ LPITEMIDLIST Cpidl::GetNextItem(LPCITEMIDLIST pidl)\r
+ {\r
+ // Check for valid pidl.\r
+ if(NULL == pidl)\r
+ return NULL;\r
+\r
+ // Get the size of the specified item identifier.\r
+ int cb = pidl->mkid.cb;\r
+\r
+ // If the size is zero, it is the end of the list.\r
+ if (0 == cb)\r
+ return NULL;\r
+\r
+ // Add cb to pidl (casting to increment by bytes).\r
+ return (LPITEMIDLIST) (((LPBYTE) pidl) + cb);\r
+ }\r
+\r
+ BOOL Cpidl::IsEqual(const Cpidl &cpidl)\r
+ {\r
+ CShellFolder sf;\r
+ sf.SHGetDesktopFolder();\r
+ return (0 == sf.CompareIDs(0, *this, cpidl) );\r
+ }\r
+}\r