update for HEAD-2003091401
[reactos.git] / subsys / system / explorer / Seashell / SeaShellExt / ShellPidl.cpp
diff --git a/subsys/system/explorer/Seashell/SeaShellExt/ShellPidl.cpp b/subsys/system/explorer/Seashell/SeaShellExt/ShellPidl.cpp
new file mode 100644 (file)
index 0000000..edeb863
--- /dev/null
@@ -0,0 +1,804 @@
+//*******************************************************************************
+// COPYRIGHT NOTES
+// ---------------
+// You may use this source code, compile or redistribute it as part of your application 
+// for free. You cannot redistribute it as a part of a software development 
+// library without the agreement of the author. If the sources are 
+// distributed along with the application, you should leave the original 
+// copyright notes in the source code without any changes.
+// This code can be used WITHOUT ANY WARRANTIES at your own risk.
+// 
+// For the latest updates to this code, check this site:
+// http://www.masmex.com 
+// after Sept 2000
+// 
+// Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
+//*******************************************************************************
+
+// ShellPidl.cpp: implementation of the CShellPidl class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "ShellPidl.h"
+#include "UIMessages.h"
+#include <intshcut.h>
+#include <subsmgr.h>
+#include <ExDisp.h>
+#include "ShellContextMenu.h"
+#include "UICoolMenu.h"
+#include "cbformats.h"
+
+#define SF_DRAGDROP_FLAGS SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK;
+UINT CF_IDLIST = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
+UINT CF_SHELLURL = RegisterClipboardFormat(CFSTR_SHELLURL);
+
+#define TPM_FLAGS               (TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD)
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CShellPidl::CShellPidl()
+{
+       SHGetMalloc(&m_pMalloc);
+    SHGetDesktopFolder(&m_psfDesktop);
+       ZeroMemory(&m_EmptyPidl,sizeof(ITEMIDLIST));
+}
+
+CShellPidl::~CShellPidl()
+{
+       if (m_pMalloc)
+               m_pMalloc->Release();
+       if (m_psfDesktop)
+               m_psfDesktop->Release();
+}
+
+IMalloc *CShellPidl::GetMalloc()
+{
+       return m_pMalloc;
+}
+
+DWORD CShellPidl::GetDragDropAttributes(LPLVITEMDATA plvid)
+{
+       return GetDragDropAttributes(plvid->lpsfParent,plvid->lpi);
+}
+
+DWORD CShellPidl::GetDragDropAttributes(LPTVITEMDATA ptvid)
+{
+       return GetDragDropAttributes(ptvid->lpsfParent,ptvid->lpi);
+}
+
+DWORD CShellPidl::GetDragDropAttributes(LPSHELLFOLDER pFolder,LPCITEMIDLIST pidl)
+{
+       if (pFolder == NULL)
+               pFolder = m_psfDesktop;
+       DWORD dwAttrs=SF_DRAGDROP_FLAGS;
+       HRESULT hr = pFolder->GetAttributesOf(1,(LPCITEMIDLIST*)&pidl,&dwAttrs);
+       if (FAILED(hr))
+               dwAttrs = SF_DRAGDROP_FLAGS;
+       return dwAttrs;
+}
+
+DWORD CShellPidl::GetDragDropAttributes(COleDataObject *pDataObject)
+{
+       IDataObject *pDataObj = pDataObject->m_lpDataObject;
+
+       STGMEDIUM stgm;
+       ZeroMemory(&stgm, sizeof(stgm));
+
+    FORMATETC fetc;
+    fetc.cfFormat = CF_IDLIST;
+    fetc.ptd = NULL;
+    fetc.dwAspect = DVASPECT_CONTENT;
+    fetc.lindex = -1;
+    fetc.tymed = TYMED_HGLOBAL;
+
+       DWORD dwAttrs=DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
+    HRESULT hr = pDataObj->QueryGetData(&fetc);
+       if (FAILED(hr))
+               return dwAttrs;
+    hr = pDataObj->GetData(&fetc, &stgm);
+       if (FAILED(hr))
+               return dwAttrs;
+    DWORD pData = (DWORD)GlobalLock(stgm.hGlobal);
+       LPIDA pIDList = (LPIDA)pData;
+       UINT nFolderOffset = pIDList->aoffset[0];
+       TRACE2("PIDL(%u) offfset=%u\n",0,nFolderOffset);
+       DWORD pFolder = pData+nFolderOffset;
+    LPITEMIDLIST pidl = (LPITEMIDLIST)pFolder;
+    LPSHELLFOLDER psfParent = GetFolder(pidl);
+       if (psfParent)
+       {
+               // get attributes for the children
+               TRACE1("PIDL count=%u\n",pIDList->cidl);
+               for(UINT i=1;i < (pIDList->cidl+1);i++)
+               {
+                       UINT nListOffset = pIDList->aoffset[i];
+                       TRACE2("PIDL(%u) offfset=%u\n",i,nListOffset);
+                       ULONG ulAttrs = SF_DRAGDROP_FLAGS;
+                       DWORD dwPidl = pData+nListOffset;
+                       LPITEMIDLIST pidlist = (LPITEMIDLIST)dwPidl;
+                       psfParent->GetAttributesOf(1,(LPCITEMIDLIST*)&pidlist,&ulAttrs);
+#ifdef _DEBUG
+                       CString sPath;
+                       SHPidlToPathEx(pidlist,sPath,psfParent);
+                       TRACE2("Drag drop source path=%s Attributes=%u\n",sPath,ulAttrs);
+#endif
+                       if (ulAttrs)
+                               dwAttrs = dwAttrs & ulAttrs;
+               }
+               psfParent->Release();
+       }
+       GlobalUnlock(stgm.hGlobal);
+    ReleaseStgMedium(&stgm);
+       return dwAttrs;
+}
+
+LPCITEMIDLIST CShellPidl::GetEmptyPidl()
+{
+       return &m_EmptyPidl;
+}
+
+bool CShellPidl::IsDesktopFolder(LPSHELLFOLDER psFolder)
+{
+       return psFolder == NULL || psFolder == m_psfDesktop;
+}
+
+LPSHELLFOLDER CShellPidl::GetDesktopFolder()
+{
+       return m_psfDesktop;
+}
+
+LPSHELLFOLDER CShellPidl::GetFolder(LPITEMIDLIST pidl)
+{
+       if (pidl == NULL || pidl->mkid.cb == 0)
+               return m_psfDesktop;
+       LPSHELLFOLDER pFolder=NULL;
+       if (FAILED(m_psfDesktop->BindToObject(pidl, 0, IID_IShellFolder,(LPVOID*)&pFolder)))
+               return NULL;
+       return pFolder;
+}
+
+// CopyItemID - creates an item identifier list containing the first 
+//     item identifier in the specified list. 
+// Returns a PIDL if successful, or NULL if out of memory. 
+LPITEMIDLIST CShellPidl::CopyItemID(LPITEMIDLIST pidl,int n) 
+{ 
+       // Get the size of the specified item identifier. 
+       ASSERT(pidl);
+       if (n == 0)
+       {
+               int cb = pidl->mkid.cb;
+               int nSize = cb + sizeof(pidl->mkid.cb);
+               // Allocate a new item identifier list. 
+               LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(nSize); 
+               ZeroMemory(pidlNew,nSize);
+               if (pidlNew == NULL) 
+                       return NULL; 
+               // Copy the specified item identifier. 
+               CopyMemory(pidlNew, pidl, nSize-sizeof(pidl->mkid.cb)); 
+               return pidlNew; 
+       }
+       else
+       {
+               LPITEMIDLIST pidl_index=NULL;
+               for(int i=0;i < n && pidl->mkid.cb;i++)
+               {
+                       pidl_index = pidl;
+                       pidl = Next(pidl);
+               }
+               return pidl_index ? CopyItemID(pidl_index,0) : NULL;
+       }
+       return NULL;
+}
+
+// Returns a PIDL if successful, or NULL if out of memory. 
+LPITEMIDLIST CShellPidl::CopyLastItemID(LPITEMIDLIST pidl) 
+{ 
+       // Get the size of the specified item identifier. 
+       ASSERT(pidl);
+    if (pidl == NULL)
+               return NULL;
+       LPITEMIDLIST last_pidl=pidl;
+    while (pidl->mkid.cb)
+    {
+               last_pidl = pidl;
+        pidl = Next(pidl);
+    }
+       if (last_pidl == NULL)
+               return NULL;
+       return CopyItemID(last_pidl);
+}
+
+// copies the absolute pidl up till n
+LPITEMIDLIST CShellPidl::CopyAbsItemID(LPITEMIDLIST pidl,int n) 
+{ 
+       // Get the size of the specified item identifier. 
+       ASSERT(pidl);
+    if (pidl == NULL)
+               return NULL;
+       LPITEMIDLIST first_pidl=NULL;
+       LPITEMIDLIST abs_pidl=NULL;
+       LPITEMIDLIST new_abs_pidl=NULL;
+    for(int i=0;i < n && pidl && pidl->mkid.cb;i++)
+    {
+               first_pidl = CopyItemID(pidl);
+               new_abs_pidl = ConcatPidl(abs_pidl,first_pidl);
+               if (abs_pidl)
+               {
+                       m_pMalloc->Free(abs_pidl);
+               }
+               abs_pidl = new_abs_pidl;
+               if (first_pidl)
+               {
+                       m_pMalloc->Free(first_pidl);
+               }
+        pidl = Next(pidl);
+    }
+       return new_abs_pidl;
+}
+
+// Makes a copy of an ITEMIDLIST 
+LPITEMIDLIST CShellPidl::CopyItemIDList(LPITEMIDLIST pidl) 
+{ 
+       // Allocate a new item identifier list. 
+       int nSize = GetSize(pidl);
+       LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(nSize); 
+       ZeroMemory(pidlNew,nSize);
+       if (pidlNew == NULL) 
+               return NULL; 
+       // Copy the specified item identifier. 
+       CopyMemory(pidlNew, pidl, nSize); 
+
+       return pidlNew; 
+}
+
+bool CShellPidl::CompareMemPidls(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2) 
+{ 
+       // Allocate a new item identifier list. 
+       if (pidl1 == NULL || pidl2 == NULL)
+               return false;
+       return memcmp(pidl1,pidl2,(size_t)GetSize(pidl1)) == 0;
+}
+
+// Returns true if lists are the same
+bool CShellPidl::ComparePidls(LPSHELLFOLDER pFolder,LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2) 
+{ 
+       // Allocate a new item identifier list. 
+       if (pFolder == NULL)
+               pFolder = GetDesktopFolder();
+       if (pidl1 == NULL || pidl2 == NULL)
+               return false;
+       return (short)pFolder->CompareIDs(0,pidl1,pidl2) == 0;
+}
+
+void CShellPidl::Free(void *pv)
+{
+       if (m_pMalloc)
+               m_pMalloc->Free(pv);
+}
+
+void CShellPidl::FreePidl(LPITEMIDLIST pidl)
+{
+       if (m_pMalloc)
+               m_pMalloc->Free(pidl);
+}
+
+UINT CShellPidl::GetCount(LPCITEMIDLIST pidl)
+{
+    UINT nCount = 0;
+    if (pidl)
+    {
+        while (pidl->mkid.cb)
+        {
+            pidl = Next(pidl);
+                       nCount++;
+        }
+    }
+    return nCount;
+}
+
+UINT CShellPidl::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;
+}
+
+LPITEMIDLIST CShellPidl::Next(LPCITEMIDLIST pidl)
+{
+   LPSTR lpMem=(LPSTR)pidl;
+
+   lpMem+=pidl->mkid.cb;
+
+   return (LPITEMIDLIST)lpMem;
+}
+
+LPITEMIDLIST CShellPidl::ConcatPidl(LPITEMIDLIST pidlDest,LPITEMIDLIST pidlSrc) 
+{ 
+       // Get the size of the specified item identifier. 
+    UINT cbDest=0;
+    UINT cbSrc=0;
+    if (pidlDest)  //May be NULL
+       cbDest = GetSize(pidlDest) - sizeof(pidlDest->mkid.cb);
+    cbSrc = GetSize(pidlSrc);
+
+       // Allocate a new item identifier list. 
+       LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(cbSrc+cbDest); 
+       if (pidlNew == NULL) 
+               return NULL; 
+       ZeroMemory(pidlNew,cbSrc+cbDest);
+       // Copy the specified item identifier. 
+       if (pidlDest)
+               CopyMemory(pidlNew, pidlDest, cbDest); 
+       CopyMemory(((USHORT*)(((LPBYTE)pidlNew)+cbDest)), pidlSrc, cbSrc); 
+
+       return pidlNew; 
+}
+
+int CShellPidl::GetIcon(LPITEMIDLIST lpi, UINT uFlags)
+{
+   SHFILEINFO    sfi;
+   ZeroMemory(&sfi,sizeof(sfi));
+   if (uFlags == 0)
+               uFlags |= (SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
+   uFlags |= SHGFI_PIDL;
+   SHGetFileInfo((LPCTSTR)lpi, 0, &sfi, sizeof(SHFILEINFO), uFlags);
+
+   return sfi.iIcon;
+}
+
+STDMETHODIMP CShellPidl::SHPidlToPathEx(LPCITEMIDLIST pidl, CString &sPath, LPSHELLFOLDER pFolder, DWORD dwFlags)
+{
+       STRRET StrRetFilePath;
+       LPTSTR pszFilePath = NULL;
+       HRESULT hr=E_FAIL;
+       if (pFolder == NULL)
+               pFolder = GetDesktopFolder();
+       if (pFolder == NULL)
+               return E_FAIL;
+       hr = pFolder->GetDisplayNameOf(pidl, dwFlags, &StrRetFilePath);
+       if (SUCCEEDED(hr))
+       {
+               StrRetToStr(StrRetFilePath, &pszFilePath, (LPITEMIDLIST)pidl);
+               sPath = pszFilePath;
+       }
+       if (pszFilePath)
+               m_pMalloc->Free(pszFilePath);
+       return hr;
+}
+
+STDMETHODIMP CShellPidl::SHPathToPidlEx(LPCTSTR szPath, LPITEMIDLIST* ppidl, LPSHELLFOLDER pFolder)
+{
+   OLECHAR wszPath[MAX_PATH] = {0};
+   ULONG nCharsParsed = 0;
+   LPSHELLFOLDER pShellFolder = NULL;
+   BOOL bFreeOnExit = FALSE;
+#ifdef UNICODE
+   lstrcpy(wszPath,szPath);
+#else
+   MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, -1, wszPath, MAX_PATH);
+#endif
+   // Use the desktop's IShellFolder by default
+   if(pFolder == NULL)
+   {
+      SHGetDesktopFolder(&pShellFolder);
+      bFreeOnExit = TRUE;
+   }
+   else
+      pShellFolder = pFolder;
+
+   HRESULT hr = pShellFolder->ParseDisplayName(NULL, NULL, wszPath, &nCharsParsed, ppidl, NULL);
+
+   if(bFreeOnExit)
+      pShellFolder->Release();
+
+   return hr;
+}
+
+void CShellPidl::GetTypeName(LPITEMIDLIST lpi,CString &sTypeName)
+{
+   SHFILEINFO    sfi;
+   ZeroMemory(&sfi,sizeof(sfi));
+   UINT uFlags = SHGFI_PIDL | SHGFI_TYPENAME;
+   SHGetFileInfo((LPCTSTR)lpi, 0, &sfi, sizeof(SHFILEINFO), uFlags);
+   sTypeName = sfi.szTypeName;
+}
+
+void CShellPidl::GetDisplayName(LPITEMIDLIST lpifq,CString &sDisplayName)
+{
+   SHFILEINFO    sfi;
+   ZeroMemory(&sfi,sizeof(sfi));
+   UINT uFlags = SHGFI_PIDL | SHGFI_DISPLAYNAME;
+   SHGetFileInfo((LPCTSTR)lpifq, 0, &sfi, sizeof(SHFILEINFO), uFlags);
+   sDisplayName = sfi.szDisplayName;
+}
+
+void CShellPidl::GetNormalAndSelectedIcons (
+   LPITEMIDLIST lpifq, int &iImage, int &iSelectedImage)
+{
+   // Don't check the return value here. 
+   // If IGetIcon() fails, you're in big trouble.
+   iImage = GetIcon (lpifq, 
+      SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
+   
+   iSelectedImage = GetIcon (lpifq, 
+      SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON);
+   
+   return;
+}
+
+BOOL CShellPidl::HandleMenuMsg(HWND hwnd, LPSHELLFOLDER lpsfParent,
+     LPITEMIDLIST  lpi, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    LPCONTEXTMENU lpcm=NULL;
+    HRESULT hr=lpsfParent->GetUIObjectOf(hwnd,
+        1,  // get attributes for this many objects
+        (const struct _ITEMIDLIST **)&lpi,
+        IID_IContextMenu,
+        0,
+        (LPVOID *)&lpcm);
+    if (SUCCEEDED(hr))  
+    {
+           LPCONTEXTMENU2 lpcm2=NULL;
+               hr = lpcm->QueryInterface(IID_IContextMenu2,(LPVOID*)&lpcm2);
+               lpcm->Release();
+               if (SUCCEEDED(hr))  
+           {
+                       lpcm2->HandleMenuMsg(uMsg,wParam,lParam);
+                       lpcm2->Release();
+               }
+               return TRUE;
+       }
+       return FALSE;
+}
+
+BOOL CShellPidl::PopupTheMenu(HWND hwnd, LPSHELLFOLDER lpsfParent,
+     LPITEMIDLIST  *plpi, UINT cidl, LPPOINT lppt)
+{
+       CMenu menu;
+    menu.CreatePopupMenu();
+       g_CoolMenuManager.Install(CWnd::FromHandle(hwnd));
+       CString sPath;
+       if (lpsfParent == NULL)
+               lpsfParent = GetDesktopFolder();
+       SHPidlToPathEx(*plpi,sPath,lpsfParent);
+       CShellContextMenu shell_menu(hwnd,sPath,plpi,cidl,lpsfParent);
+       shell_menu.SetMenu(&menu);
+    int idCmd = menu.TrackPopupMenu(TPM_FLAGS, lppt->x, lppt->y, CWnd::FromHandle(hwnd));
+       shell_menu.InvokeCommand(idCmd);
+       g_CoolMenuManager.Uninstall();
+       return TRUE;
+}
+
+/****************************************************************************
+*
+*    FUNCTION: GetName(LPSHELLFOLDER lpsf,LPITEMIDLIST  lpi,DWORD dwFlags,
+*             LPSTR         lpFriendlyName)
+*
+*    PURPOSE:  Gets the friendly name for the folder 
+*
+****************************************************************************/
+BOOL CShellPidl::GetName (LPSHELLFOLDER lpsf, LPITEMIDLIST lpi, 
+   DWORD dwFlags, CString &sFriendlyName)
+{
+   BOOL   bSuccess=TRUE;
+   STRRET str;
+
+   if (NOERROR==lpsf->GetDisplayNameOf(lpi,dwFlags, &str))
+   {
+      switch (str.uType)
+      {
+         case STRRET_WSTR:
+#ifdef UNICODE
+                        _tcscpy(sFriendlyName.GetBuffer(MAX_PATH),str.pOleStr);
+                        sFriendlyName.ReleaseBuffer();
+#else
+            WideCharToMultiByte(
+               CP_ACP,                 // code page
+               0,                             // dwFlags
+               str.pOleStr,            // lpWideCharStr
+               -1,                     // cchWideCharStr
+               sFriendlyName.GetBuffer(_MAX_PATH),         // lpMultiByteStr
+               _MAX_PATH, // cchMultiByte
+               NULL,                   // lpDefaultChar
+               NULL);                  // lpUsedDefaultChar
+#endif
+                       sFriendlyName.ReleaseBuffer();  
+             break;
+
+         case STRRET_OFFSET:
+             sFriendlyName = (LPTSTR)lpi+str.uOffset;
+             break;
+
+         case STRRET_CSTR:             
+             sFriendlyName = (LPTSTR)str.cStr;
+             break;
+
+         default:
+             bSuccess = FALSE;
+             break;
+      }
+   }
+   else
+      bSuccess = FALSE;
+
+   return bSuccess;
+}
+
+//
+// ResolveChannel: Resolves a Channel Shortcut to its URL
+//
+STDMETHODIMP CShellPidl::ResolveChannel(IShellFolder* pFolder, LPCITEMIDLIST pidl, LPTSTR* lpszURL)
+{
+   IShellLink* pShellLink;
+
+   *lpszURL = NULL;  // Assume failure
+
+   // Get a pointer to the IShellLink interface from the given folder
+   HRESULT hr = pFolder->GetUIObjectOf(NULL, 1, &pidl, IID_IShellLink, NULL, (LPVOID*)&pShellLink);
+   if (SUCCEEDED(hr))
+   {
+      LPITEMIDLIST pidlChannel;
+
+      // Convert the IShellLink pointer to a PIDL.
+      hr = pShellLink->GetIDList(&pidlChannel);
+      if (SUCCEEDED(hr))
+      {
+         IShellFolder* psfDesktop;
+
+         hr = SHGetDesktopFolder(&psfDesktop);
+         if (SUCCEEDED(hr))
+         {
+            STRRET strret;
+
+            hr = psfDesktop->GetDisplayNameOf(pidlChannel, 0, &strret);
+            if (SUCCEEDED(hr))
+                               StrRetToStr(strret, lpszURL, pidlChannel);
+
+            psfDesktop->Release();
+         }
+      }
+
+      pShellLink->Release();
+   }
+
+   return hr;
+}
+
+STDMETHODIMP CShellPidl::ResolveHistoryShortcut(LPSHELLFOLDER pFolder,LPCITEMIDLIST *ppidl,CString &sURL)
+{
+       HRESULT hr=E_FAIL;
+       IDataObject *pObj=NULL;
+       hr = pFolder->GetUIObjectOf(NULL, 1, ppidl, IID_IDataObject, NULL, (LPVOID*)&pObj);
+       if (SUCCEEDED(hr))
+       {
+               hr = GetURL(pObj,sURL);
+               pObj->Release();
+       }
+       return hr;
+}
+
+STDMETHODIMP CShellPidl::GetURL(IDataObject *pDataObj,CString &sURL)
+{
+       sURL.Empty();
+       STGMEDIUM stgm;
+       ZeroMemory(&stgm, sizeof(stgm));
+
+    FORMATETC fetc;
+    fetc.cfFormat = CF_SHELLURL;
+    fetc.ptd = NULL;
+    fetc.dwAspect = DVASPECT_CONTENT;
+    fetc.lindex = -1;
+    fetc.tymed = TYMED_HGLOBAL;
+
+    HRESULT hr = pDataObj->QueryGetData(&fetc);
+       if (FAILED(hr))
+               return hr;
+    hr = pDataObj->GetData(&fetc, &stgm);
+       if (FAILED(hr))
+               return hr;
+    LPCTSTR pData = (LPCTSTR)GlobalLock(stgm.hGlobal);
+       sURL = pData;
+       GlobalUnlock(stgm.hGlobal);
+    ReleaseStgMedium(&stgm);
+       return S_OK;
+}
+
+//
+// ResolveInternetShortcut: Resolves an Internet Shortcut to its URL
+//
+STDMETHODIMP CShellPidl::ResolveInternetShortcut(LPCTSTR lpszLinkFile, LPTSTR* lpszURL)
+{
+       IUniformResourceLocator* pUrlLink = NULL;
+
+       *lpszURL=NULL;
+
+       HRESULT hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
+                                                        IID_IUniformResourceLocator, (LPVOID*)&pUrlLink);
+       if (FAILED(hr))
+               return hr;
+
+       IPersistFile* pPersistFile = NULL;
+       hr = pUrlLink->QueryInterface(IID_IPersistFile, (LPVOID*)&pPersistFile);
+       if (SUCCEEDED(hr))
+       {
+                // Ensure that the string is Unicode. 
+                WORD wsz[MAX_PATH];  
+               #ifdef UNICODE
+                _tcscpy(wsz,lpszLinkFile);
+               #else
+                MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH);
+               #endif
+                // Load the Internet Shortcut from persistent storage.
+                hr = pPersistFile->Load(wsz, STGM_READ);
+                if (SUCCEEDED(hr))
+                {
+                       hr = pUrlLink->GetURL(lpszURL);
+                }
+                pPersistFile->Release();
+       }
+       pUrlLink->Release();
+
+       return hr;
+}  
+
+//
+// ResolveLink: Resolves a Shell Link to its actual folder location
+//
+STDMETHODIMP CShellPidl::ResolveLink(HWND hWnd,LPCTSTR lpszLinkFile, LPTSTR* lpszURL)
+{
+   IShellLink* pShellLink = NULL;
+
+   *lpszURL = NULL;   // Assume failure
+
+   HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+                                 IID_IShellLink, (LPVOID*)&pShellLink); 
+   if (SUCCEEDED(hr))
+   {
+      IPersistFile* pPersistFile = NULL;
+
+      hr = pShellLink->QueryInterface(IID_IPersistFile, (LPVOID*)&pPersistFile);
+      if (SUCCEEDED(hr))
+      {
+         // Ensure that the string is Unicode. 
+         WORD wsz[MAX_PATH];  
+#ifdef UNICODE
+                _tcscpy(wsz,lpszLinkFile);
+#else
+         MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH);
+#endif
+
+         // Load the shortcut.from persistent storage
+         hr = pPersistFile->Load(wsz, STGM_READ);
+         if (SUCCEEDED(hr))
+         {
+            WIN32_FIND_DATA wfd;      
+
+            hr = pShellLink->Resolve(hWnd, SLR_NO_UI); 
+            if (NOERROR == hr)
+            {
+               // Get the path to the link target. 
+                          *lpszURL = (LPTSTR)m_pMalloc->Alloc(MAX_PATH);  // Must remember to Free later
+
+               hr = pShellLink->GetPath(*lpszURL, MAX_PATH - 1, (WIN32_FIND_DATA*)&wfd, SLGP_UNCPRIORITY);
+            }
+         }
+
+         pPersistFile->Release();
+      }
+
+      pShellLink->Release();
+   }
+
+   return hr;
+}
+
+//
+// This method converts a STRRET structure to a LPTSTR
+//
+#ifdef UNICODE
+STDMETHODIMP CShellPidl::StrRetToStr(STRRET StrRet, LPTSTR* str, LPITEMIDLIST pidl)
+{
+       HRESULT hr = S_OK;
+       int cch;
+       LPSTR strOffset;
+
+       *str = NULL;  // Assume failure
+
+       switch (StrRet.uType)
+   {
+               case STRRET_WSTR: 
+                       cch = wcslen(StrRet.pOleStr) + 1; // NULL terminator
+                       *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));
+
+                       if (*str != NULL)
+                               lstrcpyn(*str, StrRet.pOleStr, cch);
+                       else
+                               hr = E_FAIL;
+                       break;
+
+               case STRRET_OFFSET: 
+                       strOffset = (((char *) pidl) + StrRet.uOffset);
+
+                       cch = MultiByteToWideChar(CP_OEMCP, 0, strOffset, -1, NULL, 0); 
+                       *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));
+
+                       if (*str != NULL)
+                               MultiByteToWideChar(CP_OEMCP, 0, strOffset, -1, *str, cch); 
+                       else
+                               hr = E_FAIL;
+                       break;
+
+               case STRRET_CSTR: 
+                       cch = MultiByteToWideChar(CP_OEMCP, 0, StrRet.cStr, -1, NULL, 0); 
+                       *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR)); 
+
+                       if (*str != NULL)
+                               MultiByteToWideChar(CP_OEMCP, 0, StrRet.cStr, -1, *str, cch); 
+                       else
+                               hr = E_FAIL;
+
+                       break;
+       } 
+       return hr;
+}
+#else // UNICODE not defined
+STDMETHODIMP CShellPidl::StrRetToStr(STRRET StrRet, LPTSTR* str, LPITEMIDLIST pidl)
+{
+
+       HRESULT hr = S_OK;
+       int cch;
+       LPSTR strOffset;
+
+       *str = NULL;  // Assume failure
+
+       switch (StrRet.uType)
+   {
+               case STRRET_WSTR: 
+                       cch = WideCharToMultiByte(CP_ACP, 0, StrRet.pOleStr, -1, NULL, 0, NULL, NULL); 
+                       *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR)); 
+
+                       if (*str != NULL)
+                               WideCharToMultiByte(CP_ACP, 0, StrRet.pOleStr, -1, *str, cch, NULL, NULL); 
+                       else
+                               hr = E_FAIL;
+                       break;
+
+               case STRRET_OFFSET: 
+                       strOffset = (((char *) pidl) + StrRet.uOffset);
+
+                       cch = strlen(strOffset) + 1; // NULL terminator
+                       *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));
+
+                       if (*str != NULL)
+                               strcpy(*str, strOffset);
+                       else
+                               hr = E_FAIL;
+                       break;
+
+               case STRRET_CSTR: 
+                       cch = strlen(StrRet.cStr) + 1; // NULL terminator
+                       *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));
+
+                       if (*str != NULL)
+                               strcpy(*str, StrRet.cStr);
+                       else
+                               hr = E_FAIL;
+
+                       break;
+       } 
+
+       return hr;
+}
+#endif