This commit was manufactured by cvs2svn to create branch 'captive'.
[reactos.git] / subsys / system / explorer / Seashell / SeaShellExt / ShellPidl.cpp
1 //*******************************************************************************
2 // COPYRIGHT NOTES
3 // ---------------
4 // You may use this source code, compile or redistribute it as part of your application 
5 // for free. You cannot redistribute it as a part of a software development 
6 // library without the agreement of the author. If the sources are 
7 // distributed along with the application, you should leave the original 
8 // copyright notes in the source code without any changes.
9 // This code can be used WITHOUT ANY WARRANTIES at your own risk.
10 // 
11 // For the latest updates to this code, check this site:
12 // http://www.masmex.com 
13 // after Sept 2000
14 // 
15 // Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
16 //*******************************************************************************
17
18 // ShellPidl.cpp: implementation of the CShellPidl class.
19 //
20 //////////////////////////////////////////////////////////////////////
21
22 #include "stdafx.h"
23 #include "ShellPidl.h"
24 #include "UIMessages.h"
25 #include <intshcut.h>
26 #include <subsmgr.h>
27 #include <ExDisp.h>
28 #include "ShellContextMenu.h"
29 #include "UICoolMenu.h"
30 #include "cbformats.h"
31
32 #define SF_DRAGDROP_FLAGS SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK;
33 UINT CF_IDLIST = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
34 UINT CF_SHELLURL = RegisterClipboardFormat(CFSTR_SHELLURL);
35
36 #define TPM_FLAGS               (TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD)
37
38 //////////////////////////////////////////////////////////////////////
39 // Construction/Destruction
40 //////////////////////////////////////////////////////////////////////
41
42 CShellPidl::CShellPidl()
43 {
44         SHGetMalloc(&m_pMalloc);
45     SHGetDesktopFolder(&m_psfDesktop);
46         ZeroMemory(&m_EmptyPidl,sizeof(ITEMIDLIST));
47 }
48
49 CShellPidl::~CShellPidl()
50 {
51         if (m_pMalloc)
52                 m_pMalloc->Release();
53         if (m_psfDesktop)
54                 m_psfDesktop->Release();
55 }
56
57 IMalloc *CShellPidl::GetMalloc()
58 {
59         return m_pMalloc;
60 }
61
62 DWORD CShellPidl::GetDragDropAttributes(LPLVITEMDATA plvid)
63 {
64         return GetDragDropAttributes(plvid->lpsfParent,plvid->lpi);
65 }
66
67 DWORD CShellPidl::GetDragDropAttributes(LPTVITEMDATA ptvid)
68 {
69         return GetDragDropAttributes(ptvid->lpsfParent,ptvid->lpi);
70 }
71
72 DWORD CShellPidl::GetDragDropAttributes(LPSHELLFOLDER pFolder,LPCITEMIDLIST pidl)
73 {
74         if (pFolder == NULL)
75                 pFolder = m_psfDesktop;
76         DWORD dwAttrs=SF_DRAGDROP_FLAGS;
77         HRESULT hr = pFolder->GetAttributesOf(1,(LPCITEMIDLIST*)&pidl,&dwAttrs);
78         if (FAILED(hr))
79                 dwAttrs = SF_DRAGDROP_FLAGS;
80         return dwAttrs;
81 }
82
83 DWORD CShellPidl::GetDragDropAttributes(COleDataObject *pDataObject)
84 {
85         IDataObject *pDataObj = pDataObject->m_lpDataObject;
86
87         STGMEDIUM stgm;
88         ZeroMemory(&stgm, sizeof(stgm));
89
90     FORMATETC fetc;
91     fetc.cfFormat = CF_IDLIST;
92     fetc.ptd = NULL;
93     fetc.dwAspect = DVASPECT_CONTENT;
94     fetc.lindex = -1;
95     fetc.tymed = TYMED_HGLOBAL;
96
97         DWORD dwAttrs=DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
98     HRESULT hr = pDataObj->QueryGetData(&fetc);
99         if (FAILED(hr))
100                 return dwAttrs;
101     hr = pDataObj->GetData(&fetc, &stgm);
102         if (FAILED(hr))
103                 return dwAttrs;
104     DWORD pData = (DWORD)GlobalLock(stgm.hGlobal);
105         LPIDA pIDList = (LPIDA)pData;
106         UINT nFolderOffset = pIDList->aoffset[0];
107         TRACE2("PIDL(%u) offfset=%u\n",0,nFolderOffset);
108         DWORD pFolder = pData+nFolderOffset;
109     LPITEMIDLIST pidl = (LPITEMIDLIST)pFolder;
110     LPSHELLFOLDER psfParent = GetFolder(pidl);
111         if (psfParent)
112         {
113                 // get attributes for the children
114                 TRACE1("PIDL count=%u\n",pIDList->cidl);
115                 for(UINT i=1;i < (pIDList->cidl+1);i++)
116                 {
117                         UINT nListOffset = pIDList->aoffset[i];
118                         TRACE2("PIDL(%u) offfset=%u\n",i,nListOffset);
119                         ULONG ulAttrs = SF_DRAGDROP_FLAGS;
120                         DWORD dwPidl = pData+nListOffset;
121                         LPITEMIDLIST pidlist = (LPITEMIDLIST)dwPidl;
122                         psfParent->GetAttributesOf(1,(LPCITEMIDLIST*)&pidlist,&ulAttrs);
123 #ifdef _DEBUG
124                         CString sPath;
125                         SHPidlToPathEx(pidlist,sPath,psfParent);
126                         TRACE2("Drag drop source path=%s Attributes=%u\n",sPath,ulAttrs);
127 #endif
128                         if (ulAttrs)
129                                 dwAttrs = dwAttrs & ulAttrs;
130                 }
131                 psfParent->Release();
132         }
133         GlobalUnlock(stgm.hGlobal);
134     ReleaseStgMedium(&stgm);
135         return dwAttrs;
136 }
137
138 LPCITEMIDLIST CShellPidl::GetEmptyPidl()
139 {
140         return &m_EmptyPidl;
141 }
142
143 bool CShellPidl::IsDesktopFolder(LPSHELLFOLDER psFolder)
144 {
145         return psFolder == NULL || psFolder == m_psfDesktop;
146 }
147
148 LPSHELLFOLDER CShellPidl::GetDesktopFolder()
149 {
150         return m_psfDesktop;
151 }
152
153 LPSHELLFOLDER CShellPidl::GetFolder(LPITEMIDLIST pidl)
154 {
155         if (pidl == NULL || pidl->mkid.cb == 0)
156                 return m_psfDesktop;
157         LPSHELLFOLDER pFolder=NULL;
158         if (FAILED(m_psfDesktop->BindToObject(pidl, 0, IID_IShellFolder,(LPVOID*)&pFolder)))
159                 return NULL;
160         return pFolder;
161 }
162
163 // CopyItemID - creates an item identifier list containing the first 
164 //     item identifier in the specified list. 
165 // Returns a PIDL if successful, or NULL if out of memory. 
166 LPITEMIDLIST CShellPidl::CopyItemID(LPITEMIDLIST pidl,int n) 
167
168         // Get the size of the specified item identifier. 
169         ASSERT(pidl);
170         if (n == 0)
171         {
172                 int cb = pidl->mkid.cb;
173                 int nSize = cb + sizeof(pidl->mkid.cb);
174                 // Allocate a new item identifier list. 
175                 LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(nSize); 
176                 ZeroMemory(pidlNew,nSize);
177                 if (pidlNew == NULL) 
178                         return NULL; 
179                 // Copy the specified item identifier. 
180                 CopyMemory(pidlNew, pidl, nSize-sizeof(pidl->mkid.cb)); 
181                 return pidlNew; 
182         }
183         else
184         {
185                 LPITEMIDLIST pidl_index=NULL;
186                 for(int i=0;i < n && pidl->mkid.cb;i++)
187                 {
188                         pidl_index = pidl;
189                         pidl = Next(pidl);
190                 }
191                 return pidl_index ? CopyItemID(pidl_index,0) : NULL;
192         }
193         return NULL;
194 }
195
196 // Returns a PIDL if successful, or NULL if out of memory. 
197 LPITEMIDLIST CShellPidl::CopyLastItemID(LPITEMIDLIST pidl) 
198
199         // Get the size of the specified item identifier. 
200         ASSERT(pidl);
201     if (pidl == NULL)
202                 return NULL;
203         LPITEMIDLIST last_pidl=pidl;
204     while (pidl->mkid.cb)
205     {
206                 last_pidl = pidl;
207         pidl = Next(pidl);
208     }
209         if (last_pidl == NULL)
210                 return NULL;
211         return CopyItemID(last_pidl);
212 }
213
214 // copies the absolute pidl up till n
215 LPITEMIDLIST CShellPidl::CopyAbsItemID(LPITEMIDLIST pidl,int n) 
216
217         // Get the size of the specified item identifier. 
218         ASSERT(pidl);
219     if (pidl == NULL)
220                 return NULL;
221         LPITEMIDLIST first_pidl=NULL;
222         LPITEMIDLIST abs_pidl=NULL;
223         LPITEMIDLIST new_abs_pidl=NULL;
224     for(int i=0;i < n && pidl && pidl->mkid.cb;i++)
225     {
226                 first_pidl = CopyItemID(pidl);
227                 new_abs_pidl = ConcatPidl(abs_pidl,first_pidl);
228                 if (abs_pidl)
229                 {
230                         m_pMalloc->Free(abs_pidl);
231                 }
232                 abs_pidl = new_abs_pidl;
233                 if (first_pidl)
234                 {
235                         m_pMalloc->Free(first_pidl);
236                 }
237         pidl = Next(pidl);
238     }
239         return new_abs_pidl;
240 }
241
242 // Makes a copy of an ITEMIDLIST 
243 LPITEMIDLIST CShellPidl::CopyItemIDList(LPITEMIDLIST pidl) 
244
245         // Allocate a new item identifier list. 
246         int nSize = GetSize(pidl);
247         LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(nSize); 
248         ZeroMemory(pidlNew,nSize);
249         if (pidlNew == NULL) 
250                 return NULL; 
251         // Copy the specified item identifier. 
252         CopyMemory(pidlNew, pidl, nSize); 
253
254         return pidlNew; 
255 }
256
257 bool CShellPidl::CompareMemPidls(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2) 
258
259         // Allocate a new item identifier list. 
260         if (pidl1 == NULL || pidl2 == NULL)
261                 return false;
262         return memcmp(pidl1,pidl2,(size_t)GetSize(pidl1)) == 0;
263 }
264
265 // Returns true if lists are the same
266 bool CShellPidl::ComparePidls(LPSHELLFOLDER pFolder,LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2) 
267
268         // Allocate a new item identifier list. 
269         if (pFolder == NULL)
270                 pFolder = GetDesktopFolder();
271         if (pidl1 == NULL || pidl2 == NULL)
272                 return false;
273         return (short)pFolder->CompareIDs(0,pidl1,pidl2) == 0;
274 }
275
276 void CShellPidl::Free(void *pv)
277 {
278         if (m_pMalloc)
279                 m_pMalloc->Free(pv);
280 }
281
282 void CShellPidl::FreePidl(LPITEMIDLIST pidl)
283 {
284         if (m_pMalloc)
285                 m_pMalloc->Free(pidl);
286 }
287
288 UINT CShellPidl::GetCount(LPCITEMIDLIST pidl)
289 {
290     UINT nCount = 0;
291     if (pidl)
292     {
293         while (pidl->mkid.cb)
294         {
295             pidl = Next(pidl);
296                         nCount++;
297         }
298     }
299     return nCount;
300 }
301
302 UINT CShellPidl::GetSize(LPCITEMIDLIST pidl)
303 {
304     UINT cbTotal = 0;
305     if (pidl)
306     {
307         cbTotal += sizeof(pidl->mkid.cb);       // Null terminator
308         while (pidl->mkid.cb)
309         {
310             cbTotal += pidl->mkid.cb;
311             pidl = Next(pidl);
312         }
313     }
314     return cbTotal;
315 }
316
317 LPITEMIDLIST CShellPidl::Next(LPCITEMIDLIST pidl)
318 {
319    LPSTR lpMem=(LPSTR)pidl;
320
321    lpMem+=pidl->mkid.cb;
322
323    return (LPITEMIDLIST)lpMem;
324 }
325
326 LPITEMIDLIST CShellPidl::ConcatPidl(LPITEMIDLIST pidlDest,LPITEMIDLIST pidlSrc) 
327
328         // Get the size of the specified item identifier. 
329     UINT cbDest=0;
330     UINT cbSrc=0;
331     if (pidlDest)  //May be NULL
332        cbDest = GetSize(pidlDest) - sizeof(pidlDest->mkid.cb);
333     cbSrc = GetSize(pidlSrc);
334
335         // Allocate a new item identifier list. 
336         LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(cbSrc+cbDest); 
337         if (pidlNew == NULL) 
338                 return NULL; 
339         ZeroMemory(pidlNew,cbSrc+cbDest);
340         // Copy the specified item identifier. 
341         if (pidlDest)
342                 CopyMemory(pidlNew, pidlDest, cbDest); 
343         CopyMemory(((USHORT*)(((LPBYTE)pidlNew)+cbDest)), pidlSrc, cbSrc); 
344
345         return pidlNew; 
346 }
347
348 int CShellPidl::GetIcon(LPITEMIDLIST lpi, UINT uFlags)
349 {
350    SHFILEINFO    sfi;
351    ZeroMemory(&sfi,sizeof(sfi));
352    if (uFlags == 0)
353                 uFlags |= (SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
354    uFlags |= SHGFI_PIDL;
355    SHGetFileInfo((LPCTSTR)lpi, 0, &sfi, sizeof(SHFILEINFO), uFlags);
356
357    return sfi.iIcon;
358 }
359
360 STDMETHODIMP CShellPidl::SHPidlToPathEx(LPCITEMIDLIST pidl, CString &sPath, LPSHELLFOLDER pFolder, DWORD dwFlags)
361 {
362         STRRET StrRetFilePath;
363         LPTSTR pszFilePath = NULL;
364         HRESULT hr=E_FAIL;
365         if (pFolder == NULL)
366                 pFolder = GetDesktopFolder();
367         if (pFolder == NULL)
368                 return E_FAIL;
369         hr = pFolder->GetDisplayNameOf(pidl, dwFlags, &StrRetFilePath);
370         if (SUCCEEDED(hr))
371         {
372                 StrRetToStr(StrRetFilePath, &pszFilePath, (LPITEMIDLIST)pidl);
373                 sPath = pszFilePath;
374         }
375         if (pszFilePath)
376                 m_pMalloc->Free(pszFilePath);
377         return hr;
378 }
379
380 STDMETHODIMP CShellPidl::SHPathToPidlEx(LPCTSTR szPath, LPITEMIDLIST* ppidl, LPSHELLFOLDER pFolder)
381 {
382    OLECHAR wszPath[MAX_PATH] = {0};
383    ULONG nCharsParsed = 0;
384    LPSHELLFOLDER pShellFolder = NULL;
385    BOOL bFreeOnExit = FALSE;
386 #ifdef UNICODE
387    lstrcpy(wszPath,szPath);
388 #else
389    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, -1, wszPath, MAX_PATH);
390 #endif
391    // Use the desktop's IShellFolder by default
392    if(pFolder == NULL)
393    {
394       SHGetDesktopFolder(&pShellFolder);
395       bFreeOnExit = TRUE;
396    }
397    else
398       pShellFolder = pFolder;
399
400    HRESULT hr = pShellFolder->ParseDisplayName(NULL, NULL, wszPath, &nCharsParsed, ppidl, NULL);
401
402    if(bFreeOnExit)
403       pShellFolder->Release();
404
405    return hr;
406 }
407
408 void CShellPidl::GetTypeName(LPITEMIDLIST lpi,CString &sTypeName)
409 {
410    SHFILEINFO    sfi;
411    ZeroMemory(&sfi,sizeof(sfi));
412    UINT uFlags = SHGFI_PIDL | SHGFI_TYPENAME;
413    SHGetFileInfo((LPCTSTR)lpi, 0, &sfi, sizeof(SHFILEINFO), uFlags);
414    sTypeName = sfi.szTypeName;
415 }
416
417 void CShellPidl::GetDisplayName(LPITEMIDLIST lpifq,CString &sDisplayName)
418 {
419    SHFILEINFO    sfi;
420    ZeroMemory(&sfi,sizeof(sfi));
421    UINT uFlags = SHGFI_PIDL | SHGFI_DISPLAYNAME;
422    SHGetFileInfo((LPCTSTR)lpifq, 0, &sfi, sizeof(SHFILEINFO), uFlags);
423    sDisplayName = sfi.szDisplayName;
424 }
425
426 void CShellPidl::GetNormalAndSelectedIcons (
427    LPITEMIDLIST lpifq, int &iImage, int &iSelectedImage)
428 {
429    // Don't check the return value here. 
430    // If IGetIcon() fails, you're in big trouble.
431    iImage = GetIcon (lpifq, 
432       SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
433    
434    iSelectedImage = GetIcon (lpifq, 
435       SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON);
436    
437    return;
438 }
439
440 BOOL CShellPidl::HandleMenuMsg(HWND hwnd, LPSHELLFOLDER lpsfParent,
441      LPITEMIDLIST  lpi, UINT uMsg, WPARAM wParam, LPARAM lParam)
442 {
443     LPCONTEXTMENU lpcm=NULL;
444     HRESULT hr=lpsfParent->GetUIObjectOf(hwnd,
445         1,  // get attributes for this many objects
446         (const struct _ITEMIDLIST **)&lpi,
447         IID_IContextMenu,
448         0,
449         (LPVOID *)&lpcm);
450     if (SUCCEEDED(hr))  
451     {
452             LPCONTEXTMENU2 lpcm2=NULL;
453                 hr = lpcm->QueryInterface(IID_IContextMenu2,(LPVOID*)&lpcm2);
454                 lpcm->Release();
455                 if (SUCCEEDED(hr))  
456             {
457                         lpcm2->HandleMenuMsg(uMsg,wParam,lParam);
458                         lpcm2->Release();
459                 }
460                 return TRUE;
461         }
462         return FALSE;
463 }
464
465 BOOL CShellPidl::PopupTheMenu(HWND hwnd, LPSHELLFOLDER lpsfParent,
466      LPITEMIDLIST  *plpi, UINT cidl, LPPOINT lppt)
467 {
468         CMenu menu;
469     menu.CreatePopupMenu();
470         g_CoolMenuManager.Install(CWnd::FromHandle(hwnd));
471         CString sPath;
472         if (lpsfParent == NULL)
473                 lpsfParent = GetDesktopFolder();
474         SHPidlToPathEx(*plpi,sPath,lpsfParent);
475         CShellContextMenu shell_menu(hwnd,sPath,plpi,cidl,lpsfParent);
476         shell_menu.SetMenu(&menu);
477     int idCmd = menu.TrackPopupMenu(TPM_FLAGS, lppt->x, lppt->y, CWnd::FromHandle(hwnd));
478         shell_menu.InvokeCommand(idCmd);
479         g_CoolMenuManager.Uninstall();
480         return TRUE;
481 }
482
483 /****************************************************************************
484 *
485 *    FUNCTION: GetName(LPSHELLFOLDER lpsf,LPITEMIDLIST  lpi,DWORD dwFlags,
486 *             LPSTR         lpFriendlyName)
487 *
488 *    PURPOSE:  Gets the friendly name for the folder 
489 *
490 ****************************************************************************/
491 BOOL CShellPidl::GetName (LPSHELLFOLDER lpsf, LPITEMIDLIST lpi, 
492    DWORD dwFlags, CString &sFriendlyName)
493 {
494    BOOL   bSuccess=TRUE;
495    STRRET str;
496
497    if (NOERROR==lpsf->GetDisplayNameOf(lpi,dwFlags, &str))
498    {
499       switch (str.uType)
500       {
501          case STRRET_WSTR:
502 #ifdef UNICODE
503                          _tcscpy(sFriendlyName.GetBuffer(MAX_PATH),str.pOleStr);
504                          sFriendlyName.ReleaseBuffer();
505 #else
506             WideCharToMultiByte(
507                CP_ACP,                 // code page
508                0,                              // dwFlags
509                str.pOleStr,            // lpWideCharStr
510                -1,                     // cchWideCharStr
511                sFriendlyName.GetBuffer(_MAX_PATH),         // lpMultiByteStr
512                _MAX_PATH, // cchMultiByte
513                NULL,                   // lpDefaultChar
514                NULL);                  // lpUsedDefaultChar
515 #endif
516                         sFriendlyName.ReleaseBuffer();  
517              break;
518
519          case STRRET_OFFSET:
520              sFriendlyName = (LPTSTR)lpi+str.uOffset;
521              break;
522
523          case STRRET_CSTR:             
524              sFriendlyName = (LPTSTR)str.cStr;
525              break;
526
527          default:
528              bSuccess = FALSE;
529              break;
530       }
531    }
532    else
533       bSuccess = FALSE;
534
535    return bSuccess;
536 }
537
538 //
539 // ResolveChannel: Resolves a Channel Shortcut to its URL
540 //
541 STDMETHODIMP CShellPidl::ResolveChannel(IShellFolder* pFolder, LPCITEMIDLIST pidl, LPTSTR* lpszURL)
542 {
543    IShellLink* pShellLink;
544
545    *lpszURL = NULL;  // Assume failure
546
547    // Get a pointer to the IShellLink interface from the given folder
548    HRESULT hr = pFolder->GetUIObjectOf(NULL, 1, &pidl, IID_IShellLink, NULL, (LPVOID*)&pShellLink);
549    if (SUCCEEDED(hr))
550    {
551       LPITEMIDLIST pidlChannel;
552
553       // Convert the IShellLink pointer to a PIDL.
554       hr = pShellLink->GetIDList(&pidlChannel);
555       if (SUCCEEDED(hr))
556       {
557          IShellFolder* psfDesktop;
558
559          hr = SHGetDesktopFolder(&psfDesktop);
560          if (SUCCEEDED(hr))
561          {
562             STRRET strret;
563
564             hr = psfDesktop->GetDisplayNameOf(pidlChannel, 0, &strret);
565             if (SUCCEEDED(hr))
566                                 StrRetToStr(strret, lpszURL, pidlChannel);
567
568             psfDesktop->Release();
569          }
570       }
571
572       pShellLink->Release();
573    }
574
575    return hr;
576 }
577
578 STDMETHODIMP CShellPidl::ResolveHistoryShortcut(LPSHELLFOLDER pFolder,LPCITEMIDLIST *ppidl,CString &sURL)
579 {
580         HRESULT hr=E_FAIL;
581         IDataObject *pObj=NULL;
582         hr = pFolder->GetUIObjectOf(NULL, 1, ppidl, IID_IDataObject, NULL, (LPVOID*)&pObj);
583         if (SUCCEEDED(hr))
584         {
585                 hr = GetURL(pObj,sURL);
586                 pObj->Release();
587         }
588         return hr;
589 }
590
591 STDMETHODIMP CShellPidl::GetURL(IDataObject *pDataObj,CString &sURL)
592 {
593         sURL.Empty();
594         STGMEDIUM stgm;
595         ZeroMemory(&stgm, sizeof(stgm));
596
597     FORMATETC fetc;
598     fetc.cfFormat = CF_SHELLURL;
599     fetc.ptd = NULL;
600     fetc.dwAspect = DVASPECT_CONTENT;
601     fetc.lindex = -1;
602     fetc.tymed = TYMED_HGLOBAL;
603
604     HRESULT hr = pDataObj->QueryGetData(&fetc);
605         if (FAILED(hr))
606                 return hr;
607     hr = pDataObj->GetData(&fetc, &stgm);
608         if (FAILED(hr))
609                 return hr;
610     LPCTSTR pData = (LPCTSTR)GlobalLock(stgm.hGlobal);
611         sURL = pData;
612         GlobalUnlock(stgm.hGlobal);
613     ReleaseStgMedium(&stgm);
614         return S_OK;
615 }
616
617 //
618 // ResolveInternetShortcut: Resolves an Internet Shortcut to its URL
619 //
620 STDMETHODIMP CShellPidl::ResolveInternetShortcut(LPCTSTR lpszLinkFile, LPTSTR* lpszURL)
621 {
622         IUniformResourceLocator* pUrlLink = NULL;
623
624         *lpszURL=NULL;
625
626         HRESULT hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
627                                                          IID_IUniformResourceLocator, (LPVOID*)&pUrlLink);
628         if (FAILED(hr))
629                 return hr;
630
631         IPersistFile* pPersistFile = NULL;
632         hr = pUrlLink->QueryInterface(IID_IPersistFile, (LPVOID*)&pPersistFile);
633         if (SUCCEEDED(hr))
634         {
635                  // Ensure that the string is Unicode. 
636                  WORD wsz[MAX_PATH];  
637                 #ifdef UNICODE
638                  _tcscpy(wsz,lpszLinkFile);
639                 #else
640                  MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH);
641                 #endif
642                  // Load the Internet Shortcut from persistent storage.
643                  hr = pPersistFile->Load(wsz, STGM_READ);
644                  if (SUCCEEDED(hr))
645                  {
646                         hr = pUrlLink->GetURL(lpszURL);
647                  }
648                  pPersistFile->Release();
649         }
650         pUrlLink->Release();
651
652         return hr;
653 }  
654
655 //
656 // ResolveLink: Resolves a Shell Link to its actual folder location
657 //
658 STDMETHODIMP CShellPidl::ResolveLink(HWND hWnd,LPCTSTR lpszLinkFile, LPTSTR* lpszURL)
659 {
660    IShellLink* pShellLink = NULL;
661
662    *lpszURL = NULL;   // Assume failure
663
664    HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
665                                  IID_IShellLink, (LPVOID*)&pShellLink); 
666    if (SUCCEEDED(hr))
667    {
668       IPersistFile* pPersistFile = NULL;
669
670       hr = pShellLink->QueryInterface(IID_IPersistFile, (LPVOID*)&pPersistFile);
671       if (SUCCEEDED(hr))
672       {
673          // Ensure that the string is Unicode. 
674          WORD wsz[MAX_PATH];  
675 #ifdef UNICODE
676                  _tcscpy(wsz,lpszLinkFile);
677 #else
678          MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH);
679 #endif
680
681          // Load the shortcut.from persistent storage
682          hr = pPersistFile->Load(wsz, STGM_READ);
683          if (SUCCEEDED(hr))
684          {
685             WIN32_FIND_DATA wfd;      
686
687             hr = pShellLink->Resolve(hWnd, SLR_NO_UI); 
688             if (NOERROR == hr)
689             {
690                // Get the path to the link target. 
691                            *lpszURL = (LPTSTR)m_pMalloc->Alloc(MAX_PATH);  // Must remember to Free later
692
693                hr = pShellLink->GetPath(*lpszURL, MAX_PATH - 1, (WIN32_FIND_DATA*)&wfd, SLGP_UNCPRIORITY);
694             }
695          }
696
697          pPersistFile->Release();
698       }
699
700       pShellLink->Release();
701    }
702
703    return hr;
704 }
705
706 //
707 // This method converts a STRRET structure to a LPTSTR
708 //
709 #ifdef UNICODE
710 STDMETHODIMP CShellPidl::StrRetToStr(STRRET StrRet, LPTSTR* str, LPITEMIDLIST pidl)
711 {
712         HRESULT hr = S_OK;
713         int cch;
714         LPSTR strOffset;
715
716         *str = NULL;  // Assume failure
717
718         switch (StrRet.uType)
719    {
720                 case STRRET_WSTR: 
721                         cch = wcslen(StrRet.pOleStr) + 1; // NULL terminator
722                         *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));
723
724                         if (*str != NULL)
725                                 lstrcpyn(*str, StrRet.pOleStr, cch);
726                         else
727                                 hr = E_FAIL;
728                         break;
729
730                 case STRRET_OFFSET: 
731                         strOffset = (((char *) pidl) + StrRet.uOffset);
732
733                         cch = MultiByteToWideChar(CP_OEMCP, 0, strOffset, -1, NULL, 0); 
734                         *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));
735
736                         if (*str != NULL)
737                                 MultiByteToWideChar(CP_OEMCP, 0, strOffset, -1, *str, cch); 
738                         else
739                                 hr = E_FAIL;
740                         break;
741
742                 case STRRET_CSTR: 
743                         cch = MultiByteToWideChar(CP_OEMCP, 0, StrRet.cStr, -1, NULL, 0); 
744                         *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR)); 
745
746                         if (*str != NULL)
747                                 MultiByteToWideChar(CP_OEMCP, 0, StrRet.cStr, -1, *str, cch); 
748                         else
749                                 hr = E_FAIL;
750
751                         break;
752         } 
753  
754         return hr;
755 }
756 #else // UNICODE not defined
757 STDMETHODIMP CShellPidl::StrRetToStr(STRRET StrRet, LPTSTR* str, LPITEMIDLIST pidl)
758 {
759
760         HRESULT hr = S_OK;
761         int cch;
762         LPSTR strOffset;
763
764         *str = NULL;  // Assume failure
765
766         switch (StrRet.uType)
767    {
768                 case STRRET_WSTR: 
769                         cch = WideCharToMultiByte(CP_ACP, 0, StrRet.pOleStr, -1, NULL, 0, NULL, NULL); 
770                         *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR)); 
771
772                         if (*str != NULL)
773                                 WideCharToMultiByte(CP_ACP, 0, StrRet.pOleStr, -1, *str, cch, NULL, NULL); 
774                         else
775                                 hr = E_FAIL;
776                         break;
777
778                 case STRRET_OFFSET: 
779                         strOffset = (((char *) pidl) + StrRet.uOffset);
780
781                         cch = strlen(strOffset) + 1; // NULL terminator
782                         *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));
783
784                         if (*str != NULL)
785                                 strcpy(*str, strOffset);
786                         else
787                                 hr = E_FAIL;
788                         break;
789
790                 case STRRET_CSTR: 
791                         cch = strlen(StrRet.cStr) + 1; // NULL terminator
792                         *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));
793
794                         if (*str != NULL)
795                                 strcpy(*str, StrRet.cStr);
796                         else
797                                 hr = E_FAIL;
798
799                         break;
800         } 
801
802         return hr;
803 }
804 #endif