ReactOS  0.4.15-dev-1201-gb2cf5a4
CShellLink.cpp
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 1997 Marcus Meissner
4  * Copyright 1998 Juergen Schmied
5  * Copyright 2005 Mike McCormack
6  * Copyright 2009 Andrew Hill
7  * Copyright 2013 Dominik Hornung
8  * Copyright 2017 Hermes Belusca-Maito
9  * Copyright 2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  *
25  * NOTES
26  * Nearly complete information about the binary formats
27  * of .lnk files available at http://www.wotsit.org
28  *
29  * You can use winedump to examine the contents of a link file:
30  * winedump lnk sc.lnk
31  *
32  * MSI advertised shortcuts are totally undocumented. They provide an
33  * icon for a program that is not yet installed, and invoke MSI to
34  * install the program when the shortcut is clicked on. They are
35  * created by passing a special string to SetPath, and the information
36  * in that string is parsed an stored.
37  */
38 /*
39  * In the following is listed more documentation about the Shell Link file format,
40  * as well as its interface.
41  *
42  * General introduction about "Shell Links" (MSDN):
43  * https://msdn.microsoft.com/en-us/library/windows/desktop/bb776891(v=vs.85).aspx
44  *
45  *
46  * Details of the file format:
47  *
48  * - Official MSDN documentation "[MS-SHLLINK]: Shell Link (.LNK) Binary File Format":
49  * https://msdn.microsoft.com/en-us/library/dd871305.aspx
50  *
51  * - Forensics:
52  * http://forensicswiki.org/wiki/LNK
53  * http://computerforensics.parsonage.co.uk/downloads/TheMeaningofLIFE.pdf
54  * https://ithreats.files.wordpress.com/2009/05/lnk_the_windows_shortcut_file_format.pdf
55  * https://github.com/libyal/liblnk/blob/master/documentation/Windows%20Shortcut%20File%20(LNK)%20format.asciidoc
56  *
57  * - List of possible shell link header flags (SHELL_LINK_DATA_FLAGS enumeration):
58  * https://msdn.microsoft.com/en-us/library/windows/desktop/bb762540(v=vs.85).aspx
59  * https://msdn.microsoft.com/en-us/library/dd891314.aspx
60  *
61  *
62  * In addition to storing its target by using a PIDL, a shell link file also
63  * stores metadata to make the shell able to track the link target, in situations
64  * where the link target is moved amongst local or network directories, or moved
65  * to different volumes. For this, two structures are used:
66  *
67  * - The first and oldest one (from NewShell/WinNT4) is the "LinkInfo" structure,
68  * stored in a serialized manner at the beginning of the shell link file:
69  * https://msdn.microsoft.com/en-us/library/dd871404.aspx
70  * The official API for manipulating this is located in LINKINFO.DLL .
71  *
72  * - The second, more recent one, is an extra binary block appended to the
73  * extra-data list of the shell link file: this is the "TrackerDataBlock":
74  * https://msdn.microsoft.com/en-us/library/dd891376.aspx
75  * Its purpose is for link tracking, and works in coordination with the
76  * "Distributed Link Tracking" service ('TrkWks' client, 'TrkSvr' server).
77  * See a detailed explanation at:
78  * http://www.serverwatch.com/tutorials/article.php/1476701/Searching-for-the-Missing-Link-Distributed-Link-Tracking.htm
79  *
80  *
81  * MSI installations most of the time create so-called "advertised shortcuts".
82  * They provide an icon for a program that may not be installed yet, and invoke
83  * MSI to install the program when the shortcut is opened (resolved).
84  * The philosophy of this approach is explained in detail inside the MSDN article
85  * "Application Resiliency: Unlock the Hidden Features of Windows Installer"
86  * (by Michael Sanford), here:
87  * https://msdn.microsoft.com/en-us/library/aa302344.aspx
88  *
89  * This functionality is implemented by adding a binary "Darwin" data block
90  * of type "EXP_DARWIN_LINK", signature EXP_DARWIN_ID_SIG == 0xA0000006,
91  * to the shell link file:
92  * https://msdn.microsoft.com/en-us/library/dd871369.aspx
93  * or, this could be done more simply by specifying a special link target path
94  * with the IShellLink::SetPath() function. Defining the following GUID:
95  * SHELL32_AdvtShortcutComponent = "::{9db1186e-40df-11d1-aa8c-00c04fb67863}:"
96  * setting a target of the form:
97  * "::{SHELL32_AdvtShortcutComponent}:<MSI_App_ID>"
98  * would automatically create the necessary binary block.
99  *
100  * With that, the target of the shortcut now becomes the MSI data. The latter
101  * is parsed from MSI and retrieved by the shell that then can run the program.
102  *
103  * This MSI functionality, dubbed "link blessing", actually originates from an
104  * older technology introduced in Internet Explorer 3 (and now obsolete since
105  * Internet Explorer 7), called "MS Internet Component Download (MSICD)", see
106  * this MSDN introductory article:
107  * https://msdn.microsoft.com/en-us/library/aa741198(v=vs.85).aspx
108  * and leveraged in Internet Explorer 4 with "Software Update Channels", see:
109  * https://msdn.microsoft.com/en-us/library/aa740931(v=vs.85).aspx
110  * Applications supporting this technology could present shell links having
111  * a special target, see subsection "Modifying the Shortcut" in the article:
112  * https://msdn.microsoft.com/en-us/library/aa741201(v=vs.85).aspx#pub_shor
113  *
114  * Similarly as for the MSI shortcuts, these MSICD shortcuts are created by
115  * specifying a special link target path with the IShellLink::SetPath() function,
116  * defining the following GUID:
117  * SHELL32_AdvtShortcutProduct = "::{9db1186f-40df-11d1-aa8c-00c04fb67863}:"
118  * and setting a target of the form:
119  * "::{SHELL32_AdvtShortcutProduct}:<AppName>::<Path>" .
120  * A tool, called "blesslnk.exe", was also provided for automatizing the process;
121  * its ReadMe can be found in the (now outdated) MS "Internet Client SDK" (INetSDK,
122  * for MS Windows 95 and NT), whose contents can be read at:
123  * http://www.msfn.org/board/topic/145352-new-windows-lnk-vulnerability/?page=4#comment-944223
124  * The MS INetSDK can be found at:
125  * https://web.archive.org/web/20100924000013/http://support.microsoft.com/kb/177877
126  *
127  * Internally the shell link target of these MSICD shortcuts is converted into
128  * a binary data block of a type similar to Darwin / "EXP_DARWIN_LINK", but with
129  * a different signature EXP_LOGO3_ID_SIG == 0xA0000007 . Such shell links are
130  * called "Logo3" shortcuts. They were evoked in this user comment in "The Old
131  * New Thing" blog:
132  * https://blogs.msdn.microsoft.com/oldnewthing/20121210-00/?p=5883#comment-1025083
133  *
134  * The shell exports the API 'SoftwareUpdateMessageBox' (in shdocvw.dll) that
135  * displays a message when an update for an application supporting this
136  * technology is available.
137  *
138  */
139 
140 #include "precomp.h"
141 
142 #include <appmgmt.h>
143 
145 
146 /*
147  * Allows to define whether or not Windows-compatible behaviour
148  * should be adopted when setting and retrieving icon location paths.
149  * See CShellLink::SetIconLocation(LPCWSTR pszIconPath, INT iIcon)
150  * for more details.
151  */
152 #define ICON_LINK_WINDOWS_COMPAT
153 
154 #define SHLINK_LOCAL 0
155 #define SHLINK_REMOTE 1
156 
157 /* link file formats */
158 
159 #include "pshpack1.h"
160 
162 {
170 };
171 
173 {
178 };
179 
181 {
184  WCHAR label[12]; /* assume 8.3 */
185 };
186 
187 #include "poppack.h"
188 
189 /* IShellLink Implementation */
190 
191 static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath);
192 
193 /* strdup on the process heap */
195 {
196  INT len;
197  LPWSTR p;
198 
199  assert(str);
200 
201  len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
202  p = (LPWSTR)HeapAlloc(heap, flags, len * sizeof(WCHAR));
203  if (!p)
204  return p;
205  MultiByteToWideChar(CP_ACP, 0, str, -1, p, len);
206  return p;
207 }
208 
209 static LPWSTR __inline strdupW(LPCWSTR src)
210 {
211  LPWSTR dest;
212  if (!src) return NULL;
213  dest = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(src) + 1) * sizeof(WCHAR));
214  if (dest)
215  wcscpy(dest, src);
216  return dest;
217 }
218 
219 // TODO: Use it for constructor & destructor too
221 {
222  ILFree(m_pPidl);
223  m_pPidl = NULL;
224 
226  m_sPath = NULL;
227  ZeroMemory(&volume, sizeof(volume));
228 
232  m_sPathRel = NULL;
234  m_sWorkDir = NULL;
236  m_sArgs = NULL;
238  m_sIcoPath = NULL;
239 
240  m_bRunAs = FALSE;
241  m_bDirty = FALSE;
242 
243  if (m_pDBList)
245  m_pDBList = NULL;
246 
248 }
249 
251 {
252  m_Header.dwSize = sizeof(m_Header);
253  m_Header.clsid = CLSID_ShellLink;
254  m_Header.dwFlags = 0;
255 
261 
262  m_Header.nIconIndex = 0;
264  m_Header.wHotKey = 0;
265 
266  m_pPidl = NULL;
267 
268  m_sPath = NULL;
269  ZeroMemory(&volume, sizeof(volume));
270 
272  m_sPathRel = NULL;
273  m_sWorkDir = NULL;
274  m_sArgs = NULL;
275  m_sIcoPath = NULL;
276  m_bRunAs = FALSE;
277  m_bDirty = FALSE;
278  m_pDBList = NULL;
279  m_bInInit = FALSE;
280  m_hIcon = NULL;
281  m_idCmdFirst = 0;
282 
283  m_sLinkPath = NULL;
284 
286 }
287 
289 {
290  TRACE("-- destroying IShellLink(%p)\n", this);
291 
292  ILFree(m_pPidl);
293 
295 
303 }
304 
306 {
307  TRACE("%p %p\n", this, pclsid);
308 
309  if (pclsid == NULL)
310  return E_POINTER;
311  *pclsid = CLSID_ShellLink;
312  return S_OK;
313 }
314 
315 /************************************************************************
316  * IPersistStream_IsDirty (IPersistStream)
317  */
319 {
320  TRACE("(%p)\n", this);
321  return (m_bDirty ? S_OK : S_FALSE);
322 }
323 
325 {
326  TRACE("(%p, %s, %x)\n", this, debugstr_w(pszFileName), dwMode);
327 
328  if (dwMode == 0)
329  dwMode = STGM_READ | STGM_SHARE_DENY_WRITE;
330 
331  CComPtr<IStream> stm;
332  HRESULT hr = SHCreateStreamOnFileW(pszFileName, dwMode, &stm);
333  if (SUCCEEDED(hr))
334  {
337  hr = Load(stm);
339  m_bDirty = FALSE;
340  }
341  TRACE("-- returning hr %08x\n", hr);
342  return hr;
343 }
344 
346 {
347  BOOL bAlreadyExists;
348  WCHAR szFullPath[MAX_PATH];
349 
350  TRACE("(%p)->(%s)\n", this, debugstr_w(pszFileName));
351 
352  if (!pszFileName)
353  return E_FAIL;
354 
355  bAlreadyExists = PathFileExistsW(pszFileName);
356 
357  CComPtr<IStream> stm;
359  if (SUCCEEDED(hr))
360  {
361  hr = Save(stm, FALSE);
362 
363  if (SUCCEEDED(hr))
364  {
365  GetFullPathNameW(pszFileName, _countof(szFullPath), szFullPath, NULL);
366  if (bAlreadyExists)
368  else
370 
371  if (m_sLinkPath)
373 
375  m_bDirty = FALSE;
376  }
377  else
378  {
380  WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName));
381  }
382  }
383 
384  return hr;
385 }
386 
388 {
389  FIXME("(%p)->(%s)\n", this, debugstr_w(pszFileName));
390  return S_OK;
391 }
392 
394 {
395  *ppszFileName = NULL;
396 
397  if (!m_sLinkPath)
398  {
399  /* IPersistFile::GetCurFile called before IPersistFile::Save */
400  return S_FALSE;
401  }
402 
403  *ppszFileName = (LPOLESTR)CoTaskMemAlloc((wcslen(m_sLinkPath) + 1) * sizeof(WCHAR));
404  if (!*ppszFileName)
405  {
406  /* out of memory */
407  return E_OUTOFMEMORY;
408  }
409 
410  /* copy last saved filename */
411  wcscpy(*ppszFileName, m_sLinkPath);
412 
413  return S_OK;
414 }
415 
416 static HRESULT Stream_LoadString(IStream* stm, BOOL unicode, LPWSTR *pstr)
417 {
418  TRACE("%p\n", stm);
419 
420  USHORT len;
421  DWORD count = 0;
422  HRESULT hr = stm->Read(&len, sizeof(len), &count);
423  if (FAILED(hr) || count != sizeof(len))
424  return E_FAIL;
425 
426  if (unicode)
427  len *= sizeof(WCHAR);
428 
429  TRACE("reading %d\n", len);
430  LPSTR temp = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len + sizeof(WCHAR));
431  if (!temp)
432  return E_OUTOFMEMORY;
433  count = 0;
434  hr = stm->Read(temp, len, &count);
435  if (FAILED(hr) || count != len)
436  {
438  return E_FAIL;
439  }
440 
441  TRACE("read %s\n", debugstr_an(temp, len));
442 
443  /* convert to unicode if necessary */
444  LPWSTR str;
445  if (!unicode)
446  {
448  str = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (count + 1) * sizeof(WCHAR));
449  if (!str)
450  {
452  return E_OUTOFMEMORY;
453  }
456  }
457  else
458  {
459  count /= sizeof(WCHAR);
460  str = (LPWSTR)temp;
461  }
462  str[count] = 0;
463 
464  *pstr = str;
465 
466  return S_OK;
467 }
468 
469 
470 /*
471  * NOTE: The following 5 functions are part of LINKINFO.DLL
472  */
474 {
475  WCHAR drive[4] = { path[0], ':', '\\', 0 };
476 
477  volume->type = GetDriveTypeW(drive);
478  BOOL bRet = GetVolumeInformationW(drive, volume->label, _countof(volume->label), &volume->serial, NULL, NULL, NULL, 0);
479  TRACE("ret = %d type %d serial %08x name %s\n", bRet,
480  volume->type, volume->serial, debugstr_w(volume->label));
481  return bRet;
482 }
483 
485 {
486  struct sized_chunk
487  {
488  DWORD size;
489  unsigned char data[1];
490  } *chunk;
491 
492  TRACE("%p\n", stm);
493 
494  DWORD size;
495  ULONG count;
496  HRESULT hr = stm->Read(&size, sizeof(size), &count);
497  if (FAILED(hr) || count != sizeof(size))
498  return E_FAIL;
499 
500  chunk = static_cast<sized_chunk *>(HeapAlloc(GetProcessHeap(), 0, size));
501  if (!chunk)
502  return E_OUTOFMEMORY;
503 
504  chunk->size = size;
505  hr = stm->Read(chunk->data, size - sizeof(size), &count);
506  if (FAILED(hr) || count != (size - sizeof(size)))
507  {
509  return E_FAIL;
510  }
511 
512  TRACE("Read %d bytes\n", chunk->size);
513 
514  *data = chunk;
515 
516  return S_OK;
517 }
518 
520 {
521  volume->serial = vol->dwVolSerial;
522  volume->type = vol->dwType;
523 
524  if (!vol->dwVolLabelOfs)
525  return FALSE;
526  if (vol->dwSize <= vol->dwVolLabelOfs)
527  return FALSE;
528  INT len = vol->dwSize - vol->dwVolLabelOfs;
529 
530  LPSTR label = (LPSTR)vol;
531  label += vol->dwVolLabelOfs;
532  MultiByteToWideChar(CP_ACP, 0, label, len, volume->label, _countof(volume->label));
533 
534  return TRUE;
535 }
536 
538 {
539  UINT len = 0;
540 
541  while (len < maxlen && p[len])
542  len++;
543 
544  UINT wlen = MultiByteToWideChar(CP_ACP, 0, p, len, NULL, 0);
545  LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wlen + 1) * sizeof(WCHAR));
546  if (!path)
547  return NULL;
548  MultiByteToWideChar(CP_ACP, 0, p, len, path, wlen);
549  path[wlen] = 0;
550 
551  return path;
552 }
553 
556 {
557  char *p = NULL;
558  HRESULT hr = Stream_ReadChunk(stm, (LPVOID*) &p);
559  if (FAILED(hr))
560  return hr;
561 
562  LOCATION_INFO *loc = reinterpret_cast<LOCATION_INFO *>(p);
563  if (loc->dwTotalSize < sizeof(LOCATION_INFO))
564  {
565  HeapFree(GetProcessHeap(), 0, p);
566  return E_FAIL;
567  }
568 
569  /* if there's valid local volume information, load it */
570  if (loc->dwVolTableOfs &&
571  ((loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO)) <= loc->dwTotalSize))
572  {
574 
577  }
578 
579  /* if there's a local path, load it */
580  DWORD n = loc->dwLocalPathOfs;
581  if (n && n < loc->dwTotalSize)
582  *path = Stream_LoadPath(&p[n], loc->dwTotalSize - n);
583 
584  TRACE("type %d serial %08x name %s path %s\n", volume->type,
585  volume->serial, debugstr_w(volume->label), debugstr_w(*path));
586 
587  HeapFree(GetProcessHeap(), 0, p);
588  return S_OK;
589 }
590 
591 
592 /*
593  * The format of the advertised shortcut info is:
594  *
595  * Offset Description
596  * ------ -----------
597  * 0 Length of the block (4 bytes, usually 0x314)
598  * 4 tag (dword)
599  * 8 string data in ASCII
600  * 8+0x104 string data in UNICODE
601  *
602  * In the original Win32 implementation the buffers are not initialized
603  * to zero, so data trailing the string is random garbage.
604  */
606 {
607  LPEXP_DARWIN_LINK pInfo;
608 
609  *str = NULL;
610 
612  if (!pInfo)
613  return E_FAIL;
614 
615  /* Make sure that the size of the structure is valid */
616  if (pInfo->dbh.cbSize != sizeof(*pInfo))
617  {
618  ERR("Ooops. This structure is not as expected...\n");
619  return E_FAIL;
620  }
621 
622  TRACE("dwSig %08x string = '%s'\n", pInfo->dbh.dwSignature, debugstr_w(pInfo->szwDarwinID));
623 
624  *str = pInfo->szwDarwinID;
625  return S_OK;
626 }
627 
628 /************************************************************************
629  * IPersistStream_Load (IPersistStream)
630  */
632 {
633  TRACE("%p %p\n", this, stm);
634 
635  if (!stm)
636  return STG_E_INVALIDPOINTER;
637 
638  /* Free all the old stuff */
639  Reset();
640 
641  ULONG dwBytesRead = 0;
642  HRESULT hr = stm->Read(&m_Header, sizeof(m_Header), &dwBytesRead);
643  if (FAILED(hr))
644  return hr;
645 
646  if (dwBytesRead != sizeof(m_Header))
647  return E_FAIL;
648  if (m_Header.dwSize != sizeof(m_Header))
649  return E_FAIL;
650  if (!IsEqualIID(m_Header.clsid, CLSID_ShellLink))
651  return E_FAIL;
652 
653  /* Load the new data in order */
654 
655  if (TRACE_ON(shell))
656  {
657  SYSTEMTIME stCreationTime;
658  SYSTEMTIME stLastAccessTime;
659  SYSTEMTIME stLastWriteTime;
660  WCHAR sTemp[MAX_PATH];
661 
662  FileTimeToSystemTime(&m_Header.ftCreationTime, &stCreationTime);
663  FileTimeToSystemTime(&m_Header.ftLastAccessTime, &stLastAccessTime);
664  FileTimeToSystemTime(&m_Header.ftLastWriteTime, &stLastWriteTime);
665 
667  NULL, sTemp, _countof(sTemp));
668  TRACE("-- stCreationTime: %s\n", debugstr_w(sTemp));
670  NULL, sTemp, _countof(sTemp));
671  TRACE("-- stLastAccessTime: %s\n", debugstr_w(sTemp));
673  NULL, sTemp, _countof(sTemp));
674  TRACE("-- stLastWriteTime: %s\n", debugstr_w(sTemp));
675  }
676 
677  /* load all the new stuff */
679  {
680  hr = ILLoadFromStream(stm, &m_pPidl);
681  if (FAILED(hr))
682  return hr;
683  }
684  pdump(m_pPidl);
685 
686  /* Load the location information... */
688  {
690  if (FAILED(hr))
691  return hr;
692  }
693  /* ... but if it is required not to use it, clear it */
695  {
697  m_sPath = NULL;
698  ZeroMemory(&volume, sizeof(volume));
699  }
700 
701  BOOL unicode = !!(m_Header.dwFlags & SLDF_UNICODE);
702 
704  {
705  hr = Stream_LoadString(stm, unicode, &m_sDescription);
706  if (FAILED(hr))
707  return hr;
708  TRACE("Description -> %s\n", debugstr_w(m_sDescription));
709  }
710 
712  {
713  hr = Stream_LoadString(stm, unicode, &m_sPathRel);
714  if (FAILED(hr))
715  return hr;
716  TRACE("Relative Path-> %s\n", debugstr_w(m_sPathRel));
717  }
718 
720  {
721  hr = Stream_LoadString(stm, unicode, &m_sWorkDir);
722  if (FAILED(hr))
723  return hr;
725  TRACE("Working Dir -> %s\n", debugstr_w(m_sWorkDir));
726  }
727 
729  {
730  hr = Stream_LoadString(stm, unicode, &m_sArgs);
731  if (FAILED(hr))
732  return hr;
733  TRACE("Arguments -> %s\n", debugstr_w(m_sArgs));
734  }
735 
737  {
738  hr = Stream_LoadString(stm, unicode, &m_sIcoPath);
739  if (FAILED(hr))
740  return hr;
741  TRACE("Icon file -> %s\n", debugstr_w(m_sIcoPath));
742  }
743 
744  /* Now load the optional data block list */
746  if (FAILED(hr)) // FIXME: Should we fail?
747  return hr;
748 
749  if (TRACE_ON(shell))
750  {
751 #if (NTDDI_VERSION < NTDDI_LONGHORN)
753  {
754  hr = GetAdvertiseInfo(&sProduct, EXP_LOGO3_ID_SIG);
755  if (SUCCEEDED(hr))
756  TRACE("Product -> %s\n", debugstr_w(sProduct));
757  }
758 #endif
760  {
762  if (SUCCEEDED(hr))
763  TRACE("Component -> %s\n", debugstr_w(sComponent));
764  }
765  }
766 
768  m_bRunAs = TRUE;
769  else
770  m_bRunAs = FALSE;
771 
772  TRACE("OK\n");
773 
774  pdump(m_pPidl);
775 
776  return S_OK;
777 }
778 
779 /************************************************************************
780  * Stream_WriteString
781  *
782  * Helper function for IPersistStream_Save. Writes a unicode string
783  * with terminating nul byte to a stream, preceded by the its length.
784  */
786 {
787  USHORT len = wcslen(str) + 1; // FIXME: Possible overflows?
788  DWORD count;
789 
790  HRESULT hr = stm->Write(&len, sizeof(len), &count);
791  if (FAILED(hr))
792  return hr;
793 
794  len *= sizeof(WCHAR);
795 
796  hr = stm->Write(str, len, &count);
797  if (FAILED(hr))
798  return hr;
799 
800  return S_OK;
801 }
802 
803 /************************************************************************
804  * Stream_WriteLocationInfo
805  *
806  * Writes the location info to a stream
807  *
808  * FIXME: One day we might want to write the network volume information
809  * and the final path.
810  * Figure out how Windows deals with unicode paths here.
811  */
814 {
815  LOCAL_VOLUME_INFO *vol;
816  LOCATION_INFO *loc;
817 
818  TRACE("%p %s %p\n", stm, debugstr_w(path), volume);
819 
820  /* figure out the size of everything */
821  DWORD label_size = WideCharToMultiByte(CP_ACP, 0, volume->label, -1,
822  NULL, 0, NULL, NULL);
823  DWORD path_size = WideCharToMultiByte(CP_ACP, 0, path, -1,
824  NULL, 0, NULL, NULL);
825  DWORD volume_info_size = sizeof(*vol) + label_size;
826  DWORD final_path_size = 1;
827  DWORD total_size = sizeof(*loc) + volume_info_size + path_size + final_path_size;
828 
829  /* create pointers to everything */
830  loc = static_cast<LOCATION_INFO *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, total_size));
831  vol = (LOCAL_VOLUME_INFO*) &loc[1];
832  LPSTR szLabel = (LPSTR) &vol[1];
833  LPSTR szPath = &szLabel[label_size];
834  LPSTR szFinalPath = &szPath[path_size];
835 
836  /* fill in the location information header */
837  loc->dwTotalSize = total_size;
838  loc->dwHeaderSize = sizeof(*loc);
839  loc->dwFlags = 1;
840  loc->dwVolTableOfs = sizeof(*loc);
841  loc->dwLocalPathOfs = sizeof(*loc) + volume_info_size;
842  loc->dwNetworkVolTableOfs = 0;
843  loc->dwFinalPathOfs = sizeof(*loc) + volume_info_size + path_size;
844 
845  /* fill in the volume information */
846  vol->dwSize = volume_info_size;
847  vol->dwType = volume->type;
848  vol->dwVolSerial = volume->serial;
849  vol->dwVolLabelOfs = sizeof(*vol);
850 
851  /* copy in the strings */
852  WideCharToMultiByte(CP_ACP, 0, volume->label, -1,
853  szLabel, label_size, NULL, NULL);
855  szPath, path_size, NULL, NULL);
856  *szFinalPath = 0;
857 
858  ULONG count = 0;
859  HRESULT hr = stm->Write(loc, total_size, &count);
860  HeapFree(GetProcessHeap(), 0, loc);
861 
862  return hr;
863 }
864 
865 /************************************************************************
866  * IPersistStream_Save (IPersistStream)
867  *
868  * FIXME: makes assumptions about byte order
869  */
871 {
872  TRACE("%p %p %x\n", this, stm, fClearDirty);
873 
874  m_Header.dwSize = sizeof(m_Header);
875  m_Header.clsid = CLSID_ShellLink;
876 
877  /*
878  * Reset the flags: keep only the flags related to data blocks as they were
879  * already set in accordance by the different mutator member functions.
880  * The other flags will be determined now by the presence or absence of data.
881  */
884 #if (NTDDI_VERSION < NTDDI_LONGHORN)
886 #endif
888  // TODO: When we will support Vista+ functionality, add other flags to this list.
889 
890  /* The stored strings are in UNICODE */
892 
893  if (m_pPidl)
895  if (m_sPath)
899  if (m_sPathRel && *m_sPathRel)
901  if (m_sWorkDir && *m_sWorkDir)
903  if (m_sArgs && *m_sArgs)
905  if (m_sIcoPath && *m_sIcoPath)
907  if (m_bRunAs)
909 
910  /* Write the shortcut header */
911  ULONG count;
912  HRESULT hr = stm->Write(&m_Header, sizeof(m_Header), &count);
913  if (FAILED(hr))
914  {
915  ERR("Write failed\n");
916  return hr;
917  }
918 
919  /* Save the data in order */
920 
921  if (m_pPidl)
922  {
923  hr = ILSaveToStream(stm, m_pPidl);
924  if (FAILED(hr))
925  {
926  ERR("Failed to write PIDL\n");
927  return hr;
928  }
929  }
930 
931  if (m_sPath)
932  {
934  if (FAILED(hr))
935  return hr;
936  }
937 
939  {
941  if (FAILED(hr))
942  return hr;
943  }
944 
946  {
948  if (FAILED(hr))
949  return hr;
950  }
951 
953  {
955  if (FAILED(hr))
956  return hr;
957  }
958 
960  {
961  hr = Stream_WriteString(stm, m_sArgs);
962  if (FAILED(hr))
963  return hr;
964  }
965 
967  {
969  if (FAILED(hr))
970  return hr;
971  }
972 
973  /*
974  * Now save the data block list.
975  *
976  * NOTE that both advertised Product and Component are already saved
977  * inside Logo3 and Darwin data blocks in the m_pDBList list, and the
978  * m_Header.dwFlags is suitably initialized.
979  */
981  if (FAILED(hr))
982  return hr;
983 
984  /* Clear the dirty bit if requested */
985  if (fClearDirty)
986  m_bDirty = FALSE;
987 
988  return hr;
989 }
990 
991 /************************************************************************
992  * IPersistStream_GetSizeMax (IPersistStream)
993  */
995 {
996  TRACE("(%p)\n", this);
997  return E_NOTIMPL;
998 }
999 
1001 {
1003  return FALSE;
1004 
1005  return TRUE;
1006 }
1007 
1008 /**************************************************************************
1009  * ShellLink_UpdatePath
1010  * update absolute path in sPath using relative path in sPathRel
1011  */
1012 static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath)
1013 {
1014  if (!path || !psPath)
1015  return E_INVALIDARG;
1016 
1017  if (!*psPath && sPathRel)
1018  {
1019  WCHAR buffer[2*MAX_PATH], abs_path[2*MAX_PATH];
1020  LPWSTR final = NULL;
1021 
1022  /* first try if [directory of link file] + [relative path] finds an existing file */
1023 
1024  GetFullPathNameW(path, MAX_PATH * 2, buffer, &final);
1025  if (!final)
1026  final = buffer;
1027  wcscpy(final, sPathRel);
1028 
1029  *abs_path = '\0';
1030 
1032  {
1033  if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
1034  wcscpy(abs_path, buffer);
1035  }
1036  else
1037  {
1038  /* try if [working directory] + [relative path] finds an existing file */
1039  if (sWorkDir)
1040  {
1041  wcscpy(buffer, sWorkDir);
1042  wcscpy(PathAddBackslashW(buffer), sPathRel);
1043 
1045  if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
1046  wcscpy(abs_path, buffer);
1047  }
1048  }
1049 
1050  /* FIXME: This is even not enough - not all shell links can be resolved using this algorithm. */
1051  if (!*abs_path)
1052  wcscpy(abs_path, sPathRel);
1053 
1054  *psPath = strdupW(abs_path);
1055  if (!*psPath)
1056  return E_OUTOFMEMORY;
1057  }
1058 
1059  return S_OK;
1060 }
1061 
1063 {
1064  HRESULT hr;
1065  LPWSTR pszFileW;
1066  WIN32_FIND_DATAW wfd;
1067 
1068  TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
1069  this, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(m_sPath));
1070 
1071  /* Allocate a temporary UNICODE buffer */
1072  pszFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchMaxPath * sizeof(WCHAR));
1073  if (!pszFileW)
1074  return E_OUTOFMEMORY;
1075 
1076  /* Call the UNICODE function */
1077  hr = GetPath(pszFileW, cchMaxPath, &wfd, fFlags);
1078 
1079  /* Convert the file path back to ANSI */
1080  WideCharToMultiByte(CP_ACP, 0, pszFileW, -1,
1081  pszFile, cchMaxPath, NULL, NULL);
1082 
1083  /* Free the temporary buffer */
1084  HeapFree(GetProcessHeap(), 0, pszFileW);
1085 
1086  if (pfd)
1087  {
1088  ZeroMemory(pfd, sizeof(*pfd));
1089 
1090  /* Copy the file data if a file path was returned */
1091  if (*pszFile)
1092  {
1093  DWORD len;
1094 
1095  /* Copy the fixed part */
1096  CopyMemory(pfd, &wfd, FIELD_OFFSET(WIN32_FIND_DATAA, cFileName));
1097 
1098  /* Convert the file names to ANSI */
1099  len = lstrlenW(wfd.cFileName);
1100  WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, len + 1,
1101  pfd->cFileName, sizeof(pfd->cFileName), NULL, NULL);
1102  len = lstrlenW(wfd.cAlternateFileName);
1103  WideCharToMultiByte(CP_ACP, 0, wfd.cAlternateFileName, len + 1,
1104  pfd->cAlternateFileName, sizeof(pfd->cAlternateFileName), NULL, NULL);
1105  }
1106  }
1107 
1108  return hr;
1109 }
1110 
1112 {
1113  TRACE("(%p)->(ppidl=%p)\n", this, ppidl);
1114 
1115  if (!m_pPidl)
1116  {
1117  *ppidl = NULL;
1118  return S_FALSE;
1119  }
1120 
1121  *ppidl = ILClone(m_pPidl);
1122  return S_OK;
1123 }
1124 
1126 {
1127  TRACE("(%p)->(pidl=%p)\n", this, pidl);
1128  return SetTargetFromPIDLOrPath(pidl, NULL);
1129 }
1130 
1132 {
1133  TRACE("(%p)->(%p len=%u)\n", this, pszName, cchMaxName);
1134 
1135  if (cchMaxName)
1136  *pszName = 0;
1137 
1138  if (m_sDescription)
1140  pszName, cchMaxName, NULL, NULL);
1141 
1142  return S_OK;
1143 }
1144 
1146 {
1147  TRACE("(%p)->(pName=%s)\n", this, pszName);
1148 
1150  m_sDescription = NULL;
1151 
1152  if (pszName)
1153  {
1155  if (!m_sDescription)
1156  return E_OUTOFMEMORY;
1157  }
1158  m_bDirty = TRUE;
1159 
1160  return S_OK;
1161 }
1162 
1164 {
1165  TRACE("(%p)->(%p len=%u)\n", this, pszDir, cchMaxPath);
1166 
1167  if (cchMaxPath)
1168  *pszDir = 0;
1169 
1170  if (m_sWorkDir)
1172  pszDir, cchMaxPath, NULL, NULL);
1173 
1174  return S_OK;
1175 }
1176 
1178 {
1179  TRACE("(%p)->(dir=%s)\n", this, pszDir);
1180 
1182  m_sWorkDir = NULL;
1183 
1184  if (pszDir)
1185  {
1187  if (!m_sWorkDir)
1188  return E_OUTOFMEMORY;
1189  }
1190  m_bDirty = TRUE;
1191 
1192  return S_OK;
1193 }
1194 
1196 {
1197  TRACE("(%p)->(%p len=%u)\n", this, pszArgs, cchMaxPath);
1198 
1199  if (cchMaxPath)
1200  *pszArgs = 0;
1201 
1202  if (m_sArgs)
1204  pszArgs, cchMaxPath, NULL, NULL);
1205 
1206  return S_OK;
1207 }
1208 
1210 {
1211  TRACE("(%p)->(args=%s)\n", this, pszArgs);
1212 
1214  m_sArgs = NULL;
1215 
1216  if (pszArgs)
1217  {
1218  m_sArgs = HEAP_strdupAtoW(GetProcessHeap(), 0, pszArgs);
1219  if (!m_sArgs)
1220  return E_OUTOFMEMORY;
1221  }
1222  m_bDirty = TRUE;
1223 
1224  return S_OK;
1225 }
1226 
1228 {
1229  TRACE("(%p)->(%p)(0x%08x)\n", this, pwHotkey, m_Header.wHotKey);
1230  *pwHotkey = m_Header.wHotKey;
1231  return S_OK;
1232 }
1233 
1235 {
1236  TRACE("(%p)->(hotkey=%x)\n", this, wHotkey);
1237 
1238  m_Header.wHotKey = wHotkey;
1239  m_bDirty = TRUE;
1240 
1241  return S_OK;
1242 }
1243 
1245 {
1246  TRACE("(%p)->(%p) %d\n", this, piShowCmd, m_Header.nShowCommand);
1247  *piShowCmd = m_Header.nShowCommand;
1248  return S_OK;
1249 }
1250 
1252 {
1253  TRACE("(%p) %d\n", this, iShowCmd);
1254 
1255  m_Header.nShowCommand = iShowCmd;
1256  m_bDirty = TRUE;
1257 
1258  return S_OK;
1259 }
1260 
1262 {
1263  HRESULT hr;
1264  LPWSTR pszIconPathW;
1265 
1266  TRACE("(%p)->(%p len=%u iicon=%p)\n", this, pszIconPath, cchIconPath, piIcon);
1267 
1268  /* Allocate a temporary UNICODE buffer */
1269  pszIconPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchIconPath * sizeof(WCHAR));
1270  if (!pszIconPathW)
1271  return E_OUTOFMEMORY;
1272 
1273  /* Call the UNICODE function */
1274  hr = GetIconLocation(pszIconPathW, cchIconPath, piIcon);
1275 
1276  /* Convert the file path back to ANSI */
1277  WideCharToMultiByte(CP_ACP, 0, pszIconPathW, -1,
1278  pszIconPath, cchIconPath, NULL, NULL);
1279 
1280  /* Free the temporary buffer */
1281  HeapFree(GetProcessHeap(), 0, pszIconPathW);
1282 
1283  return hr;
1284 }
1285 
1287 {
1288  HRESULT hr;
1289  LPWSTR pszIconFileW;
1290 
1291  TRACE("(%p)->(%u %p len=%u piIndex=%p pwFlags=%p)\n", this, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1292 
1293  /* Allocate a temporary UNICODE buffer */
1294  pszIconFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchMax * sizeof(WCHAR));
1295  if (!pszIconFileW)
1296  return E_OUTOFMEMORY;
1297 
1298  /* Call the UNICODE function */
1299  hr = GetIconLocation(uFlags, pszIconFileW, cchMax, piIndex, pwFlags);
1300 
1301  /* Convert the file path back to ANSI */
1302  WideCharToMultiByte(CP_ACP, 0, pszIconFileW, -1,
1303  pszIconFile, cchMax, NULL, NULL);
1304 
1305  /* Free the temporary buffer */
1306  HeapFree(GetProcessHeap(), 0, pszIconFileW);
1307 
1308  return hr;
1309 }
1310 
1311 HRESULT STDMETHODCALLTYPE CShellLink::Extract(PCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
1312 {
1313  TRACE("(%p)->(path=%s iicon=%u)\n", this, pszFile, nIconIndex);
1314 
1315  LPWSTR str = NULL;
1316  if (pszFile)
1317  {
1318  str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
1319  if (!str)
1320  return E_OUTOFMEMORY;
1321  }
1322 
1323  HRESULT hr = Extract(str, nIconIndex, phiconLarge, phiconSmall, nIconSize);
1324 
1325  if (str)
1326  HeapFree(GetProcessHeap(), 0, str);
1327 
1328  return hr;
1329 }
1330 
1332 {
1333  TRACE("(%p)->(path=%s iicon=%u)\n", this, pszIconPath, iIcon);
1334 
1335  LPWSTR str = NULL;
1336  if (pszIconPath)
1337  {
1338  str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath);
1339  if (!str)
1340  return E_OUTOFMEMORY;
1341  }
1342 
1343  HRESULT hr = SetIconLocation(str, iIcon);
1344 
1345  if (str)
1346  HeapFree(GetProcessHeap(), 0, str);
1347 
1348  return hr;
1349 }
1350 
1352 {
1353  TRACE("(%p)->(path=%s %x)\n", this, pszPathRel, dwReserved);
1354 
1356  m_sPathRel = NULL;
1357 
1358  if (pszPathRel)
1359  {
1360  m_sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
1361  m_bDirty = TRUE;
1362  }
1363 
1365 }
1366 
1367 static LPWSTR
1369 {
1370  DWORD Result, sz = 0;
1371 
1372  Result = CommandLineFromMsiDescriptor(component, NULL, &sz);
1373  if (Result != ERROR_SUCCESS)
1374  return NULL;
1375 
1376  sz++;
1377  LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR));
1378  Result = CommandLineFromMsiDescriptor(component, path, &sz);
1379  if (Result != ERROR_SUCCESS)
1380  {
1381  HeapFree(GetProcessHeap(), 0, path);
1382  path = NULL;
1383  }
1384 
1385  TRACE("returning %s\n", debugstr_w(path));
1386 
1387  return path;
1388 }
1389 
1391 {
1392  HRESULT hr = S_OK;
1393  BOOL bSuccess;
1394 
1395  TRACE("(%p)->(hwnd=%p flags=%x)\n", this, hwnd, fFlags);
1396 
1397  /* FIXME: use IResolveShellLink interface? */
1398 
1399  // FIXME: See InvokeCommand().
1400 
1401 #if (NTDDI_VERSION < NTDDI_LONGHORN)
1402  // NOTE: For Logo3 (EXP_LOGO3_ID_SIG), check also for SHRestricted(REST_NOLOGO3CHANNELNOTIFY)
1404  {
1405  FIXME("Logo3 links are not supported yet!\n");
1406  return E_FAIL;
1407  }
1408 #endif
1409 
1410  /* Resolve Darwin (MSI) target */
1412  {
1413  LPWSTR component = NULL;
1414  hr = GetAdvertiseInfo(&component, EXP_DARWIN_ID_SIG);
1415  if (FAILED(hr))
1416  return E_FAIL;
1417 
1418  /* Clear the cached path */
1421  if (!m_sPath)
1422  return E_FAIL;
1423  }
1424 
1425  if (!m_sPath && m_pPidl)
1426  {
1428 
1430  if (bSuccess && *buffer)
1431  {
1432  m_sPath = strdupW(buffer);
1433  if (!m_sPath)
1434  return E_OUTOFMEMORY;
1435 
1436  m_bDirty = TRUE;
1437  }
1438  else
1439  {
1440  hr = S_OK; /* don't report an error occurred while just caching information */
1441  }
1442  }
1443 
1444  // FIXME: Strange to do that here...
1445  if (!m_sIcoPath && m_sPath)
1446  {
1448  if (!m_sIcoPath)
1449  return E_OUTOFMEMORY;
1450 
1451  m_Header.nIconIndex = 0;
1452 
1453  m_bDirty = TRUE;
1454  }
1455 
1456  return hr;
1457 }
1458 
1460 {
1461  TRACE("(%p)->(path=%s)\n", this, pszFile);
1462 
1463  if (!pszFile)
1464  return E_INVALIDARG;
1465 
1466  LPWSTR str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
1467  if (!str)
1468  return E_OUTOFMEMORY;
1469 
1470  HRESULT hr = SetPath(str);
1471  HeapFree(GetProcessHeap(), 0, str);
1472 
1473  return hr;
1474 }
1475 
1477 {
1479 
1480  TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
1481  this, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(m_sPath));
1482 
1483  if (cchMaxPath)
1484  *pszFile = 0;
1485  // FIXME: What if cchMaxPath == 0 , or pszFile == NULL ??
1486 
1487  // FIXME: What about Darwin??
1488 
1489  /*
1490  * Retrieve the path to the target from the PIDL (if we have one).
1491  * NOTE: Do NOT use the cached path (m_sPath from link info).
1492  */
1494  {
1495  if (fFlags & SLGP_SHORTPATH)
1497  // FIXME: Add support for SLGP_UNCPRIORITY
1498  }
1499  else
1500  {
1501  *buffer = 0;
1502  }
1503 
1504  /* If we have a FindData structure, initialize it */
1505  if (pfd)
1506  {
1507  ZeroMemory(pfd, sizeof(*pfd));
1508 
1509  /* Copy the file data if the target is a file path */
1510  if (*buffer)
1511  {
1512  pfd->dwFileAttributes = m_Header.dwFileAttributes;
1513  pfd->ftCreationTime = m_Header.ftCreationTime;
1514  pfd->ftLastAccessTime = m_Header.ftLastAccessTime;
1515  pfd->ftLastWriteTime = m_Header.ftLastWriteTime;
1516  pfd->nFileSizeHigh = 0;
1517  pfd->nFileSizeLow = m_Header.nFileSizeLow;
1518 
1519  /*
1520  * Build temporarily a short path in pfd->cFileName (of size MAX_PATH),
1521  * then extract and store the short file name in pfd->cAlternateFileName.
1522  */
1523  GetShortPathNameW(buffer, pfd->cFileName, _countof(pfd->cFileName));
1524  lstrcpynW(pfd->cAlternateFileName,
1525  PathFindFileNameW(pfd->cFileName),
1526  _countof(pfd->cAlternateFileName));
1527 
1528  /* Now extract and store the long file name in pfd->cFileName */
1529  lstrcpynW(pfd->cFileName,
1531  _countof(pfd->cFileName));
1532  }
1533  }
1534 
1535  /* Finally check if we have a raw path the user actually wants to retrieve */
1536  if ((fFlags & SLGP_RAWPATH) && (m_Header.dwFlags & SLDF_HAS_EXP_SZ))
1537  {
1538  /* Search for a target environment block */
1539  LPEXP_SZ_LINK pInfo;
1541  if (pInfo && (pInfo->cbSize == sizeof(*pInfo)))
1542  lstrcpynW(buffer, pInfo->szwTarget, cchMaxPath);
1543  }
1544 
1545  /* For diagnostics purposes only... */
1546  // NOTE: SLGP_UNCPRIORITY is unsupported
1547  fFlags &= ~(SLGP_RAWPATH | SLGP_SHORTPATH);
1548  if (fFlags) FIXME("(%p): Unsupported flags %lu\n", this, fFlags);
1549 
1550  /* Copy the data back to the user */
1551  if (*buffer)
1552  lstrcpynW(pszFile, buffer, cchMaxPath);
1553 
1554  return (*buffer ? S_OK : S_FALSE);
1555 }
1556 
1558 {
1559  TRACE("(%p)->(%p len=%u)\n", this, pszName, cchMaxName);
1560 
1561  *pszName = 0;
1562  if (m_sDescription)
1563  lstrcpynW(pszName, m_sDescription, cchMaxName);
1564 
1565  return S_OK;
1566 }
1567 
1569 {
1570  TRACE("(%p)->(desc=%s)\n", this, debugstr_w(pszName));
1571 
1573  m_sDescription = NULL;
1574 
1575  if (pszName)
1576  {
1577  m_sDescription = strdupW(pszName);
1578  if (!m_sDescription)
1579  return E_OUTOFMEMORY;
1580  }
1581  m_bDirty = TRUE;
1582 
1583  return S_OK;
1584 }
1585 
1587 {
1588  TRACE("(%p)->(%p len %u)\n", this, pszDir, cchMaxPath);
1589 
1590  if (cchMaxPath)
1591  *pszDir = 0;
1592 
1593  if (m_sWorkDir)
1594  lstrcpynW(pszDir, m_sWorkDir, cchMaxPath);
1595 
1596  return S_OK;
1597 }
1598 
1600 {
1601  TRACE("(%p)->(dir=%s)\n", this, debugstr_w(pszDir));
1602 
1604  m_sWorkDir = NULL;
1605 
1606  if (pszDir)
1607  {
1609  if (!m_sWorkDir)
1610  return E_OUTOFMEMORY;
1611  }
1612  m_bDirty = TRUE;
1613 
1614  return S_OK;
1615 }
1616 
1618 {
1619  TRACE("(%p)->(%p len=%u)\n", this, pszArgs, cchMaxPath);
1620 
1621  if (cchMaxPath)
1622  *pszArgs = 0;
1623 
1624  if (m_sArgs)
1625  lstrcpynW(pszArgs, m_sArgs, cchMaxPath);
1626 
1627  return S_OK;
1628 }
1629 
1631 {
1632  TRACE("(%p)->(args=%s)\n", this, debugstr_w(pszArgs));
1633 
1635  m_sArgs = NULL;
1636 
1637  if (pszArgs)
1638  {
1639  m_sArgs = strdupW(pszArgs);
1640  if (!m_sArgs)
1641  return E_OUTOFMEMORY;
1642  }
1643  m_bDirty = TRUE;
1644 
1645  return S_OK;
1646 }
1647 
1649 {
1650  TRACE("(%p)->(%p len=%u iicon=%p)\n", this, pszIconPath, cchIconPath, piIcon);
1651 
1652  if (cchIconPath)
1653  *pszIconPath = 0;
1654 
1655  *piIcon = 0;
1656 
1657  /* Update the original icon path location */
1659  {
1661 
1662  /* Search for an icon environment block */
1663  LPEXP_SZ_LINK pInfo;
1665  if (pInfo && (pInfo->cbSize == sizeof(*pInfo)))
1666  {
1668 
1671 
1673  if (!m_sIcoPath)
1674  return E_OUTOFMEMORY;
1675 
1677 
1678  m_bDirty = TRUE;
1679  }
1680  }
1681 
1682  *piIcon = m_Header.nIconIndex;
1683 
1684  if (m_sIcoPath)
1685  lstrcpynW(pszIconPath, m_sIcoPath, cchIconPath);
1686 
1687  return S_OK;
1688 }
1689 
1691  UINT uFlags, PWSTR pszIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
1692 {
1693  LPCITEMIDLIST pidlLast;
1695 
1696  HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
1697  if (FAILED_UNEXPECTEDLY(hr))
1698  return hr;
1699 
1701  hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_NULL_PPV_ARG(IExtractIconW, &pei));
1702  if (FAILED_UNEXPECTEDLY(hr))
1703  return hr;
1704 
1705  hr = pei->GetIconLocation(uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1706  if (FAILED_UNEXPECTEDLY(hr))
1707  return hr;
1708 
1709  return S_OK;
1710 }
1711 
1713 {
1714  HRESULT hr;
1715 
1716  pszIconFile[0] = UNICODE_NULL;
1717 
1718  /*
1719  * It is possible for a shell link to point to another shell link,
1720  * and in particular there is the possibility to point to itself.
1721  * Now, suppose we ask such a link to retrieve its associated icon.
1722  * This function would be called, and due to COM would be called again
1723  * recursively. To solve this issue, we forbid calling GetIconLocation()
1724  * with GIL_FORSHORTCUT set in uFlags, as done by Windows (shown by tests).
1725  */
1726  if (uFlags & GIL_FORSHORTCUT)
1727  return E_INVALIDARG;
1728 
1729  /*
1730  * Now, we set GIL_FORSHORTCUT so that: i) we allow the icon extractor
1731  * of the target to give us a suited icon, and ii) we protect ourselves
1732  * against recursive call.
1733  */
1734  uFlags |= GIL_FORSHORTCUT;
1735 
1736  if (uFlags & GIL_DEFAULTICON)
1737  return S_FALSE;
1738 
1739  hr = GetIconLocation(pszIconFile, cchMax, piIndex);
1740  if (FAILED(hr) || pszIconFile[0] == UNICODE_NULL)
1741  {
1742  hr = SHELL_PidlGetIconLocationW(m_pPidl, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1743  }
1744  else
1745  {
1746  *pwFlags = GIL_NOTFILENAME | GIL_PERCLASS;
1747  }
1748 
1749  return hr;
1750 }
1751 
1753 CShellLink::Extract(PCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
1754 {
1755  HRESULT hr = NOERROR;
1756  UINT cxyLarge = LOWORD(nIconSize), cxySmall = HIWORD(nIconSize);
1757 
1758  if (phiconLarge)
1759  {
1760  *phiconLarge = NULL;
1761  PrivateExtractIconsW(pszFile, nIconIndex, cxyLarge, cxyLarge, phiconLarge, NULL, 1, 0);
1762 
1763  if (*phiconLarge == NULL)
1764  hr = S_FALSE;
1765  }
1766 
1767  if (phiconSmall)
1768  {
1769  *phiconSmall = NULL;
1770  PrivateExtractIconsW(pszFile, nIconIndex, cxySmall, cxySmall, phiconSmall, NULL, 1, 0);
1771 
1772  if (*phiconSmall == NULL)
1773  hr = S_FALSE;
1774  }
1775 
1776  if (hr == S_FALSE)
1777  {
1778  if (phiconLarge && *phiconLarge)
1779  {
1780  DestroyIcon(*phiconLarge);
1781  *phiconLarge = NULL;
1782  }
1783  if (phiconSmall && *phiconSmall)
1784  {
1785  DestroyIcon(*phiconSmall);
1786  *phiconSmall = NULL;
1787  }
1788  }
1789 
1790  return hr;
1791 }
1792 
1793 #if 0
1794 /* Extends the functionality of PathUnExpandEnvStringsW */
1795 BOOL PathFullyUnExpandEnvStringsW(
1796  _In_ LPCWSTR pszPath,
1797  _Out_ LPWSTR pszBuf,
1798  _In_ UINT cchBuf)
1799 {
1800  BOOL Ret = FALSE; // Set to TRUE as soon as PathUnExpandEnvStrings starts unexpanding.
1801  BOOL res;
1802  LPCWSTR p;
1803 
1804  // *pszBuf = L'\0';
1805  while (*pszPath && cchBuf > 0)
1806  {
1807  /* Attempt unexpanding the path */
1808  res = PathUnExpandEnvStringsW(pszPath, pszBuf, cchBuf);
1809  if (!res)
1810  {
1811  /* The unexpansion failed. Try to find a path delimiter. */
1812  p = wcspbrk(pszPath, L" /\\:*?\"<>|%");
1813  if (!p) /* None found, we will copy the remaining path */
1814  p = pszPath + wcslen(pszPath);
1815  else /* Found one, we will copy the delimiter and skip it */
1816  ++p;
1817  /* If we overflow, we cannot unexpand more, so return FALSE */
1818  if (p - pszPath >= cchBuf)
1819  return FALSE; // *pszBuf = L'\0';
1820 
1821  /* Copy the untouched portion of path up to the delimiter, included */
1822  wcsncpy(pszBuf, pszPath, p - pszPath);
1823  pszBuf[p - pszPath] = L'\0'; // NULL-terminate
1824 
1825  /* Advance the pointers and decrease the remaining buffer size */
1826  cchBuf -= (p - pszPath);
1827  pszBuf += (p - pszPath);
1828  pszPath += (p - pszPath);
1829  }
1830  else
1831  {
1832  /*
1833  * The unexpansion succeeded. Skip the unexpanded part by trying
1834  * to find where the original path and the unexpanded string
1835  * become different.
1836  * NOTE: An alternative(?) would be to stop also at the last
1837  * path delimiter encountered in the loop (i.e. would be the
1838  * first path delimiter in the strings).
1839  */
1840  LPWSTR q;
1841 
1842  /*
1843  * The algorithm starts at the end of the strings and loops back
1844  * while the characters are equal, until it finds a discrepancy.
1845  */
1846  p = pszPath + wcslen(pszPath);
1847  q = pszBuf + wcslen(pszBuf); // This wcslen should be < cchBuf
1848  while ((*p == *q) && (p > pszPath) && (q > pszBuf))
1849  {
1850  --p; --q;
1851  }
1852  /* Skip discrepancy */
1853  ++p; ++q;
1854 
1855  /* Advance the pointers and decrease the remaining buffer size */
1856  cchBuf -= (q - pszBuf);
1857  pszBuf = q;
1858  pszPath = p;
1859 
1860  Ret = TRUE;
1861  }
1862  }
1863 
1864  return Ret;
1865 }
1866 #endif
1867 
1869 {
1870  HRESULT hr = E_FAIL;
1871  WCHAR szIconPath[MAX_PATH];
1872 
1873  TRACE("(%p)->(path=%s iicon=%u)\n", this, debugstr_w(pszIconPath), iIcon);
1874 
1875  if (pszIconPath)
1876  {
1877  /*
1878  * Check whether the user-given file path contains unexpanded
1879  * environment variables. If so, create a target environment block.
1880  * Note that in this block we will store the user-given path.
1881  * It will contain the unexpanded environment variables, but
1882  * it can also contain already expanded path that the user does
1883  * not want to see them unexpanded (e.g. so that they always
1884  * refer to the same place even if the would-be corresponding
1885  * environment variable could change).
1886  */
1887 #ifdef ICON_LINK_WINDOWS_COMPAT
1888  /* Try to fully unexpand the icon path */
1889  // if (PathFullyUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath)))
1890  BOOL bSuccess = PathUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath));
1891  if (bSuccess && wcscmp(pszIconPath, szIconPath) != 0)
1892 #else
1893  /*
1894  * In some situations, described in http://stackoverflow.com/questions/2976489/ishelllinkseticonlocation-translates-my-icon-path-into-program-files-which-i
1895  * the result of PathUnExpandEnvStringsW() could be wrong, and instead
1896  * one would have to store the actual provided icon location path, while
1897  * creating an icon environment block ONLY if that path already contains
1898  * environment variables. This is what the present case is trying to implement.
1899  */
1900  SHExpandEnvironmentStringsW(pszIconPath, szIconPath, _countof(szIconPath));
1901  if (wcscmp(pszIconPath, szIconPath) != 0)
1902 #endif
1903  {
1904  /*
1905  * The user-given file path contains unexpanded environment
1906  * variables, so we need an icon environment block.
1907  */
1909  LPEXP_SZ_LINK pInfo;
1910 
1911 #ifdef ICON_LINK_WINDOWS_COMPAT
1912  /* Make pszIconPath point to the unexpanded path */
1913  LPCWSTR pszOrgIconPath = pszIconPath;
1914  pszIconPath = szIconPath;
1915 #endif
1917  if (pInfo)
1918  {
1919  /* Make sure that the size of the structure is valid */
1920  if (pInfo->cbSize != sizeof(*pInfo))
1921  {
1922  ERR("Ooops. This structure is not as expected...\n");
1923 
1924  /* Invalid structure, remove it altogether */
1927 
1928  /* Reset the pointer and go use the static buffer */
1929  pInfo = NULL;
1930  }
1931  }
1932  if (!pInfo)
1933  {
1934  /* Use the static buffer */
1935  pInfo = &buffer;
1936  buffer.cbSize = sizeof(buffer);
1937  buffer.dwSignature = EXP_SZ_ICON_SIG;
1938  }
1939 
1940  lstrcpynW(pInfo->szwTarget, pszIconPath, _countof(pInfo->szwTarget));
1941  WideCharToMultiByte(CP_ACP, 0, pszIconPath, -1,
1942  pInfo->szTarget, _countof(pInfo->szTarget), NULL, NULL);
1943 
1944  hr = S_OK;
1945  if (pInfo == &buffer)
1946  hr = AddDataBlock(pInfo);
1947  if (hr == S_OK)
1949 
1950 #ifdef ICON_LINK_WINDOWS_COMPAT
1951  /* Set pszIconPath back to the original one */
1952  pszIconPath = pszOrgIconPath;
1953 #else
1954  /* Now, make pszIconPath point to the expanded path */
1955  pszIconPath = szIconPath;
1956 #endif
1957  }
1958  else
1959  {
1960  /*
1961  * The user-given file path does not contain unexpanded environment
1962  * variables, so we need to remove any icon environment block.
1963  */
1966 
1967  /* pszIconPath points to the user path */
1968  }
1969  }
1970 
1971 #ifdef ICON_LINK_WINDOWS_COMPAT
1972  /* Store the original icon path location (may contain unexpanded environment strings) */
1973 #endif
1974  if (pszIconPath)
1975  {
1978 
1979  m_sIcoPath = strdupW(pszIconPath);
1980  if (!m_sIcoPath)
1981  return E_OUTOFMEMORY;
1982 
1984  }
1985 
1986  hr = S_OK;
1987 
1988  m_Header.nIconIndex = iIcon;
1989  m_bDirty = TRUE;
1990 
1991  return hr;
1992 }
1993 
1995 {
1996  TRACE("(%p)->(path=%s %x)\n", this, debugstr_w(pszPathRel), dwReserved);
1997 
1999  m_sPathRel = NULL;
2000 
2001  if (pszPathRel)
2002  {
2003  m_sPathRel = strdupW(pszPathRel);
2004  if (!m_sPathRel)
2005  return E_OUTOFMEMORY;
2006  }
2007  m_bDirty = TRUE;
2008 
2010 }
2011 
2013 {
2014  if (!str)
2015  return NULL;
2016 
2017  LPCWSTR p = wcschr(str, L':');
2018  if (!p)
2019  return NULL;
2020 
2021  DWORD len = p - str;
2022  LPWSTR ret = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (len + 1));
2023  if (!ret)
2024  return ret;
2025 
2026  memcpy(ret, str, sizeof(WCHAR)*len);
2027  ret[len] = 0;
2028  return ret;
2029 }
2030 
2032 {
2034  LPEXP_DARWIN_LINK pInfo;
2035 
2036  if ( (dwSig != EXP_DARWIN_ID_SIG)
2038  && (dwSig != EXP_LOGO3_ID_SIG)
2039 #endif
2040  )
2041  {
2042  return E_INVALIDARG;
2043  }
2044 
2045  if (!string)
2046  return S_FALSE;
2047 
2048  pInfo = (LPEXP_DARWIN_LINK)SHFindDataBlock(m_pDBList, dwSig);
2049  if (pInfo)
2050  {
2051  /* Make sure that the size of the structure is valid */
2052  if (pInfo->dbh.cbSize != sizeof(*pInfo))
2053  {
2054  ERR("Ooops. This structure is not as expected...\n");
2055 
2056  /* Invalid structure, remove it altogether */
2057  if (dwSig == EXP_DARWIN_ID_SIG)
2059 #if (NTDDI_VERSION < NTDDI_LONGHORN)
2060  else if (dwSig == EXP_LOGO3_ID_SIG)
2062 #endif
2063  RemoveDataBlock(dwSig);
2064 
2065  /* Reset the pointer and go use the static buffer */
2066  pInfo = NULL;
2067  }
2068  }
2069  if (!pInfo)
2070  {
2071  /* Use the static buffer */
2072  pInfo = &buffer;
2073  buffer.dbh.cbSize = sizeof(buffer);
2074  buffer.dbh.dwSignature = dwSig;
2075  }
2076 
2077  lstrcpynW(pInfo->szwDarwinID, string, _countof(pInfo->szwDarwinID));
2078  WideCharToMultiByte(CP_ACP, 0, string, -1,
2079  pInfo->szDarwinID, _countof(pInfo->szDarwinID), NULL, NULL);
2080 
2081  HRESULT hr = S_OK;
2082  if (pInfo == &buffer)
2083  hr = AddDataBlock(pInfo);
2084  if (hr == S_OK)
2085  {
2086  if (dwSig == EXP_DARWIN_ID_SIG)
2088 #if (NTDDI_VERSION < NTDDI_LONGHORN)
2089  else if (dwSig == EXP_LOGO3_ID_SIG)
2091 #endif
2092  }
2093 
2094  return hr;
2095 }
2096 
2098 {
2099  HRESULT hr;
2100  LPCWSTR szComponent = NULL, szProduct = NULL, p;
2101  INT len;
2102  GUID guid;
2103  WCHAR szGuid[38+1];
2104 
2105  sProduct = sComponent = NULL;
2106 
2107  while (str[0])
2108  {
2109  /* each segment must start with two colons */
2110  if (str[0] != ':' || str[1] != ':')
2111  return E_FAIL;
2112 
2113  /* the last segment is just two colons */
2114  if (!str[2])
2115  break;
2116  str += 2;
2117 
2118  /* there must be a colon straight after a guid */
2119  p = wcschr(str, L':');
2120  if (!p)
2121  return E_FAIL;
2122  len = p - str;
2123  if (len != 38)
2124  return E_FAIL;
2125 
2126  /* get the guid, and check if it's validly formatted */
2127  memcpy(szGuid, str, sizeof(WCHAR)*len);
2128  szGuid[len] = 0;
2129 
2131  if (hr != S_OK)
2132  return hr;
2133  str = p + 1;
2134 
2135  /* match it up to a guid that we care about */
2136  if (IsEqualGUID(guid, SHELL32_AdvtShortcutComponent) && !szComponent)
2137  szComponent = str; /* Darwin */
2138  else if (IsEqualGUID(guid, SHELL32_AdvtShortcutProduct) && !szProduct)
2139  szProduct = str; /* Logo3 */
2140  else
2141  return E_FAIL;
2142 
2143  /* skip to the next field */
2144  str = wcschr(str, L':');
2145  if (!str)
2146  return E_FAIL;
2147  }
2148 
2149  /* we have to have a component for an advertised shortcut */
2150  if (!szComponent)
2151  return E_FAIL;
2152 
2153  szComponent = GetAdvertisedArg(szComponent);
2154  szProduct = GetAdvertisedArg(szProduct);
2155 
2156  hr = WriteAdvertiseInfo(szComponent, EXP_DARWIN_ID_SIG);
2157  // if (FAILED(hr))
2158  // return hr;
2159 #if (NTDDI_VERSION < NTDDI_LONGHORN)
2160  hr = WriteAdvertiseInfo(szProduct, EXP_LOGO3_ID_SIG);
2161  // if (FAILED(hr))
2162  // return hr;
2163 #endif
2164 
2165  HeapFree(GetProcessHeap(), 0, (PVOID)szComponent);
2166  HeapFree(GetProcessHeap(), 0, (PVOID)szProduct);
2167 
2168  if (TRACE_ON(shell))
2169  {
2171  TRACE("Component = %s\n", debugstr_w(sComponent));
2172 #if (NTDDI_VERSION < NTDDI_LONGHORN)
2173  GetAdvertiseInfo(&sProduct, EXP_LOGO3_ID_SIG);
2174  TRACE("Product = %s\n", debugstr_w(sProduct));
2175 #endif
2176  }
2177 
2178  return S_OK;
2179 }
2180 
2181 /*
2182  * Since the real PathResolve (from Wine) is unimplemented at the moment,
2183  * we use this local implementation, until a better one is written (using
2184  * code parts of the SHELL_xxx helpers in Wine's shellpath.c).
2185  */
2187  IN OUT PWSTR pszPath,
2188  IN PZPCWSTR dirs OPTIONAL,
2189  IN UINT fFlags)
2190 {
2191  // FIXME: This is unimplemented!!!
2192 #if 0
2193  return PathResolve(pszPath, dirs, fFlags);
2194 #else
2195  BOOL Success = FALSE;
2196  USHORT i;
2197  LPWSTR fname = NULL;
2199 
2200  /* First, search for a valid existing path */
2201 
2202  // NOTE: See also: SHELL_FindExecutable()
2203 
2204  /*
2205  * List of extensions searched for, by PathResolve with the flag
2206  * PRF_TRYPROGRAMEXTENSIONS == PRF_EXECUTABLE | PRF_VERIFYEXISTS set,
2207  * according to MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/bb776478(v=vs.85).aspx
2208  */
2209  static PCWSTR Extensions[] = {L".pif", L".com", L".bat", L".cmd", L".lnk", L".exe", NULL};
2210  #define LNK_EXT_INDEX 4 // ".lnk" has index 4 in the array above
2211 
2212  /*
2213  * Start at the beginning of the list if PRF_EXECUTABLE is set, otherwise
2214  * just use the last element 'NULL' (no extension checking).
2215  */
2216  i = ((fFlags & PRF_EXECUTABLE) ? 0 : _countof(Extensions) - 1);
2217  for (; i < _countof(Extensions); ++i)
2218  {
2219  /* Ignore shell links ".lnk" if needed */
2220  if ((fFlags & PRF_DONTFINDLNK) && (i == LNK_EXT_INDEX))
2221  continue;
2222 
2223  Success = (SearchPathW(NULL, pszPath, Extensions[i],
2224  _countof(szPath), szPath, NULL) != 0);
2225  if (!Success)
2226  {
2227  ERR("SearchPathW(pszPath = '%S') failed. Error code: %lu\n", pszPath, GetLastError());
2228  }
2229  else
2230  {
2231  ERR("SearchPathW(pszPath = '%S', szPath = '%S') succeeded\n", pszPath, szPath);
2232  break;
2233  }
2234  }
2235 
2236  if (!Success)
2237  {
2238  ERR("SearchPathW(pszPath = '%S') failed. Error code: %lu\n", pszPath, GetLastError());
2239 
2240  /* We failed, try with PathFindOnPath, as explained by MSDN */
2241  // Success = PathFindOnPathW(pszPath, dirs);
2242  StringCchCopyW(szPath, _countof(szPath), pszPath);
2243  Success = PathFindOnPathW(szPath, dirs);
2244  if (!Success)
2245  {
2246  ERR("PathFindOnPathW(pszPath = '%S') failed\n", pszPath);
2247 
2248  /* We failed again, fall back to building a possible non-existing path */
2249  if (!GetFullPathNameW(pszPath, _countof(szPath), szPath, &fname))
2250  {
2251  ERR("GetFullPathNameW(pszPath = '%S') failed. Error code: %lu\n", pszPath, GetLastError());
2252  return FALSE;
2253  }
2254 
2256  if (!Success)
2257  ERR("PathFileExistsW(szPath = '%S') failed. Error code: %lu\n", szPath, GetLastError());
2258 
2259  /******************************************************/
2260  /* Question: Why this line is needed only for files?? */
2261  if (fname && (_wcsicmp(pszPath, fname) == 0))
2262  *szPath = L'\0';
2263  /******************************************************/
2264  }
2265  else
2266  {
2267  ERR("PathFindOnPathW(pszPath = '%S' ==> '%S') succeeded\n", pszPath, szPath);
2268  }
2269  }
2270 
2271  /* Copy back the results to the caller */
2272  StringCchCopyW(pszPath, MAX_PATH, szPath);
2273 
2274  /*
2275  * Since the called functions always checked whether the file path existed,
2276  * we do not need to redo a final check: we can use instead the cached
2277  * result in 'Success'.
2278  */
2279  return ((fFlags & PRF_VERIFYEXISTS) ? Success : TRUE);
2280 #endif
2281 }
2282 
2284 {
2285  HRESULT hr = S_OK;
2286  LPITEMIDLIST pidlNew = NULL;
2288 
2289  /*
2290  * Not both 'pidl' and 'pszFile' should be set.
2291  * But either one or both can be NULL.
2292  */
2293  if (pidl && pszFile)
2294  return E_FAIL;
2295 
2296  if (pidl)
2297  {
2298  /* Clone the PIDL */
2299  pidlNew = ILClone(pidl);
2300  if (!pidlNew)
2301  return E_FAIL;
2302  }
2303  else if (pszFile)
2304  {
2305  /* Build a PIDL for this path target */
2306  hr = SHILCreateFromPathW(pszFile, &pidlNew, NULL);
2307  if (FAILED(hr))
2308  {
2309  /* This failed, try to resolve the path, then create a simple PIDL */
2310 
2311  StringCchCopyW(szPath, _countof(szPath), pszFile);
2312  // FIXME: Because PathResolve is unimplemented, we use our hackish implementation!
2314 
2315  pidlNew = SHSimpleIDListFromPathW(szPath);
2316  /******************************************************/
2317  /* Question: Why this line is needed only for files?? */
2318  hr = (*szPath ? S_OK : E_INVALIDARG); // S_FALSE
2319  /******************************************************/
2320  }
2321  }
2322  // else if (!pidl && !pszFile) { pidlNew = NULL; hr = S_OK; }
2323 
2324  ILFree(m_pPidl);
2325  m_pPidl = pidlNew;
2326 
2327  if (!pszFile)
2328  {
2329  if (SHGetPathFromIDListW(pidlNew, szPath))
2330  pszFile = szPath;
2331  }
2332 
2333  // TODO: Fully update link info, tracker, file attribs...
2334 
2335  // if (pszFile)
2336  if (!pszFile)
2337  {
2338  *szPath = L'\0';
2339  pszFile = szPath;
2340  }
2341 
2342  /* Update the cached path (for link info) */
2343  ShellLink_GetVolumeInfo(pszFile, &volume);
2344 
2345  if (m_sPath)
2347 
2348  m_sPath = strdupW(pszFile);
2349  if (!m_sPath)
2350  return E_OUTOFMEMORY;
2351 
2352  m_bDirty = TRUE;
2353  return hr;
2354 }
2355 
2357 {
2358  LPWSTR unquoted = NULL;
2359  HRESULT hr = S_OK;
2360 
2361  TRACE("(%p)->(path=%s)\n", this, debugstr_w(pszFile));
2362 
2363  if (!pszFile)
2364  return E_INVALIDARG;
2365 
2366  /*
2367  * Allow upgrading Logo3 shortcuts (m_Header.dwFlags & SLDF_HAS_LOGO3ID),
2368  * but forbid upgrading Darwin ones.
2369  */
2371  return S_FALSE;
2372 
2373  /* quotes at the ends of the string are stripped */
2374  SIZE_T len = wcslen(pszFile);
2375  if (pszFile[0] == L'"' && pszFile[len-1] == L'"')
2376  {
2377  unquoted = strdupW(pszFile);
2378  PathUnquoteSpacesW(unquoted);
2379  pszFile = unquoted;
2380  }
2381 
2382  /* any other quote marks are invalid */
2383  if (wcschr(pszFile, L'"'))
2384  {
2385  hr = S_FALSE;
2386  goto end;
2387  }
2388 
2389  /* Clear the cached path */
2391  m_sPath = NULL;
2392 
2393  /* Check for an advertised target (Logo3 or Darwin) */
2394  if (SetAdvertiseInfo(pszFile) != S_OK)
2395  {
2396  /* This is not an advertised target, but a regular path */
2398 
2399  /*
2400  * Check whether the user-given file path contains unexpanded
2401  * environment variables. If so, create a target environment block.
2402  * Note that in this block we will store the user-given path.
2403  * It will contain the unexpanded environment variables, but
2404  * it can also contain already expanded path that the user does
2405  * not want to see them unexpanded (e.g. so that they always
2406  * refer to the same place even if the would-be corresponding
2407  * environment variable could change).
2408  */
2409  if (*pszFile)
2411  else
2412  *szPath = L'\0';
2413 
2414  if (*pszFile && (wcscmp(pszFile, szPath) != 0))
2415  {
2416  /*
2417  * The user-given file path contains unexpanded environment
2418  * variables, so we need a target environment block.
2419  */
2421  LPEXP_SZ_LINK pInfo;
2422 
2424  if (pInfo)
2425  {
2426  /* Make sure that the size of the structure is valid */
2427  if (pInfo->cbSize != sizeof(*pInfo))
2428  {
2429  ERR("Ooops. This structure is not as expected...\n");
2430 
2431  /* Invalid structure, remove it altogether */
2434 
2435  /* Reset the pointer and go use the static buffer */
2436  pInfo = NULL;
2437  }
2438  }
2439  if (!pInfo)
2440  {
2441  /* Use the static buffer */
2442  pInfo = &buffer;
2443  buffer.cbSize = sizeof(buffer);
2444  buffer.dwSignature = EXP_SZ_LINK_SIG;
2445  }
2446 
2447  lstrcpynW(pInfo->szwTarget, pszFile, _countof(pInfo->szwTarget));
2448  WideCharToMultiByte(CP_ACP, 0, pszFile, -1,
2449  pInfo->szTarget, _countof(pInfo->szTarget), NULL, NULL);
2450 
2451  hr = S_OK;
2452  if (pInfo == &buffer)
2453  hr = AddDataBlock(pInfo);
2454  if (hr == S_OK)
2456 
2457  /* Now, make pszFile point to the expanded path */
2458  pszFile = szPath;
2459  }
2460  else
2461  {
2462  /*
2463  * The user-given file path does not contain unexpanded environment
2464  * variables, so we need to remove any target environment block.
2465  */
2468 
2469  /* pszFile points to the user path */
2470  }
2471 
2472  /* Set the target */
2473  hr = SetTargetFromPIDLOrPath(NULL, pszFile);
2474  }
2475 
2476  m_bDirty = TRUE;
2477 
2478 end:
2479  HeapFree(GetProcessHeap(), 0, unquoted);
2480  return hr;
2481 }
2482 
2484 {
2485  if (SHAddDataBlock(&m_pDBList, (DATABLOCK_HEADER*)pDataBlock))
2486  {
2487  m_bDirty = TRUE;
2488  return S_OK;
2489  }
2490  return S_FALSE;
2491 }
2492 
2494 {
2495  DATABLOCK_HEADER* pBlock;
2496  PVOID pDataBlock;
2497 
2498  TRACE("%p %08x %p\n", this, dwSig, ppDataBlock);
2499 
2500  *ppDataBlock = NULL;
2501 
2502  pBlock = SHFindDataBlock(m_pDBList, dwSig);
2503  if (!pBlock)
2504  {
2505  ERR("unknown datablock %08x (not found)\n", dwSig);
2506  return E_FAIL;
2507  }
2508 
2509  pDataBlock = LocalAlloc(LMEM_ZEROINIT, pBlock->cbSize);
2510  if (!pDataBlock)
2511  return E_OUTOFMEMORY;
2512 
2513  CopyMemory(pDataBlock, pBlock, pBlock->cbSize);
2514 
2515  *ppDataBlock = pDataBlock;
2516  return S_OK;
2517 }
2518 
2520 {
2521  if (SHRemoveDataBlock(&m_pDBList, dwSig))
2522  {
2523  m_bDirty = TRUE;
2524  return S_OK;
2525  }
2526  return S_FALSE;
2527 }
2528 
2530 {
2531  TRACE("%p %p\n", this, pdwFlags);
2532  *pdwFlags = m_Header.dwFlags;
2533  return S_OK;
2534 }
2535 
2537 {
2538 #if 0 // FIXME!
2540  m_bDirty = TRUE;
2541  return S_OK;
2542 #else
2543  FIXME("\n");
2544  return E_NOTIMPL;
2545 #endif
2546 }
2547 
2548 /**************************************************************************
2549  * CShellLink implementation of IShellExtInit::Initialize()
2550  *
2551  * Loads the shelllink from the dataobject the shell is pointing to.
2552  */
2554 {
2555  TRACE("%p %p %p %p\n", this, pidlFolder, pdtobj, hkeyProgID);
2556 
2557  if (!pdtobj)
2558  return E_FAIL;
2559 
2560  FORMATETC format;
2561  format.cfFormat = CF_HDROP;
2562  format.ptd = NULL;
2563  format.dwAspect = DVASPECT_CONTENT;
2564  format.lindex = -1;
2565  format.tymed = TYMED_HGLOBAL;
2566 
2567  STGMEDIUM stgm;
2568  HRESULT hr = pdtobj->GetData(&format, &stgm);
2569  if (FAILED(hr))
2570  return hr;
2571 
2572  UINT count = DragQueryFileW((HDROP)stgm.hGlobal, -1, NULL, 0);
2573  if (count == 1)
2574  {
2575  count = DragQueryFileW((HDROP)stgm.hGlobal, 0, NULL, 0);
2576  count++;
2577  LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
2578  if (path)
2579  {
2580  count = DragQueryFileW((HDROP)stgm.hGlobal, 0, path, count);
2581  hr = Load(path, 0);
2582  HeapFree(GetProcessHeap(), 0, path);
2583  }
2584  }
2585  ReleaseStgMedium(&stgm);
2586 
2587  return S_OK;
2588 }
2589 
2591 {
2592  INT id = 0;
2593 
2594  m_idCmdFirst = idCmdFirst;
2595 
2596  TRACE("%p %p %u %u %u %u\n", this,
2597  hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
2598 
2599  if (!hMenu)
2600  return E_INVALIDARG;
2601 
2604 
2605  MENUITEMINFOW mii;
2606  ZeroMemory(&mii, sizeof(mii));
2607  mii.cbSize = sizeof(mii);
2608  mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
2609  mii.dwTypeData = strOpen.GetBuffer();
2610  mii.cch = wcslen(mii.dwTypeData);
2611  mii.wID = idCmdFirst + id++;
2612  mii.fState = MFS_DEFAULT | MFS_ENABLED;
2613  mii.fType = MFT_STRING;
2614  if (!InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii))
2615  return E_FAIL;
2616 
2617  mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
2618  mii.dwTypeData = strOpenFileLoc.GetBuffer();
2619  mii.cch = wcslen(mii.dwTypeData);
2620  mii.wID = idCmdFirst + id++;
2621  mii.fState = MFS_ENABLED;
2622  mii.fType = MFT_STRING;
2623  if (!InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii))
2624  return E_FAIL;
2625 
2626  UNREFERENCED_PARAMETER(indexMenu);
2627 
2628  return MAKE_HRESULT(SEVERITY_SUCCESS, 0, id);
2629 }
2630 
2632 {
2633  WCHAR szParams[MAX_PATH + 64];
2634  StringCbPrintfW(szParams, sizeof(szParams), L"/select,%s", m_sPath);
2635 
2636  INT_PTR ret;
2637  ret = reinterpret_cast<INT_PTR>(ShellExecuteW(NULL, NULL, L"explorer.exe", szParams,
2639  if (ret <= 32)
2640  {
2641  ERR("ret: %08lX\n", ret);
2642  return E_FAIL;
2643  }
2644 
2645  return S_OK;
2646 }
2647 
2649 {
2650  TRACE("%p %p\n", this, lpici);
2651 
2652  if (lpici->cbSize < sizeof(CMINVOKECOMMANDINFO))
2653  return E_INVALIDARG;
2654 
2655  // NOTE: We could use lpici->hwnd (certainly in case lpici->fMask doesn't contain CMIC_MASK_FLAG_NO_UI)
2656  // as the parent window handle... ?
2657  /* FIXME: get using interface set from IObjectWithSite?? */
2658  // NOTE: We might need an extended version of Resolve that provides us with paths...
2659  HRESULT hr = Resolve(lpici->hwnd, 0);
2660  if (FAILED(hr))
2661  {
2662  TRACE("failed to resolve component with error 0x%08x", hr);
2663  return hr;
2664  }
2665 
2666  UINT idCmd = LOWORD(lpici->lpVerb);
2667  TRACE("idCmd: %d\n", idCmd);
2668 
2669  switch (idCmd)
2670  {
2671  case IDCMD_OPEN:
2672  return DoOpen(lpici);
2674  return DoOpenFileLocation();
2675  default:
2676  return E_NOTIMPL;
2677  }
2678 }
2679 
2681 {
2682  HRESULT hr;
2683  LPWSTR args = NULL;
2685 
2686  if ( lpici->cbSize == sizeof(CMINVOKECOMMANDINFOEX) &&
2687  (lpici->fMask & CMIC_MASK_UNICODE) )
2688  {
2690  SIZE_T len = 2;
2691 
2692  if (m_sArgs)
2693  len += wcslen(m_sArgs);
2694  if (iciex->lpParametersW)
2695  len += wcslen(iciex->lpParametersW);
2696 
2697  args = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2698  *args = 0;
2699  if (m_sArgs)
2700  wcscat(args, m_sArgs);
2701  if (iciex->lpParametersW)
2702  {
2703  wcscat(args, L" ");
2704  wcscat(args, iciex->lpParametersW);
2705  }
2706  }
2707  else if (m_sArgs != NULL)
2708  {
2709  args = strdupW(m_sArgs);
2710  }
2711 
2712  SHELLEXECUTEINFOW sei;
2713  ZeroMemory(&sei, sizeof(sei));
2714  sei.cbSize = sizeof(sei);
2717  sei.lpFile = path;
2718  sei.lpClass = m_sLinkPath;
2719  sei.nShow = m_Header.nShowCommand;
2720  sei.lpDirectory = m_sWorkDir;
2721  sei.lpParameters = args;
2722  sei.lpVerb = L"open";
2723 
2724  // HACK for ShellExecuteExW
2725  if (m_sPath && wcsstr(m_sPath, L".cpl"))
2726  sei.lpVerb = L"cplopen";
2727 
2728  if (ShellExecuteExW(&sei))
2729  hr = S_OK;
2730  else
2731  hr = E_FAIL;
2732 
2733  HeapFree(GetProcessHeap(), 0, args);
2734  HeapFree(GetProcessHeap(), 0, path);
2735 
2736  return hr;
2737 }
2738 
2740 {
2741  FIXME("%p %lu %u %p %p %u\n", this, idCmd, uType, pwReserved, pszName, cchMax);
2742  return E_NOTIMPL;
2743 }
2744 
2747 {
2748  switch(uMsg)
2749  {
2750  case WM_INITDIALOG:
2751  if (lParam)
2752  {
2753  HWND hDlgCtrl = GetDlgItem(hwndDlg, IDC_SHORTEX_RUN_DIFFERENT);
2754  SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0);
2755  }
2756  return TRUE;
2757  case WM_COMMAND:
2758  {
2759  HWND hDlgCtrl = GetDlgItem(hwndDlg, IDC_SHORTEX_RUN_DIFFERENT);
2760  if (LOWORD(wParam) == IDOK)
2761  {
2762  if (SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED)
2763  EndDialog(hwndDlg, 1);
2764  else
2765  EndDialog(hwndDlg, 0);
2766  }
2767  else if (LOWORD(wParam) == IDCANCEL)
2768  {
2769  EndDialog(hwndDlg, -1);
2770  }
2772  {
2773  if (SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED)
2774  SendMessage(hDlgCtrl, BM_SETCHECK, BST_UNCHECKED, 0);
2775  else
2776  SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0);
2777  }
2778  }
2779  }
2780  return FALSE;
2781 }
2782 
2783 /**************************************************************************
2784 * SH_GetTargetTypeByPath
2785 *
2786 * Function to get target type by passing full path to it
2787 */
2789 {
2790  LPCWSTR pwszExt;
2791  static WCHAR wszBuf[MAX_PATH];
2792 
2793  /* Get file information */
2794  SHFILEINFOW fi;
2795  if (!SHGetFileInfoW(lpcwFullPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES))
2796  {
2797  ERR("SHGetFileInfoW failed for %ls (%lu)\n", lpcwFullPath, GetLastError());
2798  fi.szTypeName[0] = L'\0';
2799  fi.hIcon = NULL;
2800  }
2801 
2802  pwszExt = PathFindExtensionW(lpcwFullPath);
2803  if (pwszExt[0])
2804  {
2805  if (!fi.szTypeName[0])
2806  {
2807  /* The file type is unknown, so default to string "FileExtension File" */
2808  size_t cchRemaining = 0;
2809  LPWSTR pwszEnd = NULL;
2810 
2811  StringCchPrintfExW(wszBuf, _countof(wszBuf), &pwszEnd, &cchRemaining, 0, L"%s ", pwszExt + 1);
2812  }
2813  else
2814  {
2815  /* Update file type */
2816  StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s (%s)", fi.szTypeName, pwszExt);
2817  }
2818  }
2819 
2820  return wszBuf;
2821 }
2822 
2824 {
2825  TRACE("CShellLink::OnInitDialog(hwnd %p hwndFocus %p lParam %p)\n", hwndDlg, hwndFocus, lParam);
2826 
2827  TRACE("m_sArgs: %S sComponent: %S m_sDescription: %S m_sIcoPath: %S m_sPath: %S m_sPathRel: %S sProduct: %S m_sWorkDir: %S\n", m_sArgs, sComponent, m_sDescription,
2829 
2830  m_bInInit = TRUE;
2831 
2832  /* Get file information */
2833  // FIXME! FIXME! Shouldn't we use m_sIcoPath, m_Header.nIconIndex instead???
2834  SHFILEINFOW fi;
2835  if (!SHGetFileInfoW(m_sLinkPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME | SHGFI_ICON))
2836  {
2837  ERR("SHGetFileInfoW failed for %ls (%lu)\n", m_sLinkPath, GetLastError());
2838  fi.szTypeName[0] = L'\0';
2839  fi.hIcon = NULL;
2840  }
2841 
2842  if (fi.hIcon)
2843  {
2844  if (m_hIcon)
2846  m_hIcon = fi.hIcon;
2848  }
2849  else
2850  ERR("ExtractIconW failed %ls %u\n", m_sIcoPath, m_Header.nIconIndex);
2851 
2852  /* Target type */
2853  if (m_sPath)
2855 
2856  /* Target location */
2857  if (m_sPath)
2858  {
2863  }
2864 
2865  /* Target path */
2866  if (m_sPath)
2867  {
2868  WCHAR newpath[2*MAX_PATH] = L"\0";
2869  if (wcschr(m_sPath, ' '))
2870  StringCchPrintfExW(newpath, _countof(newpath), NULL, NULL, 0, L"\"%ls\"", m_sPath);
2871  else
2872  StringCchCopyExW(newpath, _countof(newpath), m_sPath, NULL, NULL, 0);
2873 
2874  if (m_sArgs && m_sArgs[0])
2875  {
2876  StringCchCatW(newpath, _countof(newpath), L" ");
2877  StringCchCatW(newpath, _countof(newpath), m_sArgs);
2878  }
2879  SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, newpath);
2880  }
2881 
2882  /* Working dir */
2883  if (m_sWorkDir)
2885 
2886  /* Description */
2887  if (m_sDescription)
2889 
2890  m_bInInit = FALSE;
2891 
2892  return TRUE;
2893 }
2894 
2895 void CShellLink::OnCommand(HWND hwndDlg, int id, HWND hwndCtl, UINT codeNotify)
2896 {
2897  switch (id)
2898  {
2899  case IDC_SHORTCUT_FIND:
2905  return;
2906 
2908  {
2909  WCHAR wszPath[MAX_PATH] = L"";
2910 
2911  if (m_sIcoPath)
2912  wcscpy(wszPath, m_sIcoPath);
2913  else
2914  FindExecutableW(m_sPath, NULL, wszPath);
2915 
2917  if (PickIconDlg(hwndDlg, wszPath, _countof(wszPath), &IconIndex))
2918  {
2919  SetIconLocation(wszPath, IconIndex);
2920  PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
2921 
2922  HICON hIconLarge = CreateShortcutIcon(wszPath, IconIndex);
2923  if (hIconLarge)
2924  {
2925  if (m_hIcon)
2927  m_hIcon = hIconLarge;
2929  }
2930  }
2931  return;
2932  }
2933 
2934  case IDC_SHORTCUT_ADVANCED:
2935  {
2937  if (result == 1 || result == 0)
2938  {
2939  if (m_bRunAs != result)
2940  {
2941  PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
2942  }
2943 
2944  m_bRunAs = result;
2945  }
2946  return;
2947  }
2948  }
2949  if (codeNotify == EN_CHANGE)
2950  {
2951  if (!m_bInInit)
2952  PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
2953  }
2954 }
2955 
2956 LRESULT CShellLink::OnNotify(HWND hwndDlg, int idFrom, LPNMHDR pnmhdr)
2957 {
2958  WCHAR wszBuf[MAX_PATH];
2959  LPPSHNOTIFY lppsn = (LPPSHNOTIFY)pnmhdr;
2960 
2961  if (lppsn->hdr.code == PSN_APPLY)
2962  {
2963  /* set working directory */
2964  GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_START_IN_EDIT, wszBuf, _countof(wszBuf));
2965  SetWorkingDirectory(wszBuf);
2966 
2967  /* set link destination */
2968  GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, wszBuf, _countof(wszBuf));
2969  LPWSTR lpszArgs = NULL;
2970  LPWSTR unquoted = strdupW(wszBuf);
2971  StrTrimW(unquoted, L" ");
2972 
2973  if (!PathFileExistsW(unquoted))
2974  {
2975  lpszArgs = PathGetArgsW(unquoted);
2976  PathRemoveArgsW(unquoted);
2977  StrTrimW(lpszArgs, L" ");
2978  }
2979  if (unquoted[0] == '"' && unquoted[wcslen(unquoted) - 1] == '"')
2980  PathUnquoteSpacesW(unquoted);
2981 
2982  WCHAR *pwszExt = PathFindExtensionW(unquoted);
2983  if (!wcsicmp(pwszExt, L".lnk"))
2984  {
2985  // FIXME load localized error msg
2986  MessageBoxW(hwndDlg, L"You cannot create a link to a shortcut", L"Error", MB_ICONERROR);
2988  return TRUE;
2989  }
2990 
2991  if (!PathFileExistsW(unquoted))
2992  {
2993  // FIXME load localized error msg
2994  MessageBoxW(hwndDlg, L"The specified file name in the target box is invalid", L"Error", MB_ICONERROR);
2996  return TRUE;
2997  }
2998 
2999  SetPath(unquoted);
3000  if (lpszArgs)
3001  SetArguments(lpszArgs);
3002  else
3003  SetArguments(L"\0");
3004 
3005  HeapFree(GetProcessHeap(), 0, unquoted);
3006 
3007  TRACE("This %p m_sLinkPath %S\n", this, m_sLinkPath);
3008  Save(m_sLinkPath, TRUE);
3011  return TRUE;
3012  }
3013  return FALSE;
3014 }
3015 
3017 {
3018  if (m_hIcon)
3019  {
3021  m_hIcon = NULL;
3022  }
3023 }
3024 
3025 /**************************************************************************
3026  * SH_ShellLinkDlgProc
3027  *
3028  * dialog proc of the shortcut property dialog
3029  */
3030 
3033 {
3034  LPPROPSHEETPAGEW ppsp;
3035  CShellLink *pThis = reinterpret_cast<CShellLink *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
3036 
3037  switch (uMsg)
3038  {
3039  case WM_INITDIALOG:
3040  ppsp = (LPPROPSHEETPAGEW)lParam;
3041  if (ppsp == NULL)
3042  break;
3043 
3044  pThis = reinterpret_cast<CShellLink *>(ppsp->lParam);
3045  SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pThis);
3046  return pThis->OnInitDialog(hwndDlg, (HWND)(wParam), lParam);
3047 
3048  case WM_NOTIFY:
3049  return pThis->OnNotify(hwndDlg, (int)wParam, (NMHDR *)lParam);
3050 
3051  case WM_COMMAND:
3052  pThis->OnCommand(hwndDlg, LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
3053  break;
3054 
3055  case WM_DESTROY:
3056  pThis->OnDestroy(hwndDlg);
3057  break;
3058 
3059  default:
3060  break;
3061  }
3062 
3063  return FALSE;
3064 }
3065 
3066 /**************************************************************************
3067  * ShellLink_IShellPropSheetExt interface
3068  */
3069 
3071 {
3073  if (hPage == NULL)
3074  {
3075  ERR("failed to create property sheet page\n");
3076  return E_FAIL;
3077  }
3078 
3079  if (!pfnAddPage(hPage, lParam))
3080  return E_FAIL;
3081 
3082  return S_OK;
3083 }
3084 
3086 {
3087  TRACE("(%p) (uPageID %u, pfnReplacePage %p lParam %p\n", this, uPageID, pfnReplacePage, lParam);
3088  return E_NOTIMPL;
3089 }
3090 
3092 {
3093  TRACE("%p %p\n", this, punk);
3094 
3095  m_site = punk;
3096 
3097  return S_OK;
3098 }
3099 
3101 {
3102  TRACE("%p %s %p\n", this, debugstr_guid(&iid), ppvSite);
3103 
3104  if (m_site == NULL)
3105  return E_FAIL;
3106 
3107  return m_site->QueryInterface(iid, ppvSite);
3108 }
3109 
3111  DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
3112 {
3113  TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
3114 
3115  if (*pdwEffect == DROPEFFECT_NONE)
3116  return S_OK;
3117 
3118  LPCITEMIDLIST pidlLast;
3120 
3121  HRESULT hr = SHBindToParent(m_pPidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
3122 
3123  if (SUCCEEDED(hr))
3124  {
3125  hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_NULL_PPV_ARG(IDropTarget, &m_DropTarget));
3126 
3127  if (SUCCEEDED(hr))
3128  hr = m_DropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect);
3129  else
3130  *pdwEffect = DROPEFFECT_NONE;
3131  }
3132  else
3133  *pdwEffect = DROPEFFECT_NONE;
3134 
3135  return S_OK;
3136 }
3137 
3139  DWORD *pdwEffect)
3140 {
3141  TRACE("(%p)\n", this);
3142  HRESULT hr = S_OK;
3143  if (m_DropTarget)
3144  hr = m_DropTarget->DragOver(dwKeyState, pt, pdwEffect);
3145  return hr;
3146 }
3147 
3149 {
3150  TRACE("(%p)\n", this);
3151  HRESULT hr = S_OK;
3152  if (m_DropTarget)
3153  {
3154  hr = m_DropTarget->DragLeave();
3156  }
3157 
3158  return hr;
3159 }
3160 
3162  DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
3163 {
3164  TRACE("(%p)\n", this);
3165  HRESULT hr = S_OK;
3166  if (m_DropTarget)
3167  hr = m_DropTarget->Drop(pDataObject, dwKeyState, pt, pdwEffect);
3168 
3169  return hr;
3170 }
3171 
3172 /**************************************************************************
3173  * IShellLink_ConstructFromFile
3174  */
3176 {
3178  HRESULT hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IPersistFile, &ppf));
3179  if (FAILED(hr))
3180  return hr;
3181 
3182  hr = ppf->Load(path, 0);
3183  if (FAILED(hr))
3184  return hr;
3185 
3186  return ppf->QueryInterface(riid, ppv);
3187 }
3188 
3190 {
3191  WCHAR path[MAX_PATH];
3192  if (!ILGetDisplayNameExW(psf, pidl, path, 0))
3193  return E_FAIL;
3194 
3196 }
3197 
3199 {
3201  const COLORREF crMask = GetSysColor(COLOR_3DFACE);
3202  HDC hDC;
3204  HICON hIcon = NULL, hNewIcon = NULL;
3206  IMAGE_ICON, cx, cy, 0);
3207 
3208  ::ExtractIconExW(wszIconPath, IconIndex, &hIcon, NULL, 1);
3209  if (!hIcon || !hShortcut || !himl)
3210  goto cleanup;
3211 
3213  if (hDC)
3214  {
3215  // create 32bpp bitmap
3216  BITMAPINFO bi;
3217  ZeroMemory(&bi, sizeof(bi));
3218  bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
3219  bi.bmiHeader.biWidth = cx;
3220  bi.bmiHeader.biHeight = cy;
3221  bi.bmiHeader.biPlanes = 1;
3222  bi.bmiHeader.biBitCount = 32;
3223  LPVOID pvBits;
3224  HBITMAP hbm = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0);
3225  if (hbm)
3226  {
3227  // draw the icon image
3228  HGDIOBJ hbmOld = SelectObject(hDC, hbm);
3229  {
3230  HBRUSH hbr = CreateSolidBrush(crMask);
3231  RECT rc = { 0, 0, cx, cy };
3232  FillRect(hDC, &rc, hbr);
3233  DeleteObject(hbr);
3234 
3235  DrawIconEx(hDC, 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL);
3236  DrawIconEx(hDC, 0, 0, hShortcut, cx, cy, 0, NULL, DI_NORMAL);
3237  }
3238  SelectObject(hDC, hbmOld);
3239 
3240  INT iAdded = ImageList_AddMasked(himl, hbm, crMask);
3241  hNewIcon = ImageList_GetIcon(himl, iAdded, ILD_NORMAL | ILD_TRANSPARENT);
3242 
3243  DeleteObject(hbm);
3244  }
3245  DeleteDC(hDC);
3246  }
3247 
3248 cleanup:
3249  if (hIcon)
3250  DestroyIcon(hIcon);
3251  if (hShortcut)
3252  DestroyIcon(hShortcut);
3253  if (himl)
3255 
3256  return hNewIcon;
3257 }
DWORD dwHeaderSize
Definition: CShellLink.cpp:164
struct EXP_SZ_LINK * LPEXP_SZ_LINK
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
#define STM_SETICON
Definition: winuser.h:2074
#define MAKEINTRESOURCE
Definition: winuser.h:591
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define IN
Definition: typedefs.h:39
static HICON
Definition: imagelist.c:84
UINT WINAPI GetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount)
Definition: dialog.c:2271
BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
Definition: path.c:624
#define MFT_STRING
Definition: winuser.h:741
#define REFIID
Definition: guiddef.h:118
uint16_t size
Definition: btrfs_drv.h:572
#define IDOK
Definition: winuser.h:824
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:925
#define IDC_SHORTCUT_TYPE_EDIT
Definition: shresdef.h:414
#define IMAGE_ICON
Definition: winuser.h:212
INT_PTR WINAPI DialogBoxParamW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_opt_ HWND, _In_opt_ DLGPROC, _In_ LPARAM)
#define IDC_SHORTCUT_TARGET_TEXT
Definition: shresdef.h:418
#define SHGFI_TYPENAME
Definition: shellapi.h:165
BITMAPINFOHEADER bmiHeader
Definition: wingdi.h:1475
#define ERROR_SUCCESS
Definition: deptool.c:10
#define WideCharToMultiByte
Definition: compat.h:111
HRESULT hr
Definition: shlfolder.c:183
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
Definition: path.c:774
#define STG_E_INVALIDPOINTER
Definition: winerror.h:2571
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:922
#define NOERROR
Definition: winerror.h:2354
void WINAPI ReleaseStgMedium(STGMEDIUM *pmedium)
Definition: ole2.c:2033
struct _PSHNOTIFY * LPPSHNOTIFY
BOOL WINAPI DestroyIcon(_In_ HICON)
Definition: cursoricon.c:2022
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#define pt(x, y)
Definition: drawing.c:79
GLsizei const GLchar ** path
Definition: glext.h:7234
#define IDD_SHORTCUT_EXTENDED_PROPERTIES
Definition: shresdef.h:358
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
REFIID riid
Definition: precomp.h:44
uint16_t * PWSTR
Definition: typedefs.h:56
#define CP_ACP
Definition: compat.h:109
#define PRF_DONTFINDLNK
Definition: PathResolve.cpp:33
#define IDS_OPENFILELOCATION
Definition: shresdef.h:231
struct tagBITMAPINFOHEADER BITMAPINFOHEADER
#define LOCALE_USER_DEFAULT
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define IDC_SHORTCUT_ICON
Definition: shresdef.h:411
#define DATE_SHORTDATE
Definition: winnls.h:193
#define PRF_VERIFYEXISTS
Definition: PathResolve.cpp:29
#define WARN(fmt,...)
Definition: debug.h:112
#define STGM_CREATE
Definition: objbase.h:925
EXTERN_C HRESULT WINAPI SHOpenFolderAndSelectItems(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD dwFlags)
Definition: shlfolder.cpp:389
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1294
static HDC
Definition: imagelist.c:92
#define EXP_SZ_ICON_SIG
Definition: shlobj.h:1898
#define CALLBACK
Definition: compat.h:35
REFIID LPVOID * ppv
Definition: atlbase.h:39
GLdouble n
Definition: glext.h:7729
#define SEE_MASK_ASYNCOK
Definition: shellapi.h:52
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1499
#define assert(x)
Definition: debug.h:53
HRESULT GetData([in, unique] FORMATETC *pformatetcIn, [out] STGMEDIUM *pmedium)
#define SEE_MASK_HASLINKNAME
Definition: shellapi.h:48
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1044
#define ZeroMemory
Definition: winbase.h:1648
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
GLuint buffer
Definition: glext.h:5915
BOOL(CALLBACK * LPFNADDPROPSHEETPAGE)(HPROPSHEETPAGE, LPARAM)
Definition: prsht.h:327
LPWSTR dwTypeData
Definition: winuser.h:3244
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
UINT_PTR WPARAM
Definition: windef.h:207
GLuint GLuint end
Definition: gl.h:1545
DWORD dwNetworkVolTableOfs
Definition: CShellLink.cpp:168
HRESULT WINAPI SHReadDataBlockList(IStream *lpStream, LPDBLIST *lppList)
Definition: clist.c:235
#define IDC_SHORTCUT_CHANGE_ICON
Definition: shresdef.h:428
#define IDS_OPEN_VERB
Definition: shresdef.h:197
#define PSN_APPLY
Definition: prsht.h:117
UINT uFlags
Definition: api.c:59
DWORD WINAPI CommandLineFromMsiDescriptor(WCHAR *szDescriptor, WCHAR *szCommandLine, DWORD *pcchCommandLine)
Definition: msi.c:22
int32_t INT_PTR
Definition: typedefs.h:64
#define MFS_DEFAULT
Definition: winuser.h:743
char * LPSTR
Definition: xmlstorage.h:182
static LPOLESTR
Definition: stg_prop.c:27
WCHAR szTypeName[80]
Definition: shellapi.h:374
#define lstrlenW
Definition: compat.h:609
#define IID_PPV_ARG(Itype, ppType)
#define E_FAIL
Definition: ddrawi.h:102
HIMAGELIST himl
Definition: match.c:390
const GUID SHELL32_AdvtShortcutComponent
int32_t INT
Definition: typedefs.h:58
static BOOLEAN bSuccess
Definition: drive.cpp:419
#define SetWindowLongPtr
Definition: treelist.c:70
DWORD WINAPI GetSysColor(_In_ int)
BOOL WINAPI EndDialog(_In_ HWND, _In_ INT_PTR)
WPARAM wParam
Definition: combotst.c:138
#define SEVERITY_SUCCESS
Definition: winerror.h:64
#define PRF_TRYPROGRAMEXTENSIONS
Definition: PathResolve.cpp:31
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
#define DWLP_MSGRESULT
Definition: winuser.h:864
#define lstrcpynW
Definition: compat.h:597
HRESULT WINAPI ILSaveToStream(IStream *pStream, LPCITEMIDLIST pPidl)
Definition: pidl.c:342
STRSAFEAPI StringCchCatW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:325
BOOL WINAPI ImageList_Destroy(HIMAGELIST himl)
Definition: imagelist.c:928
#define ILC_COLOR32
Definition: commctrl.h:354
BOOL WINAPI SetDlgItemTextW(_In_ HWND, _In_ int, _In_ LPCWSTR)
#define IDC_SHORTCUT_LOCATION_EDIT
Definition: shresdef.h:416
UINT code
Definition: winuser.h:3134
STRSAFEAPI StringCchPrintfExW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:585
#define IDC_SHORTEX_RUN_DIFFERENT
Definition: shresdef.h:432
NMHDR hdr
Definition: prsht.h:330
const DWORD DROPEFFECT_NONE
Definition: oleidl.idl:929
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
const GUID * guid
#define COLOR_3DFACE
Definition: winuser.h:919
#define EXP_DARWIN_ID_SIG
Definition: shlobj.h:1894
HIMAGELIST WINAPI ImageList_Create(INT cx, INT cy, UINT flags, INT cInitial, INT cGrow)
Definition: imagelist.c:804
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define MFS_ENABLED
Definition: winuser.h:745
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
_In_ HANDLE _In_ DWORD _In_ DWORD _Inout_opt_ LPOVERLAPPED _In_opt_ LPTRANSMIT_FILE_BUFFERS _In_ DWORD dwReserved
Definition: mswsock.h:90
LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
Definition: path.c:289
#define MIIM_STATE
Definition: winuser.h:716
unsigned int BOOL
Definition: ntddk_ex.h:94
_Null_terminated_ PCWSTR * PZPCWSTR
Definition: ntbasedef.h:418
HANDLE WINAPI LoadImageW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_ UINT, _In_ int, _In_ int, _In_ UINT)
Definition: cursoricon.c:2172
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:652
BOOL WINAPI PickIconDlg(HWND hWndOwner, LPWSTR lpstrFile, UINT nMaxFile, INT *lpdwIconIndex)
Definition: dialogs.cpp:351
UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIcons)
Definition: iconcache.cpp:872
LPCWSTR lpDirectory
Definition: shellapi.h:332
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
BOOL WINAPI SHAddDataBlock(LPDBLIST *lppList, const DATABLOCK_HEADER *lpNewItem)
Definition: clist.c:68
struct _PSP * HPROPSHEETPAGE
Definition: mstask.idl:90
#define debugstr_w
Definition: kernel32.h:32
#define FIXME(fmt,...)
Definition: debug.h:111
BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR path, LPWSTR buffer, UINT buf_len)
Definition: path.c:4170
WORD WORD PSZ PSZ pszFileName
Definition: vdmdbg.h:41
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
#define SM_CXICON
Definition: winuser.h:962
#define S_FALSE
Definition: winerror.h:2357
#define IDC_SHORTCUT_COMMENT_EDIT
Definition: shresdef.h:426
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:581
#define E_INVALIDARG
Definition: ddrawi.h:101
const WCHAR * str
#define PSNRET_INVALID_NOCHANGEPAGE
Definition: prsht.h:131
smooth NULL
Definition: ftsmooth.c:416
struct _PROPSHEETPAGEW * LPPROPSHEETPAGEW
#define SEE_MASK_NOASYNC
Definition: shellapi.h:33
struct EXP_DARWIN_LINK * LPEXP_DARWIN_LINK
STRSAFEAPI StringCbPrintfW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:557
#define SEE_MASK_FLAG_NO_UI
Definition: shellapi.h:36
const GUID SHELL32_AdvtShortcutProduct
#define CF_HDROP
Definition: constants.h:410
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
#define _Out_
Definition: no_sal2.h:323
LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
Definition: path.c:389
LONG_PTR LPARAM
Definition: windef.h:208
#define BM_GETCHECK
Definition: winuser.h:1900
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:2263
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1756
const char * LPCSTR
Definition: xmlstorage.h:183
BOOL ILGetDisplayNameExW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPWSTR path, DWORD type)
Definition: pidl.c:91
#define MAKE_HRESULT(sev, fac, code)
Definition: dmerror.h:30
LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath)
Definition: path.c:442
#define debugstr_guid
Definition: kernel32.h:35
#define WM_DESTROY
Definition: winuser.h:1591
#define MIIM_ID
Definition: winuser.h:717
#define IDI_SHELL_SHORTCUT
Definition: shresdef.h:525
DWORD dwLocalPathOfs
Definition: CShellLink.cpp:167
#define STGM_READ
Definition: objbase.h:916
#define NTDDI_VERSION
Definition: k32.h:33
#define IID_NULL_PPV_ARG(Itype, ppType)
#define BM_SETCHECK
Definition: winuser.h:1903
#define TRACE(s)
Definition: solgame.cpp:4
BOOL WINAPI FileTimeToSystemTime(IN CONST FILETIME *lpFileTime, OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:188
GLsizeiptr size
Definition: glext.h:5919
#define GetProcessHeap()
Definition: compat.h:595
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
#define LMEM_ZEROINIT
Definition: winbase.h:356
int WINAPI MessageBoxW(_In_opt_ HWND, _In_opt_ LPCWSTR, _In_opt_ LPCWSTR, _In_ UINT)
if(!(yy_init))
Definition: macro.lex.yy.c:714
HWND WINAPI GetDlgItem(_In_opt_ HWND, _In_ int)
LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath)
Definition: pidl.c:1120
__wchar_t WCHAR
Definition: xmlstorage.h:180
DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path, DWORD dwFileAttributes, SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags)
Definition: shell32_main.c:413
BOOL WINAPI DrawIconEx(_In_ HDC, _In_ int, _In_ int, _In_ HICON, _In_ int, _In_ int, _In_ UINT, _In_opt_ HBRUSH, _In_ UINT)
Definition: cursoricon.c:1997
HICON WINAPI ImageList_GetIcon(HIMAGELIST himl, INT i, UINT fStyle)
Definition: imagelist.c:1963
#define PropSheet_Changed(d, w)
Definition: prsht.h:344
LONG HRESULT
Definition: typedefs.h:79
DWORD COLORREF
Definition: windef.h:300
#define _countof(array)
Definition: sndvol32.h:68
#define PathRemoveBackslash
Definition: shlwapi.h:1023
DWORD WINAPI GetShortPathNameW(IN LPCWSTR lpszLongPath, OUT LPWSTR lpszShortPath, IN DWORD cchBuffer)
Definition: path.c:1832
#define FAILED_UNEXPECTEDLY(hr)
Definition: shellutils.h:71
_In_ LPCSTR pszDir
Definition: shellapi.h:582
#define MAX_PATH
Definition: compat.h:34
#define WINAPI
Definition: msvc.h:6
UINT WINAPI PrivateExtractIconsW(_In_reads_(MAX_PATH) LPCWSTR szFileName, _In_ int nIconIndex, _In_ int cxIcon, _In_ int cyIcon, _Out_writes_opt_(nIcons) HICON *phicon, _Out_writes_opt_(nIcons) UINT *piconid, _In_ UINT nIcons, _In_ UINT flags)
#define CopyMemory
Definition: winbase.h:1646
#define STDMETHODCALLTYPE
Definition: bdasup.h:9
DATABLOCK_HEADER *WINAPI SHFindDataBlock(LPDBLIST lpList, DWORD dwSignature)
Definition: clist.c:424
unsigned short WORD
Definition: ntddk_ex.h:93
int WINAPI GetSystemMetrics(_In_ int)
DWORD dwFinalPathOfs
Definition: CShellLink.cpp:169
DWORD WINAPI SHExpandEnvironmentStringsW(LPCWSTR, LPWSTR, DWORD)
unsigned long DWORD
Definition: ntddk_ex.h:95
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
LRESULT WINAPI SendDlgItemMessageW(_In_ HWND, _In_ int, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
#define SHGFI_USEFILEATTRIBUTES
Definition: shellapi.h:179
GLbitfield flags
Definition: glext.h:7161
UINT cchMax
#define IDD_SHORTCUT_PROPERTIES
Definition: shresdef.h:352
static const WCHAR IconIndex[]
Definition: install.c:52
#define PSNRET_NOERROR
Definition: prsht.h:129
static PIXELFORMATDESCRIPTOR pfd
Definition: ssstars.c:67
#define wcsicmp
Definition: compat.h:15
HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
Definition: shlexec.cpp:1266
int ret
EXTERN_C void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
HRESULT WINAPI ILLoadFromStream(IStream *pStream, LPITEMIDLIST *ppPidl)
Definition: pidl.c:284
#define SM_CYICON
Definition: winuser.h:963
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
static const WCHAR L[]
Definition: oid.c:1250
LPARAM lParam
Definition: prsht.h:227
static __inline const char * debugstr_an(const char *s, int n)
Definition: compat.h:55
#define DWLP_USER
Definition: winuser.h:866
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
#define MIIM_TYPE
Definition: winuser.h:720
#define MB_ICONERROR
Definition: winuser.h:781
#define ILC_MASK
Definition: commctrl.h:347
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define DI_NORMAL
Definition: wingdi.h:72
GLenum GLsizei len
Definition: glext.h:6722
HRESULT WINAPI SHWriteDataBlockList(IStream *lpStream, LPDBLIST lpList)
Definition: clist.c:179
GLenum src
Definition: glext.h:6340
#define WM_COMMAND
Definition: winuser.h:1722
UINT WINAPI GetDriveTypeW(IN LPCWSTR lpRootPathName)
Definition: disk.c:497
#define SEE_MASK_UNICODE
Definition: shellapi.h:37
HICON hIcon
Definition: shellapi.h:370
#define BST_UNCHECKED
Definition: winuser.h:199
#define STGM_READWRITE
Definition: objbase.h:918
uint8_t label[11]
Definition: fsck.fat.h:65
STRSAFEAPI StringCchCopyExW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags)
Definition: strsafe.h:184
INT WINAPI GetDateFormatW(LCID lcid, DWORD dwFlags, const SYSTEMTIME *lpTime, LPCWSTR lpFormat, LPWSTR lpDateStr, INT cchOut)
Definition: lcformat.c:979
#define SHCNF_PATHW
Definition: shlobj.h:1764
DWORD WINAPI SearchPathW(IN LPCWSTR lpPath OPTIONAL, IN LPCWSTR lpFileName, IN LPCWSTR lpExtension OPTIONAL, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart OPTIONAL)
Definition: path.c:1297
#define IDC_SHORTCUT_FIND
Definition: shresdef.h:427
#define ERR(fmt,...)
Definition: debug.h:110
#define _In_
Definition: no_sal2.h:204
BOOL WINAPI GetVolumeInformationW(IN LPCWSTR lpRootPathName, IN LPWSTR lpVolumeNameBuffer, IN DWORD nVolumeNameSize, OUT LPDWORD lpVolumeSerialNumber OPTIONAL, OUT LPDWORD lpMaximumComponentLength OPTIONAL, OUT LPDWORD lpFileSystemFlags OPTIONAL, OUT LPWSTR lpFileSystemNameBuffer OPTIONAL, IN DWORD nFileSystemNameSize)
Definition: volume.c:226
static HDC hDC
Definition: 3dtext.c:33
#define ILD_TRANSPARENT
Definition: commctrl.h:414
ULONG_PTR SIZE_T
Definition: typedefs.h:80
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
HWND WINAPI GetParent(_In_ HWND)
#define S_OK
Definition: intsafe.h:51
struct IContextMenu::tagCMInvokeCommandInfoEx * LPCMINVOKECOMMANDINFOEX
#define SW_SHOWNORMAL
Definition: winuser.h:764
#define shell32_hInstance
DWORD dwVolTableOfs
Definition: CShellLink.cpp:166
_CRTIMP wchar_t *__cdecl wcsncpy(wchar_t *_Dest, const wchar_t *_Source, size_t _Count)
#define IDC_SHORTCUT_ADVANCED
Definition: shresdef.h:429
BOOL WINAPI DeleteDC(_In_ HDC)
HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
Definition: pidl.c:1337
BOOL WINAPI SHRemoveDataBlock(LPDBLIST *lppList, DWORD dwSignature)
Definition: clist.c:355
unsigned short USHORT
Definition: pedump.c:61
static const WCHAR szGuid[]
Definition: rtlstr.c:1892
static calc_node_t temp
Definition: rpn_ieee.c:38
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
HICON hIcon
Definition: msconfig.c:44
LPCWSTR szPath
Definition: env.c:35
LPCWSTR lpParameters
Definition: shellapi.h:331
LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl)
Definition: pidl.c:228
HBITMAP WINAPI CreateDIBSection(HDC hDC, CONST BITMAPINFO *BitmapInfo, UINT Usage, VOID **Bits, HANDLE hSection, DWORD dwOffset)
Definition: bitmap.c:197
void pdump(LPCITEMIDLIST pidl)
Definition: debughlp.cpp:248
_In_ HBITMAP hbm
Definition: ntgdi.h:2776
LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath)
Definition: path.c:501
void Release()
Definition: atlcomcli.h:140
#define E_NOTIMPL
Definition: ddrawi.h:99
signed char * PSTR
Definition: retypes.h:7
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcspbrk(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
WCHAR label[12]
Definition: CShellLink.cpp:184
VOID WINAPI PathUnquoteSpacesW(LPWSTR lpszPath)
Definition: path.c:1029
#define PRF_EXECUTABLE
Definition: PathResolve.cpp:30
BOOL WINAPI InsertMenuItemW(_In_ HMENU, _In_ UINT, _In_ BOOL, _In_ LPCMENUITEMINFOW)
unsigned int UINT
Definition: ndis.h:50
BOOL WINAPI IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
Definition: compobj.c:4112
HBRUSH WINAPI CreateSolidBrush(_In_ COLORREF)
VOID WINAPI SHFreeDataBlockList(LPDBLIST lpList)
Definition: clist.c:331
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
#define EXP_SZ_LINK_SIG
Definition: shlobj.h:1890
#define IDC_SHORTCUT_START_IN_EDIT
Definition: shresdef.h:420
#define MultiByteToWideChar
Definition: compat.h:110
HRESULT WINAPI SHILCreateFromPathW(LPCWSTR path, LPITEMIDLIST *ppidl, DWORD *attributes)
Definition: pidl.c:392
#define BST_CHECKED
Definition: winuser.h:197
BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
Definition: string.c:1869
_Out_opt_ int * cx
Definition: commctrl.h:581
#define SendMessage
Definition: winuser.h:5818
#define OUT
Definition: typedefs.h:40
GLuint res
Definition: glext.h:9613
HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
Definition: shlexec.cpp:2274
HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id)
Definition: compobj.c:2338
#define HIWORD(l)
Definition: typedefs.h:247
unsigned int ULONG
Definition: retypes.h:1
GLenum target
Definition: glext.h:7315
HRESULT WINAPI SHCreateStreamOnFileW(LPCWSTR lpszPath, DWORD dwMode, IStream **lppStream)
Definition: istream.c:484
char * cleanup(char *str)
Definition: wpickclick.c:99
HRESULT Write([in, size_is(cb)] const void *pv, [in] ULONG cb, [out] ULONG *pcbWritten)
static char * dest
Definition: rtl.c:135
INT WINAPI ImageList_AddMasked(HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
Definition: imagelist.c:563
static HBITMAP
Definition: button.c:44
HLOCAL NTAPI LocalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:1373
const char * PCSTR
Definition: typedefs.h:52
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define ILD_NORMAL
Definition: commctrl.h:413
#define SHCNE_CREATE
Definition: shlobj.h:1730
#define GetWindowLongPtr
Definition: treelist.c:73
#define SHCNE_UPDATEITEM
Definition: shlobj.h:1742
HPROPSHEETPAGE SH_CreatePropertySheetPage(LPCSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle)
#define STGM_SHARE_DENY_WRITE
Definition: objbase.h:921
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define IDCANCEL
Definition: winuser.h:825
LONG_PTR LRESULT
Definition: windef.h:209
#define DIB_RGB_COLORS
Definition: wingdi.h:366
#define E_POINTER
Definition: winerror.h:2365
#define NTDDI_LONGHORN
Definition: sdkddkver.h:102
int WINAPI FillRect(HDC, LPCRECT, HBRUSH)
#define SHGFI_ICON
Definition: shellapi.h:162
HRESULT Read([out, size_is(cb), length_is(*pcbRead)] void *pv, [in] ULONG cb, [out] ULONG *pcbRead)
GLuint64EXT * result
Definition: glext.h:11304
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
#define TRACE_ON(x)
Definition: compat.h:75
#define args
Definition: format.c:66
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:60
UINT WINAPI DragQueryFileW(HDROP hDrop, UINT lFile, LPWSTR lpszwFile, UINT lLength)
Definition: shellole.c:627
#define WM_INITDIALOG
Definition: winuser.h:1721
BOOL WINAPI PathFindOnPathW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs)
Definition: path.c:1382
LPARAM lParam
Definition: combotst.c:139
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: ifs.c:426
#define LOWORD(l)
Definition: pedump.c:82
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define HeapFree(x, y, z)
Definition: compat.h:594
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
#define WM_NOTIFY
Definition: richedit.h:61
#define SUCCEEDED(hr)
Definition: intsafe.h:49
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
#define EN_CHANGE
Definition: winuser.h:2004