ReactOS  0.4.14-dev-614-gbfd8a84
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  TRACE("(%p)->(%s)\n", this, debugstr_w(pszFileName));
348 
349  if (!pszFileName)
350  return E_FAIL;
351 
352  CComPtr<IStream> stm;
354  if (SUCCEEDED(hr))
355  {
356  hr = Save(stm, FALSE);
357 
358  if (SUCCEEDED(hr))
359  {
360  if (m_sLinkPath)
362 
364  m_bDirty = FALSE;
365  }
366  else
367  {
369  WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName));
370  }
371  }
372 
373  return hr;
374 }
375 
377 {
378  FIXME("(%p)->(%s)\n", this, debugstr_w(pszFileName));
379  return S_OK;
380 }
381 
383 {
384  *ppszFileName = NULL;
385 
386  if (!m_sLinkPath)
387  {
388  /* IPersistFile::GetCurFile called before IPersistFile::Save */
389  return S_FALSE;
390  }
391 
392  *ppszFileName = (LPOLESTR)CoTaskMemAlloc((wcslen(m_sLinkPath) + 1) * sizeof(WCHAR));
393  if (!*ppszFileName)
394  {
395  /* out of memory */
396  return E_OUTOFMEMORY;
397  }
398 
399  /* copy last saved filename */
400  wcscpy(*ppszFileName, m_sLinkPath);
401 
402  return S_OK;
403 }
404 
405 static HRESULT Stream_LoadString(IStream* stm, BOOL unicode, LPWSTR *pstr)
406 {
407  TRACE("%p\n", stm);
408 
409  USHORT len;
410  DWORD count = 0;
411  HRESULT hr = stm->Read(&len, sizeof(len), &count);
412  if (FAILED(hr) || count != sizeof(len))
413  return E_FAIL;
414 
415  if (unicode)
416  len *= sizeof(WCHAR);
417 
418  TRACE("reading %d\n", len);
419  LPSTR temp = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len + sizeof(WCHAR));
420  if (!temp)
421  return E_OUTOFMEMORY;
422  count = 0;
423  hr = stm->Read(temp, len, &count);
424  if (FAILED(hr) || count != len)
425  {
427  return E_FAIL;
428  }
429 
430  TRACE("read %s\n", debugstr_an(temp, len));
431 
432  /* convert to unicode if necessary */
433  LPWSTR str;
434  if (!unicode)
435  {
437  str = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (count + 1) * sizeof(WCHAR));
438  if (!str)
439  {
441  return E_OUTOFMEMORY;
442  }
445  }
446  else
447  {
448  count /= sizeof(WCHAR);
449  str = (LPWSTR)temp;
450  }
451  str[count] = 0;
452 
453  *pstr = str;
454 
455  return S_OK;
456 }
457 
458 
459 /*
460  * NOTE: The following 5 functions are part of LINKINFO.DLL
461  */
463 {
464  WCHAR drive[4] = { path[0], ':', '\\', 0 };
465 
466  volume->type = GetDriveTypeW(drive);
467  BOOL bRet = GetVolumeInformationW(drive, volume->label, _countof(volume->label), &volume->serial, NULL, NULL, NULL, 0);
468  TRACE("ret = %d type %d serial %08x name %s\n", bRet,
469  volume->type, volume->serial, debugstr_w(volume->label));
470  return bRet;
471 }
472 
474 {
475  struct sized_chunk
476  {
477  DWORD size;
478  unsigned char data[1];
479  } *chunk;
480 
481  TRACE("%p\n", stm);
482 
483  DWORD size;
484  ULONG count;
485  HRESULT hr = stm->Read(&size, sizeof(size), &count);
486  if (FAILED(hr) || count != sizeof(size))
487  return E_FAIL;
488 
489  chunk = static_cast<sized_chunk *>(HeapAlloc(GetProcessHeap(), 0, size));
490  if (!chunk)
491  return E_OUTOFMEMORY;
492 
493  chunk->size = size;
494  hr = stm->Read(chunk->data, size - sizeof(size), &count);
495  if (FAILED(hr) || count != (size - sizeof(size)))
496  {
498  return E_FAIL;
499  }
500 
501  TRACE("Read %d bytes\n", chunk->size);
502 
503  *data = chunk;
504 
505  return S_OK;
506 }
507 
509 {
510  volume->serial = vol->dwVolSerial;
511  volume->type = vol->dwType;
512 
513  if (!vol->dwVolLabelOfs)
514  return FALSE;
515  if (vol->dwSize <= vol->dwVolLabelOfs)
516  return FALSE;
517  INT len = vol->dwSize - vol->dwVolLabelOfs;
518 
519  LPSTR label = (LPSTR)vol;
520  label += vol->dwVolLabelOfs;
521  MultiByteToWideChar(CP_ACP, 0, label, len, volume->label, _countof(volume->label));
522 
523  return TRUE;
524 }
525 
527 {
528  UINT len = 0;
529 
530  while (len < maxlen && p[len])
531  len++;
532 
533  UINT wlen = MultiByteToWideChar(CP_ACP, 0, p, len, NULL, 0);
534  LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wlen + 1) * sizeof(WCHAR));
535  if (!path)
536  return NULL;
537  MultiByteToWideChar(CP_ACP, 0, p, len, path, wlen);
538  path[wlen] = 0;
539 
540  return path;
541 }
542 
545 {
546  char *p = NULL;
547  HRESULT hr = Stream_ReadChunk(stm, (LPVOID*) &p);
548  if (FAILED(hr))
549  return hr;
550 
551  LOCATION_INFO *loc = reinterpret_cast<LOCATION_INFO *>(p);
552  if (loc->dwTotalSize < sizeof(LOCATION_INFO))
553  {
554  HeapFree(GetProcessHeap(), 0, p);
555  return E_FAIL;
556  }
557 
558  /* if there's valid local volume information, load it */
559  if (loc->dwVolTableOfs &&
560  ((loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO)) <= loc->dwTotalSize))
561  {
563 
566  }
567 
568  /* if there's a local path, load it */
569  DWORD n = loc->dwLocalPathOfs;
570  if (n && n < loc->dwTotalSize)
571  *path = Stream_LoadPath(&p[n], loc->dwTotalSize - n);
572 
573  TRACE("type %d serial %08x name %s path %s\n", volume->type,
574  volume->serial, debugstr_w(volume->label), debugstr_w(*path));
575 
576  HeapFree(GetProcessHeap(), 0, p);
577  return S_OK;
578 }
579 
580 
581 /*
582  * The format of the advertised shortcut info is:
583  *
584  * Offset Description
585  * ------ -----------
586  * 0 Length of the block (4 bytes, usually 0x314)
587  * 4 tag (dword)
588  * 8 string data in ASCII
589  * 8+0x104 string data in UNICODE
590  *
591  * In the original Win32 implementation the buffers are not initialized
592  * to zero, so data trailing the string is random garbage.
593  */
595 {
596  LPEXP_DARWIN_LINK pInfo;
597 
598  *str = NULL;
599 
601  if (!pInfo)
602  return E_FAIL;
603 
604  /* Make sure that the size of the structure is valid */
605  if (pInfo->dbh.cbSize != sizeof(*pInfo))
606  {
607  ERR("Ooops. This structure is not as expected...\n");
608  return E_FAIL;
609  }
610 
611  TRACE("dwSig %08x string = '%s'\n", pInfo->dbh.dwSignature, debugstr_w(pInfo->szwDarwinID));
612 
613  *str = pInfo->szwDarwinID;
614  return S_OK;
615 }
616 
617 /************************************************************************
618  * IPersistStream_Load (IPersistStream)
619  */
621 {
622  TRACE("%p %p\n", this, stm);
623 
624  if (!stm)
625  return STG_E_INVALIDPOINTER;
626 
627  /* Free all the old stuff */
628  Reset();
629 
630  ULONG dwBytesRead = 0;
631  HRESULT hr = stm->Read(&m_Header, sizeof(m_Header), &dwBytesRead);
632  if (FAILED(hr))
633  return hr;
634 
635  if (dwBytesRead != sizeof(m_Header))
636  return E_FAIL;
637  if (m_Header.dwSize != sizeof(m_Header))
638  return E_FAIL;
639  if (!IsEqualIID(m_Header.clsid, CLSID_ShellLink))
640  return E_FAIL;
641 
642  /* Load the new data in order */
643 
644  if (TRACE_ON(shell))
645  {
646  SYSTEMTIME stCreationTime;
647  SYSTEMTIME stLastAccessTime;
648  SYSTEMTIME stLastWriteTime;
649  WCHAR sTemp[MAX_PATH];
650 
651  FileTimeToSystemTime(&m_Header.ftCreationTime, &stCreationTime);
652  FileTimeToSystemTime(&m_Header.ftLastAccessTime, &stLastAccessTime);
653  FileTimeToSystemTime(&m_Header.ftLastWriteTime, &stLastWriteTime);
654 
656  NULL, sTemp, _countof(sTemp));
657  TRACE("-- stCreationTime: %s\n", debugstr_w(sTemp));
659  NULL, sTemp, _countof(sTemp));
660  TRACE("-- stLastAccessTime: %s\n", debugstr_w(sTemp));
662  NULL, sTemp, _countof(sTemp));
663  TRACE("-- stLastWriteTime: %s\n", debugstr_w(sTemp));
664  }
665 
666  /* load all the new stuff */
668  {
669  hr = ILLoadFromStream(stm, &m_pPidl);
670  if (FAILED(hr))
671  return hr;
672  }
673  pdump(m_pPidl);
674 
675  /* Load the location information... */
677  {
679  if (FAILED(hr))
680  return hr;
681  }
682  /* ... but if it is required not to use it, clear it */
684  {
686  m_sPath = NULL;
687  ZeroMemory(&volume, sizeof(volume));
688  }
689 
690  BOOL unicode = !!(m_Header.dwFlags & SLDF_UNICODE);
691 
693  {
694  hr = Stream_LoadString(stm, unicode, &m_sDescription);
695  if (FAILED(hr))
696  return hr;
697  TRACE("Description -> %s\n", debugstr_w(m_sDescription));
698  }
699 
701  {
702  hr = Stream_LoadString(stm, unicode, &m_sPathRel);
703  if (FAILED(hr))
704  return hr;
705  TRACE("Relative Path-> %s\n", debugstr_w(m_sPathRel));
706  }
707 
709  {
710  hr = Stream_LoadString(stm, unicode, &m_sWorkDir);
711  if (FAILED(hr))
712  return hr;
714  TRACE("Working Dir -> %s\n", debugstr_w(m_sWorkDir));
715  }
716 
718  {
719  hr = Stream_LoadString(stm, unicode, &m_sArgs);
720  if (FAILED(hr))
721  return hr;
722  TRACE("Arguments -> %s\n", debugstr_w(m_sArgs));
723  }
724 
726  {
727  hr = Stream_LoadString(stm, unicode, &m_sIcoPath);
728  if (FAILED(hr))
729  return hr;
730  TRACE("Icon file -> %s\n", debugstr_w(m_sIcoPath));
731  }
732 
733  /* Now load the optional data block list */
735  if (FAILED(hr)) // FIXME: Should we fail?
736  return hr;
737 
738  if (TRACE_ON(shell))
739  {
740 #if (NTDDI_VERSION < NTDDI_LONGHORN)
742  {
743  hr = GetAdvertiseInfo(&sProduct, EXP_LOGO3_ID_SIG);
744  if (SUCCEEDED(hr))
745  TRACE("Product -> %s\n", debugstr_w(sProduct));
746  }
747 #endif
749  {
751  if (SUCCEEDED(hr))
752  TRACE("Component -> %s\n", debugstr_w(sComponent));
753  }
754  }
755 
757  m_bRunAs = TRUE;
758  else
759  m_bRunAs = FALSE;
760 
761  TRACE("OK\n");
762 
763  pdump(m_pPidl);
764 
765  return S_OK;
766 }
767 
768 /************************************************************************
769  * Stream_WriteString
770  *
771  * Helper function for IPersistStream_Save. Writes a unicode string
772  * with terminating nul byte to a stream, preceded by the its length.
773  */
775 {
776  USHORT len = wcslen(str) + 1; // FIXME: Possible overflows?
777  DWORD count;
778 
779  HRESULT hr = stm->Write(&len, sizeof(len), &count);
780  if (FAILED(hr))
781  return hr;
782 
783  len *= sizeof(WCHAR);
784 
785  hr = stm->Write(str, len, &count);
786  if (FAILED(hr))
787  return hr;
788 
789  return S_OK;
790 }
791 
792 /************************************************************************
793  * Stream_WriteLocationInfo
794  *
795  * Writes the location info to a stream
796  *
797  * FIXME: One day we might want to write the network volume information
798  * and the final path.
799  * Figure out how Windows deals with unicode paths here.
800  */
803 {
804  LOCAL_VOLUME_INFO *vol;
805  LOCATION_INFO *loc;
806 
807  TRACE("%p %s %p\n", stm, debugstr_w(path), volume);
808 
809  /* figure out the size of everything */
810  DWORD label_size = WideCharToMultiByte(CP_ACP, 0, volume->label, -1,
811  NULL, 0, NULL, NULL);
812  DWORD path_size = WideCharToMultiByte(CP_ACP, 0, path, -1,
813  NULL, 0, NULL, NULL);
814  DWORD volume_info_size = sizeof(*vol) + label_size;
815  DWORD final_path_size = 1;
816  DWORD total_size = sizeof(*loc) + volume_info_size + path_size + final_path_size;
817 
818  /* create pointers to everything */
819  loc = static_cast<LOCATION_INFO *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, total_size));
820  vol = (LOCAL_VOLUME_INFO*) &loc[1];
821  LPSTR szLabel = (LPSTR) &vol[1];
822  LPSTR szPath = &szLabel[label_size];
823  LPSTR szFinalPath = &szPath[path_size];
824 
825  /* fill in the location information header */
826  loc->dwTotalSize = total_size;
827  loc->dwHeaderSize = sizeof(*loc);
828  loc->dwFlags = 1;
829  loc->dwVolTableOfs = sizeof(*loc);
830  loc->dwLocalPathOfs = sizeof(*loc) + volume_info_size;
831  loc->dwNetworkVolTableOfs = 0;
832  loc->dwFinalPathOfs = sizeof(*loc) + volume_info_size + path_size;
833 
834  /* fill in the volume information */
835  vol->dwSize = volume_info_size;
836  vol->dwType = volume->type;
837  vol->dwVolSerial = volume->serial;
838  vol->dwVolLabelOfs = sizeof(*vol);
839 
840  /* copy in the strings */
841  WideCharToMultiByte(CP_ACP, 0, volume->label, -1,
842  szLabel, label_size, NULL, NULL);
844  szPath, path_size, NULL, NULL);
845  *szFinalPath = 0;
846 
847  ULONG count = 0;
848  HRESULT hr = stm->Write(loc, total_size, &count);
849  HeapFree(GetProcessHeap(), 0, loc);
850 
851  return hr;
852 }
853 
854 /************************************************************************
855  * IPersistStream_Save (IPersistStream)
856  *
857  * FIXME: makes assumptions about byte order
858  */
860 {
861  TRACE("%p %p %x\n", this, stm, fClearDirty);
862 
863  m_Header.dwSize = sizeof(m_Header);
864  m_Header.clsid = CLSID_ShellLink;
865 
866  /*
867  * Reset the flags: keep only the flags related to data blocks as they were
868  * already set in accordance by the different mutator member functions.
869  * The other flags will be determined now by the presence or absence of data.
870  */
873 #if (NTDDI_VERSION < NTDDI_LONGHORN)
875 #endif
877  // TODO: When we will support Vista+ functionality, add other flags to this list.
878 
879  /* The stored strings are in UNICODE */
881 
882  if (m_pPidl)
884  if (m_sPath)
888  if (m_sPathRel && *m_sPathRel)
890  if (m_sWorkDir && *m_sWorkDir)
892  if (m_sArgs && *m_sArgs)
894  if (m_sIcoPath && *m_sIcoPath)
896  if (m_bRunAs)
898 
899  /* Write the shortcut header */
900  ULONG count;
901  HRESULT hr = stm->Write(&m_Header, sizeof(m_Header), &count);
902  if (FAILED(hr))
903  {
904  ERR("Write failed\n");
905  return hr;
906  }
907 
908  /* Save the data in order */
909 
910  if (m_pPidl)
911  {
912  hr = ILSaveToStream(stm, m_pPidl);
913  if (FAILED(hr))
914  {
915  ERR("Failed to write PIDL\n");
916  return hr;
917  }
918  }
919 
920  if (m_sPath)
921  {
923  if (FAILED(hr))
924  return hr;
925  }
926 
928  {
930  if (FAILED(hr))
931  return hr;
932  }
933 
935  {
937  if (FAILED(hr))
938  return hr;
939  }
940 
942  {
944  if (FAILED(hr))
945  return hr;
946  }
947 
949  {
950  hr = Stream_WriteString(stm, m_sArgs);
951  if (FAILED(hr))
952  return hr;
953  }
954 
956  {
958  if (FAILED(hr))
959  return hr;
960  }
961 
962  /*
963  * Now save the data block list.
964  *
965  * NOTE that both advertised Product and Component are already saved
966  * inside Logo3 and Darwin data blocks in the m_pDBList list, and the
967  * m_Header.dwFlags is suitably initialized.
968  */
970  if (FAILED(hr))
971  return hr;
972 
973  /* Clear the dirty bit if requested */
974  if (fClearDirty)
975  m_bDirty = FALSE;
976 
977  return hr;
978 }
979 
980 /************************************************************************
981  * IPersistStream_GetSizeMax (IPersistStream)
982  */
984 {
985  TRACE("(%p)\n", this);
986  return E_NOTIMPL;
987 }
988 
990 {
992  return FALSE;
993 
994  return TRUE;
995 }
996 
997 /**************************************************************************
998  * ShellLink_UpdatePath
999  * update absolute path in sPath using relative path in sPathRel
1000  */
1001 static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath)
1002 {
1003  if (!path || !psPath)
1004  return E_INVALIDARG;
1005 
1006  if (!*psPath && sPathRel)
1007  {
1008  WCHAR buffer[2*MAX_PATH], abs_path[2*MAX_PATH];
1009  LPWSTR final = NULL;
1010 
1011  /* first try if [directory of link file] + [relative path] finds an existing file */
1012 
1013  GetFullPathNameW(path, MAX_PATH * 2, buffer, &final);
1014  if (!final)
1015  final = buffer;
1016  wcscpy(final, sPathRel);
1017 
1018  *abs_path = '\0';
1019 
1021  {
1022  if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
1023  wcscpy(abs_path, buffer);
1024  }
1025  else
1026  {
1027  /* try if [working directory] + [relative path] finds an existing file */
1028  if (sWorkDir)
1029  {
1030  wcscpy(buffer, sWorkDir);
1031  wcscpy(PathAddBackslashW(buffer), sPathRel);
1032 
1034  if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
1035  wcscpy(abs_path, buffer);
1036  }
1037  }
1038 
1039  /* FIXME: This is even not enough - not all shell links can be resolved using this algorithm. */
1040  if (!*abs_path)
1041  wcscpy(abs_path, sPathRel);
1042 
1043  *psPath = strdupW(abs_path);
1044  if (!*psPath)
1045  return E_OUTOFMEMORY;
1046  }
1047 
1048  return S_OK;
1049 }
1050 
1052 {
1053  HRESULT hr;
1054  LPWSTR pszFileW;
1055  WIN32_FIND_DATAW wfd;
1056 
1057  TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
1058  this, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(m_sPath));
1059 
1060  /* Allocate a temporary UNICODE buffer */
1061  pszFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchMaxPath * sizeof(WCHAR));
1062  if (!pszFileW)
1063  return E_OUTOFMEMORY;
1064 
1065  /* Call the UNICODE function */
1066  hr = GetPath(pszFileW, cchMaxPath, &wfd, fFlags);
1067 
1068  /* Convert the file path back to ANSI */
1069  WideCharToMultiByte(CP_ACP, 0, pszFileW, -1,
1070  pszFile, cchMaxPath, NULL, NULL);
1071 
1072  /* Free the temporary buffer */
1073  HeapFree(GetProcessHeap(), 0, pszFileW);
1074 
1075  if (pfd)
1076  {
1077  ZeroMemory(pfd, sizeof(*pfd));
1078 
1079  /* Copy the file data if a file path was returned */
1080  if (*pszFile)
1081  {
1082  DWORD len;
1083 
1084  /* Copy the fixed part */
1085  CopyMemory(pfd, &wfd, FIELD_OFFSET(WIN32_FIND_DATAA, cFileName));
1086 
1087  /* Convert the file names to ANSI */
1088  len = lstrlenW(wfd.cFileName);
1089  WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, len + 1,
1090  pfd->cFileName, sizeof(pfd->cFileName), NULL, NULL);
1091  len = lstrlenW(wfd.cAlternateFileName);
1092  WideCharToMultiByte(CP_ACP, 0, wfd.cAlternateFileName, len + 1,
1093  pfd->cAlternateFileName, sizeof(pfd->cAlternateFileName), NULL, NULL);
1094  }
1095  }
1096 
1097  return hr;
1098 }
1099 
1101 {
1102  TRACE("(%p)->(ppidl=%p)\n", this, ppidl);
1103 
1104  if (!m_pPidl)
1105  {
1106  *ppidl = NULL;
1107  return S_FALSE;
1108  }
1109 
1110  *ppidl = ILClone(m_pPidl);
1111  return S_OK;
1112 }
1113 
1115 {
1116  TRACE("(%p)->(pidl=%p)\n", this, pidl);
1117  return SetTargetFromPIDLOrPath(pidl, NULL);
1118 }
1119 
1121 {
1122  TRACE("(%p)->(%p len=%u)\n", this, pszName, cchMaxName);
1123 
1124  if (cchMaxName)
1125  *pszName = 0;
1126 
1127  if (m_sDescription)
1129  pszName, cchMaxName, NULL, NULL);
1130 
1131  return S_OK;
1132 }
1133 
1135 {
1136  TRACE("(%p)->(pName=%s)\n", this, pszName);
1137 
1139  m_sDescription = NULL;
1140 
1141  if (pszName)
1142  {
1144  if (!m_sDescription)
1145  return E_OUTOFMEMORY;
1146  }
1147  m_bDirty = TRUE;
1148 
1149  return S_OK;
1150 }
1151 
1153 {
1154  TRACE("(%p)->(%p len=%u)\n", this, pszDir, cchMaxPath);
1155 
1156  if (cchMaxPath)
1157  *pszDir = 0;
1158 
1159  if (m_sWorkDir)
1161  pszDir, cchMaxPath, NULL, NULL);
1162 
1163  return S_OK;
1164 }
1165 
1167 {
1168  TRACE("(%p)->(dir=%s)\n", this, pszDir);
1169 
1171  m_sWorkDir = NULL;
1172 
1173  if (pszDir)
1174  {
1176  if (!m_sWorkDir)
1177  return E_OUTOFMEMORY;
1178  }
1179  m_bDirty = TRUE;
1180 
1181  return S_OK;
1182 }
1183 
1185 {
1186  TRACE("(%p)->(%p len=%u)\n", this, pszArgs, cchMaxPath);
1187 
1188  if (cchMaxPath)
1189  *pszArgs = 0;
1190 
1191  if (m_sArgs)
1193  pszArgs, cchMaxPath, NULL, NULL);
1194 
1195  return S_OK;
1196 }
1197 
1199 {
1200  TRACE("(%p)->(args=%s)\n", this, pszArgs);
1201 
1203  m_sArgs = NULL;
1204 
1205  if (pszArgs)
1206  {
1207  m_sArgs = HEAP_strdupAtoW(GetProcessHeap(), 0, pszArgs);
1208  if (!m_sArgs)
1209  return E_OUTOFMEMORY;
1210  }
1211  m_bDirty = TRUE;
1212 
1213  return S_OK;
1214 }
1215 
1217 {
1218  TRACE("(%p)->(%p)(0x%08x)\n", this, pwHotkey, m_Header.wHotKey);
1219  *pwHotkey = m_Header.wHotKey;
1220  return S_OK;
1221 }
1222 
1224 {
1225  TRACE("(%p)->(hotkey=%x)\n", this, wHotkey);
1226 
1227  m_Header.wHotKey = wHotkey;
1228  m_bDirty = TRUE;
1229 
1230  return S_OK;
1231 }
1232 
1234 {
1235  TRACE("(%p)->(%p) %d\n", this, piShowCmd, m_Header.nShowCommand);
1236  *piShowCmd = m_Header.nShowCommand;
1237  return S_OK;
1238 }
1239 
1241 {
1242  TRACE("(%p) %d\n", this, iShowCmd);
1243 
1244  m_Header.nShowCommand = iShowCmd;
1245  m_bDirty = TRUE;
1246 
1247  return S_OK;
1248 }
1249 
1251 {
1252  HRESULT hr;
1253  LPWSTR pszIconPathW;
1254 
1255  TRACE("(%p)->(%p len=%u iicon=%p)\n", this, pszIconPath, cchIconPath, piIcon);
1256 
1257  /* Allocate a temporary UNICODE buffer */
1258  pszIconPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchIconPath * sizeof(WCHAR));
1259  if (!pszIconPathW)
1260  return E_OUTOFMEMORY;
1261 
1262  /* Call the UNICODE function */
1263  hr = GetIconLocation(pszIconPathW, cchIconPath, piIcon);
1264 
1265  /* Convert the file path back to ANSI */
1266  WideCharToMultiByte(CP_ACP, 0, pszIconPathW, -1,
1267  pszIconPath, cchIconPath, NULL, NULL);
1268 
1269  /* Free the temporary buffer */
1270  HeapFree(GetProcessHeap(), 0, pszIconPathW);
1271 
1272  return hr;
1273 }
1274 
1276 {
1277  HRESULT hr;
1278  LPWSTR pszIconFileW;
1279 
1280  TRACE("(%p)->(%u %p len=%u piIndex=%p pwFlags=%p)\n", this, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1281 
1282  /* Allocate a temporary UNICODE buffer */
1283  pszIconFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchMax * sizeof(WCHAR));
1284  if (!pszIconFileW)
1285  return E_OUTOFMEMORY;
1286 
1287  /* Call the UNICODE function */
1288  hr = GetIconLocation(uFlags, pszIconFileW, cchMax, piIndex, pwFlags);
1289 
1290  /* Convert the file path back to ANSI */
1291  WideCharToMultiByte(CP_ACP, 0, pszIconFileW, -1,
1292  pszIconFile, cchMax, NULL, NULL);
1293 
1294  /* Free the temporary buffer */
1295  HeapFree(GetProcessHeap(), 0, pszIconFileW);
1296 
1297  return hr;
1298 }
1299 
1300 HRESULT STDMETHODCALLTYPE CShellLink::Extract(PCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
1301 {
1302  TRACE("(%p)->(path=%s iicon=%u)\n", this, pszFile, nIconIndex);
1303 
1304  LPWSTR str = NULL;
1305  if (pszFile)
1306  {
1307  str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
1308  if (!str)
1309  return E_OUTOFMEMORY;
1310  }
1311 
1312  HRESULT hr = Extract(str, nIconIndex, phiconLarge, phiconSmall, nIconSize);
1313 
1314  if (str)
1315  HeapFree(GetProcessHeap(), 0, str);
1316 
1317  return hr;
1318 }
1319 
1321 {
1322  TRACE("(%p)->(path=%s iicon=%u)\n", this, pszIconPath, iIcon);
1323 
1324  LPWSTR str = NULL;
1325  if (pszIconPath)
1326  {
1327  str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath);
1328  if (!str)
1329  return E_OUTOFMEMORY;
1330  }
1331 
1332  HRESULT hr = SetIconLocation(str, iIcon);
1333 
1334  if (str)
1335  HeapFree(GetProcessHeap(), 0, str);
1336 
1337  return hr;
1338 }
1339 
1341 {
1342  TRACE("(%p)->(path=%s %x)\n", this, pszPathRel, dwReserved);
1343 
1345  m_sPathRel = NULL;
1346 
1347  if (pszPathRel)
1348  {
1349  m_sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
1350  m_bDirty = TRUE;
1351  }
1352 
1354 }
1355 
1356 static LPWSTR
1358 {
1359  DWORD Result, sz = 0;
1360 
1361  Result = CommandLineFromMsiDescriptor(component, NULL, &sz);
1362  if (Result != ERROR_SUCCESS)
1363  return NULL;
1364 
1365  sz++;
1366  LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR));
1367  Result = CommandLineFromMsiDescriptor(component, path, &sz);
1368  if (Result != ERROR_SUCCESS)
1369  {
1370  HeapFree(GetProcessHeap(), 0, path);
1371  path = NULL;
1372  }
1373 
1374  TRACE("returning %s\n", debugstr_w(path));
1375 
1376  return path;
1377 }
1378 
1380 {
1381  HRESULT hr = S_OK;
1382  BOOL bSuccess;
1383 
1384  TRACE("(%p)->(hwnd=%p flags=%x)\n", this, hwnd, fFlags);
1385 
1386  /* FIXME: use IResolveShellLink interface? */
1387 
1388  // FIXME: See InvokeCommand().
1389 
1390 #if (NTDDI_VERSION < NTDDI_LONGHORN)
1391  // NOTE: For Logo3 (EXP_LOGO3_ID_SIG), check also for SHRestricted(REST_NOLOGO3CHANNELNOTIFY)
1393  {
1394  FIXME("Logo3 links are not supported yet!\n");
1395  return E_FAIL;
1396  }
1397 #endif
1398 
1399  /* Resolve Darwin (MSI) target */
1401  {
1402  LPWSTR component = NULL;
1403  hr = GetAdvertiseInfo(&component, EXP_DARWIN_ID_SIG);
1404  if (FAILED(hr))
1405  return E_FAIL;
1406 
1407  /* Clear the cached path */
1410  if (!m_sPath)
1411  return E_FAIL;
1412  }
1413 
1414  if (!m_sPath && m_pPidl)
1415  {
1417 
1419  if (bSuccess && *buffer)
1420  {
1421  m_sPath = strdupW(buffer);
1422  if (!m_sPath)
1423  return E_OUTOFMEMORY;
1424 
1425  m_bDirty = TRUE;
1426  }
1427  else
1428  {
1429  hr = S_OK; /* don't report an error occurred while just caching information */
1430  }
1431  }
1432 
1433  // FIXME: Strange to do that here...
1434  if (!m_sIcoPath && m_sPath)
1435  {
1437  if (!m_sIcoPath)
1438  return E_OUTOFMEMORY;
1439 
1440  m_Header.nIconIndex = 0;
1441 
1442  m_bDirty = TRUE;
1443  }
1444 
1445  return hr;
1446 }
1447 
1449 {
1450  TRACE("(%p)->(path=%s)\n", this, pszFile);
1451 
1452  if (!pszFile)
1453  return E_INVALIDARG;
1454 
1455  LPWSTR str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
1456  if (!str)
1457  return E_OUTOFMEMORY;
1458 
1459  HRESULT hr = SetPath(str);
1460  HeapFree(GetProcessHeap(), 0, str);
1461 
1462  return hr;
1463 }
1464 
1466 {
1468 
1469  TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
1470  this, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(m_sPath));
1471 
1472  if (cchMaxPath)
1473  *pszFile = 0;
1474  // FIXME: What if cchMaxPath == 0 , or pszFile == NULL ??
1475 
1476  // FIXME: What about Darwin??
1477 
1478  /*
1479  * Retrieve the path to the target from the PIDL (if we have one).
1480  * NOTE: Do NOT use the cached path (m_sPath from link info).
1481  */
1483  {
1484  if (fFlags & SLGP_SHORTPATH)
1486  // FIXME: Add support for SLGP_UNCPRIORITY
1487  }
1488  else
1489  {
1490  *buffer = 0;
1491  }
1492 
1493  /* If we have a FindData structure, initialize it */
1494  if (pfd)
1495  {
1496  ZeroMemory(pfd, sizeof(*pfd));
1497 
1498  /* Copy the file data if the target is a file path */
1499  if (*buffer)
1500  {
1501  pfd->dwFileAttributes = m_Header.dwFileAttributes;
1502  pfd->ftCreationTime = m_Header.ftCreationTime;
1503  pfd->ftLastAccessTime = m_Header.ftLastAccessTime;
1504  pfd->ftLastWriteTime = m_Header.ftLastWriteTime;
1505  pfd->nFileSizeHigh = 0;
1506  pfd->nFileSizeLow = m_Header.nFileSizeLow;
1507 
1508  /*
1509  * Build temporarily a short path in pfd->cFileName (of size MAX_PATH),
1510  * then extract and store the short file name in pfd->cAlternateFileName.
1511  */
1512  GetShortPathNameW(buffer, pfd->cFileName, _countof(pfd->cFileName));
1513  lstrcpynW(pfd->cAlternateFileName,
1514  PathFindFileNameW(pfd->cFileName),
1515  _countof(pfd->cAlternateFileName));
1516 
1517  /* Now extract and store the long file name in pfd->cFileName */
1518  lstrcpynW(pfd->cFileName,
1520  _countof(pfd->cFileName));
1521  }
1522  }
1523 
1524  /* Finally check if we have a raw path the user actually wants to retrieve */
1525  if ((fFlags & SLGP_RAWPATH) && (m_Header.dwFlags & SLDF_HAS_EXP_SZ))
1526  {
1527  /* Search for a target environment block */
1528  LPEXP_SZ_LINK pInfo;
1530  if (pInfo && (pInfo->cbSize == sizeof(*pInfo)))
1531  lstrcpynW(buffer, pInfo->szwTarget, cchMaxPath);
1532  }
1533 
1534  /* For diagnostics purposes only... */
1535  // NOTE: SLGP_UNCPRIORITY is unsupported
1536  fFlags &= ~(SLGP_RAWPATH | SLGP_SHORTPATH);
1537  if (fFlags) FIXME("(%p): Unsupported flags %lu\n", this, fFlags);
1538 
1539  /* Copy the data back to the user */
1540  if (*buffer)
1541  lstrcpynW(pszFile, buffer, cchMaxPath);
1542 
1543  return (*buffer ? S_OK : S_FALSE);
1544 }
1545 
1547 {
1548  TRACE("(%p)->(%p len=%u)\n", this, pszName, cchMaxName);
1549 
1550  *pszName = 0;
1551  if (m_sDescription)
1552  lstrcpynW(pszName, m_sDescription, cchMaxName);
1553 
1554  return S_OK;
1555 }
1556 
1558 {
1559  TRACE("(%p)->(desc=%s)\n", this, debugstr_w(pszName));
1560 
1562  m_sDescription = NULL;
1563 
1564  if (pszName)
1565  {
1566  m_sDescription = strdupW(pszName);
1567  if (!m_sDescription)
1568  return E_OUTOFMEMORY;
1569  }
1570  m_bDirty = TRUE;
1571 
1572  return S_OK;
1573 }
1574 
1576 {
1577  TRACE("(%p)->(%p len %u)\n", this, pszDir, cchMaxPath);
1578 
1579  if (cchMaxPath)
1580  *pszDir = 0;
1581 
1582  if (m_sWorkDir)
1583  lstrcpynW(pszDir, m_sWorkDir, cchMaxPath);
1584 
1585  return S_OK;
1586 }
1587 
1589 {
1590  TRACE("(%p)->(dir=%s)\n", this, debugstr_w(pszDir));
1591 
1593  m_sWorkDir = NULL;
1594 
1595  if (pszDir)
1596  {
1598  if (!m_sWorkDir)
1599  return E_OUTOFMEMORY;
1600  }
1601  m_bDirty = TRUE;
1602 
1603  return S_OK;
1604 }
1605 
1607 {
1608  TRACE("(%p)->(%p len=%u)\n", this, pszArgs, cchMaxPath);
1609 
1610  if (cchMaxPath)
1611  *pszArgs = 0;
1612 
1613  if (m_sArgs)
1614  lstrcpynW(pszArgs, m_sArgs, cchMaxPath);
1615 
1616  return S_OK;
1617 }
1618 
1620 {
1621  TRACE("(%p)->(args=%s)\n", this, debugstr_w(pszArgs));
1622 
1624  m_sArgs = NULL;
1625 
1626  if (pszArgs)
1627  {
1628  m_sArgs = strdupW(pszArgs);
1629  if (!m_sArgs)
1630  return E_OUTOFMEMORY;
1631  }
1632  m_bDirty = TRUE;
1633 
1634  return S_OK;
1635 }
1636 
1638 {
1639  TRACE("(%p)->(%p len=%u iicon=%p)\n", this, pszIconPath, cchIconPath, piIcon);
1640 
1641  if (cchIconPath)
1642  *pszIconPath = 0;
1643 
1644  *piIcon = 0;
1645 
1646  /* Update the original icon path location */
1648  {
1650 
1651  /* Search for an icon environment block */
1652  LPEXP_SZ_LINK pInfo;
1654  if (pInfo && (pInfo->cbSize == sizeof(*pInfo)))
1655  {
1657 
1660 
1662  if (!m_sIcoPath)
1663  return E_OUTOFMEMORY;
1664 
1666 
1667  m_bDirty = TRUE;
1668  }
1669  }
1670 
1671  *piIcon = m_Header.nIconIndex;
1672 
1673  if (m_sIcoPath)
1674  lstrcpynW(pszIconPath, m_sIcoPath, cchIconPath);
1675 
1676  return S_OK;
1677 }
1678 
1680  UINT uFlags, PWSTR pszIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
1681 {
1682  LPCITEMIDLIST pidlLast;
1684 
1685  HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
1686  if (FAILED_UNEXPECTEDLY(hr))
1687  return hr;
1688 
1690  hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_NULL_PPV_ARG(IExtractIconW, &pei));
1691  if (FAILED_UNEXPECTEDLY(hr))
1692  return hr;
1693 
1694  hr = pei->GetIconLocation(uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1695  if (FAILED_UNEXPECTEDLY(hr))
1696  return hr;
1697 
1698  return S_OK;
1699 }
1700 
1702 {
1703  HRESULT hr;
1704 
1705  pszIconFile[0] = UNICODE_NULL;
1706 
1707  /*
1708  * It is possible for a shell link to point to another shell link,
1709  * and in particular there is the possibility to point to itself.
1710  * Now, suppose we ask such a link to retrieve its associated icon.
1711  * This function would be called, and due to COM would be called again
1712  * recursively. To solve this issue, we forbid calling GetIconLocation()
1713  * with GIL_FORSHORTCUT set in uFlags, as done by Windows (shown by tests).
1714  */
1715  if (uFlags & GIL_FORSHORTCUT)
1716  return E_INVALIDARG;
1717 
1718  /*
1719  * Now, we set GIL_FORSHORTCUT so that: i) we allow the icon extractor
1720  * of the target to give us a suited icon, and ii) we protect ourselves
1721  * against recursive call.
1722  */
1723  uFlags |= GIL_FORSHORTCUT;
1724 
1725  if (uFlags & GIL_DEFAULTICON)
1726  return S_FALSE;
1727 
1728  hr = GetIconLocation(pszIconFile, cchMax, piIndex);
1729  if (FAILED(hr) || pszIconFile[0] == UNICODE_NULL)
1730  {
1731  hr = SHELL_PidlGetIconLocationW(m_pPidl, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1732  }
1733  else
1734  {
1735  *pwFlags = GIL_NOTFILENAME | GIL_PERCLASS;
1736  }
1737 
1738  return hr;
1739 }
1740 
1742 CShellLink::Extract(PCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
1743 {
1744  HRESULT hr = NOERROR;
1745  UINT cxyLarge = LOWORD(nIconSize), cxySmall = HIWORD(nIconSize);
1746 
1747  if (phiconLarge)
1748  {
1749  *phiconLarge = NULL;
1750  PrivateExtractIconsW(pszFile, nIconIndex, cxyLarge, cxyLarge, phiconLarge, NULL, 1, 0);
1751 
1752  if (*phiconLarge == NULL)
1753  hr = S_FALSE;
1754  }
1755 
1756  if (phiconSmall)
1757  {
1758  *phiconSmall = NULL;
1759  PrivateExtractIconsW(pszFile, nIconIndex, cxySmall, cxySmall, phiconSmall, NULL, 1, 0);
1760 
1761  if (*phiconSmall == NULL)
1762  hr = S_FALSE;
1763  }
1764 
1765  if (hr == S_FALSE)
1766  {
1767  if (phiconLarge && *phiconLarge)
1768  {
1769  DestroyIcon(*phiconLarge);
1770  *phiconLarge = NULL;
1771  }
1772  if (phiconSmall && *phiconSmall)
1773  {
1774  DestroyIcon(*phiconSmall);
1775  *phiconSmall = NULL;
1776  }
1777  }
1778 
1779  return hr;
1780 }
1781 
1782 #if 0
1783 /* Extends the functionality of PathUnExpandEnvStringsW */
1784 BOOL PathFullyUnExpandEnvStringsW(
1785  _In_ LPCWSTR pszPath,
1786  _Out_ LPWSTR pszBuf,
1787  _In_ UINT cchBuf)
1788 {
1789  BOOL Ret = FALSE; // Set to TRUE as soon as PathUnExpandEnvStrings starts unexpanding.
1790  BOOL res;
1791  LPCWSTR p;
1792 
1793  // *pszBuf = L'\0';
1794  while (*pszPath && cchBuf > 0)
1795  {
1796  /* Attempt unexpanding the path */
1797  res = PathUnExpandEnvStringsW(pszPath, pszBuf, cchBuf);
1798  if (!res)
1799  {
1800  /* The unexpansion failed. Try to find a path delimiter. */
1801  p = wcspbrk(pszPath, L" /\\:*?\"<>|%");
1802  if (!p) /* None found, we will copy the remaining path */
1803  p = pszPath + wcslen(pszPath);
1804  else /* Found one, we will copy the delimiter and skip it */
1805  ++p;
1806  /* If we overflow, we cannot unexpand more, so return FALSE */
1807  if (p - pszPath >= cchBuf)
1808  return FALSE; // *pszBuf = L'\0';
1809 
1810  /* Copy the untouched portion of path up to the delimiter, included */
1811  wcsncpy(pszBuf, pszPath, p - pszPath);
1812  pszBuf[p - pszPath] = L'\0'; // NULL-terminate
1813 
1814  /* Advance the pointers and decrease the remaining buffer size */
1815  cchBuf -= (p - pszPath);
1816  pszBuf += (p - pszPath);
1817  pszPath += (p - pszPath);
1818  }
1819  else
1820  {
1821  /*
1822  * The unexpansion succeeded. Skip the unexpanded part by trying
1823  * to find where the original path and the unexpanded string
1824  * become different.
1825  * NOTE: An alternative(?) would be to stop also at the last
1826  * path delimiter encountered in the loop (i.e. would be the
1827  * first path delimiter in the strings).
1828  */
1829  LPWSTR q;
1830 
1831  /*
1832  * The algorithm starts at the end of the strings and loops back
1833  * while the characters are equal, until it finds a discrepancy.
1834  */
1835  p = pszPath + wcslen(pszPath);
1836  q = pszBuf + wcslen(pszBuf); // This wcslen should be < cchBuf
1837  while ((*p == *q) && (p > pszPath) && (q > pszBuf))
1838  {
1839  --p; --q;
1840  }
1841  /* Skip discrepancy */
1842  ++p; ++q;
1843 
1844  /* Advance the pointers and decrease the remaining buffer size */
1845  cchBuf -= (q - pszBuf);
1846  pszBuf = q;
1847  pszPath = p;
1848 
1849  Ret = TRUE;
1850  }
1851  }
1852 
1853  return Ret;
1854 }
1855 #endif
1856 
1858 {
1859  HRESULT hr = E_FAIL;
1860  WCHAR szIconPath[MAX_PATH];
1861 
1862  TRACE("(%p)->(path=%s iicon=%u)\n", this, debugstr_w(pszIconPath), iIcon);
1863 
1864  if (pszIconPath)
1865  {
1866  /*
1867  * Check whether the user-given file path contains unexpanded
1868  * environment variables. If so, create a target environment block.
1869  * Note that in this block we will store the user-given path.
1870  * It will contain the unexpanded environment variables, but
1871  * it can also contain already expanded path that the user does
1872  * not want to see them unexpanded (e.g. so that they always
1873  * refer to the same place even if the would-be corresponding
1874  * environment variable could change).
1875  */
1876 #ifdef ICON_LINK_WINDOWS_COMPAT
1877  /* Try to fully unexpand the icon path */
1878  // if (PathFullyUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath)))
1879  BOOL bSuccess = PathUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath));
1880  if (bSuccess && wcscmp(pszIconPath, szIconPath) != 0)
1881 #else
1882  /*
1883  * In some situations, described in http://stackoverflow.com/questions/2976489/ishelllinkseticonlocation-translates-my-icon-path-into-program-files-which-i
1884  * the result of PathUnExpandEnvStringsW() could be wrong, and instead
1885  * one would have to store the actual provided icon location path, while
1886  * creating an icon environment block ONLY if that path already contains
1887  * environment variables. This is what the present case is trying to implement.
1888  */
1889  SHExpandEnvironmentStringsW(pszIconPath, szIconPath, _countof(szIconPath));
1890  if (wcscmp(pszIconPath, szIconPath) != 0)
1891 #endif
1892  {
1893  /*
1894  * The user-given file path contains unexpanded environment
1895  * variables, so we need an icon environment block.
1896  */
1898  LPEXP_SZ_LINK pInfo;
1899 
1900 #ifdef ICON_LINK_WINDOWS_COMPAT
1901  /* Make pszIconPath point to the unexpanded path */
1902  LPCWSTR pszOrgIconPath = pszIconPath;
1903  pszIconPath = szIconPath;
1904 #endif
1906  if (pInfo)
1907  {
1908  /* Make sure that the size of the structure is valid */
1909  if (pInfo->cbSize != sizeof(*pInfo))
1910  {
1911  ERR("Ooops. This structure is not as expected...\n");
1912 
1913  /* Invalid structure, remove it altogether */
1916 
1917  /* Reset the pointer and go use the static buffer */
1918  pInfo = NULL;
1919  }
1920  }
1921  if (!pInfo)
1922  {
1923  /* Use the static buffer */
1924  pInfo = &buffer;
1925  buffer.cbSize = sizeof(buffer);
1926  buffer.dwSignature = EXP_SZ_ICON_SIG;
1927  }
1928 
1929  lstrcpynW(pInfo->szwTarget, pszIconPath, _countof(pInfo->szwTarget));
1930  WideCharToMultiByte(CP_ACP, 0, pszIconPath, -1,
1931  pInfo->szTarget, _countof(pInfo->szTarget), NULL, NULL);
1932 
1933  hr = S_OK;
1934  if (pInfo == &buffer)
1935  hr = AddDataBlock(pInfo);
1936  if (hr == S_OK)
1938 
1939 #ifdef ICON_LINK_WINDOWS_COMPAT
1940  /* Set pszIconPath back to the original one */
1941  pszIconPath = pszOrgIconPath;
1942 #else
1943  /* Now, make pszIconPath point to the expanded path */
1944  pszIconPath = szIconPath;
1945 #endif
1946  }
1947  else
1948  {
1949  /*
1950  * The user-given file path does not contain unexpanded environment
1951  * variables, so we need to remove any icon environment block.
1952  */
1955 
1956  /* pszIconPath points to the user path */
1957  }
1958  }
1959 
1960 #ifdef ICON_LINK_WINDOWS_COMPAT
1961  /* Store the original icon path location (may contain unexpanded environment strings) */
1962 #endif
1963  if (pszIconPath)
1964  {
1967 
1968  m_sIcoPath = strdupW(pszIconPath);
1969  if (!m_sIcoPath)
1970  return E_OUTOFMEMORY;
1971 
1973  }
1974 
1975  hr = S_OK;
1976 
1977  m_Header.nIconIndex = iIcon;
1978  m_bDirty = TRUE;
1979 
1980  return hr;
1981 }
1982 
1984 {
1985  TRACE("(%p)->(path=%s %x)\n", this, debugstr_w(pszPathRel), dwReserved);
1986 
1988  m_sPathRel = NULL;
1989 
1990  if (pszPathRel)
1991  {
1992  m_sPathRel = strdupW(pszPathRel);
1993  if (!m_sPathRel)
1994  return E_OUTOFMEMORY;
1995  }
1996  m_bDirty = TRUE;
1997 
1999 }
2000 
2002 {
2003  if (!str)
2004  return NULL;
2005 
2006  LPCWSTR p = wcschr(str, L':');
2007  if (!p)
2008  return NULL;
2009 
2010  DWORD len = p - str;
2011  LPWSTR ret = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (len + 1));
2012  if (!ret)
2013  return ret;
2014 
2015  memcpy(ret, str, sizeof(WCHAR)*len);
2016  ret[len] = 0;
2017  return ret;
2018 }
2019 
2021 {
2023  LPEXP_DARWIN_LINK pInfo;
2024 
2025  if ( (dwSig != EXP_DARWIN_ID_SIG)
2027  && (dwSig != EXP_LOGO3_ID_SIG)
2028 #endif
2029  )
2030  {
2031  return E_INVALIDARG;
2032  }
2033 
2034  if (!string)
2035  return S_FALSE;
2036 
2037  pInfo = (LPEXP_DARWIN_LINK)SHFindDataBlock(m_pDBList, dwSig);
2038  if (pInfo)
2039  {
2040  /* Make sure that the size of the structure is valid */
2041  if (pInfo->dbh.cbSize != sizeof(*pInfo))
2042  {
2043  ERR("Ooops. This structure is not as expected...\n");
2044 
2045  /* Invalid structure, remove it altogether */
2046  if (dwSig == EXP_DARWIN_ID_SIG)
2048 #if (NTDDI_VERSION < NTDDI_LONGHORN)
2049  else if (dwSig == EXP_LOGO3_ID_SIG)
2051 #endif
2052  RemoveDataBlock(dwSig);
2053 
2054  /* Reset the pointer and go use the static buffer */
2055  pInfo = NULL;
2056  }
2057  }
2058  if (!pInfo)
2059  {
2060  /* Use the static buffer */
2061  pInfo = &buffer;
2062  buffer.dbh.cbSize = sizeof(buffer);
2063  buffer.dbh.dwSignature = dwSig;
2064  }
2065 
2066  lstrcpynW(pInfo->szwDarwinID, string, _countof(pInfo->szwDarwinID));
2067  WideCharToMultiByte(CP_ACP, 0, string, -1,
2068  pInfo->szDarwinID, _countof(pInfo->szDarwinID), NULL, NULL);
2069 
2070  HRESULT hr = S_OK;
2071  if (pInfo == &buffer)
2072  hr = AddDataBlock(pInfo);
2073  if (hr == S_OK)
2074  {
2075  if (dwSig == EXP_DARWIN_ID_SIG)
2077 #if (NTDDI_VERSION < NTDDI_LONGHORN)
2078  else if (dwSig == EXP_LOGO3_ID_SIG)
2080 #endif
2081  }
2082 
2083  return hr;
2084 }
2085 
2087 {
2088  HRESULT hr;
2089  LPCWSTR szComponent = NULL, szProduct = NULL, p;
2090  INT len;
2091  GUID guid;
2092  WCHAR szGuid[38+1];
2093 
2094  sProduct = sComponent = NULL;
2095 
2096  while (str[0])
2097  {
2098  /* each segment must start with two colons */
2099  if (str[0] != ':' || str[1] != ':')
2100  return E_FAIL;
2101 
2102  /* the last segment is just two colons */
2103  if (!str[2])
2104  break;
2105  str += 2;
2106 
2107  /* there must be a colon straight after a guid */
2108  p = wcschr(str, L':');
2109  if (!p)
2110  return E_FAIL;
2111  len = p - str;
2112  if (len != 38)
2113  return E_FAIL;
2114 
2115  /* get the guid, and check if it's validly formatted */
2116  memcpy(szGuid, str, sizeof(WCHAR)*len);
2117  szGuid[len] = 0;
2118 
2120  if (hr != S_OK)
2121  return hr;
2122  str = p + 1;
2123 
2124  /* match it up to a guid that we care about */
2125  if (IsEqualGUID(guid, SHELL32_AdvtShortcutComponent) && !szComponent)
2126  szComponent = str; /* Darwin */
2127  else if (IsEqualGUID(guid, SHELL32_AdvtShortcutProduct) && !szProduct)
2128  szProduct = str; /* Logo3 */
2129  else
2130  return E_FAIL;
2131 
2132  /* skip to the next field */
2133  str = wcschr(str, L':');
2134  if (!str)
2135  return E_FAIL;
2136  }
2137 
2138  /* we have to have a component for an advertised shortcut */
2139  if (!szComponent)
2140  return E_FAIL;
2141 
2142  szComponent = GetAdvertisedArg(szComponent);
2143  szProduct = GetAdvertisedArg(szProduct);
2144 
2145  hr = WriteAdvertiseInfo(szComponent, EXP_DARWIN_ID_SIG);
2146  // if (FAILED(hr))
2147  // return hr;
2148 #if (NTDDI_VERSION < NTDDI_LONGHORN)
2149  hr = WriteAdvertiseInfo(szProduct, EXP_LOGO3_ID_SIG);
2150  // if (FAILED(hr))
2151  // return hr;
2152 #endif
2153 
2154  HeapFree(GetProcessHeap(), 0, (PVOID)szComponent);
2155  HeapFree(GetProcessHeap(), 0, (PVOID)szProduct);
2156 
2157  if (TRACE_ON(shell))
2158  {
2160  TRACE("Component = %s\n", debugstr_w(sComponent));
2161 #if (NTDDI_VERSION < NTDDI_LONGHORN)
2162  GetAdvertiseInfo(&sProduct, EXP_LOGO3_ID_SIG);
2163  TRACE("Product = %s\n", debugstr_w(sProduct));
2164 #endif
2165  }
2166 
2167  return S_OK;
2168 }
2169 
2170 /*
2171  * Since the real PathResolve (from Wine) is unimplemented at the moment,
2172  * we use this local implementation, until a better one is written (using
2173  * code parts of the SHELL_xxx helpers in Wine's shellpath.c).
2174  */
2176  IN OUT PWSTR pszPath,
2177  IN PZPCWSTR dirs OPTIONAL,
2178  IN UINT fFlags)
2179 {
2180  // FIXME: This is unimplemented!!!
2181 #if 0
2182  return PathResolve(pszPath, dirs, fFlags);
2183 #else
2184  BOOL Success = FALSE;
2185  USHORT i;
2186  LPWSTR fname = NULL;
2188 
2189  /* First, search for a valid existing path */
2190 
2191  // NOTE: See also: SHELL_FindExecutable()
2192 
2193  /*
2194  * List of extensions searched for, by PathResolve with the flag
2195  * PRF_TRYPROGRAMEXTENSIONS == PRF_EXECUTABLE | PRF_VERIFYEXISTS set,
2196  * according to MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/bb776478(v=vs.85).aspx
2197  */
2198  static PCWSTR Extensions[] = {L".pif", L".com", L".bat", L".cmd", L".lnk", L".exe", NULL};
2199  #define LNK_EXT_INDEX 4 // ".lnk" has index 4 in the array above
2200 
2201  /*
2202  * Start at the beginning of the list if PRF_EXECUTABLE is set, otherwise
2203  * just use the last element 'NULL' (no extension checking).
2204  */
2205  i = ((fFlags & PRF_EXECUTABLE) ? 0 : _countof(Extensions) - 1);
2206  for (; i < _countof(Extensions); ++i)
2207  {
2208  /* Ignore shell links ".lnk" if needed */
2209  if ((fFlags & PRF_DONTFINDLNK) && (i == LNK_EXT_INDEX))
2210  continue;
2211 
2212  Success = (SearchPathW(NULL, pszPath, Extensions[i],
2213  _countof(szPath), szPath, NULL) != 0);
2214  if (!Success)
2215  {
2216  ERR("SearchPathW(pszPath = '%S') failed. Error code: %lu\n", pszPath, GetLastError());
2217  }
2218  else
2219  {
2220  ERR("SearchPathW(pszPath = '%S', szPath = '%S') succeeded\n", pszPath, szPath);
2221  break;
2222  }
2223  }
2224 
2225  if (!Success)
2226  {
2227  ERR("SearchPathW(pszPath = '%S') failed. Error code: %lu\n", pszPath, GetLastError());
2228 
2229  /* We failed, try with PathFindOnPath, as explained by MSDN */
2230  // Success = PathFindOnPathW(pszPath, dirs);
2231  StringCchCopyW(szPath, _countof(szPath), pszPath);
2232  Success = PathFindOnPathW(szPath, dirs);
2233  if (!Success)
2234  {
2235  ERR("PathFindOnPathW(pszPath = '%S') failed\n", pszPath);
2236 
2237  /* We failed again, fall back to building a possible non-existing path */
2238  if (!GetFullPathNameW(pszPath, _countof(szPath), szPath, &fname))
2239  {
2240  ERR("GetFullPathNameW(pszPath = '%S') failed. Error code: %lu\n", pszPath, GetLastError());
2241  return FALSE;
2242  }
2243 
2245  if (!Success)
2246  ERR("PathFileExistsW(szPath = '%S') failed. Error code: %lu\n", szPath, GetLastError());
2247 
2248  /******************************************************/
2249  /* Question: Why this line is needed only for files?? */
2250  if (fname && (_wcsicmp(pszPath, fname) == 0))
2251  *szPath = L'\0';
2252  /******************************************************/
2253  }
2254  else
2255  {
2256  ERR("PathFindOnPathW(pszPath = '%S' ==> '%S') succeeded\n", pszPath, szPath);
2257  }
2258  }
2259 
2260  /* Copy back the results to the caller */
2261  StringCchCopyW(pszPath, MAX_PATH, szPath);
2262 
2263  /*
2264  * Since the called functions always checked whether the file path existed,
2265  * we do not need to redo a final check: we can use instead the cached
2266  * result in 'Success'.
2267  */
2268  return ((fFlags & PRF_VERIFYEXISTS) ? Success : TRUE);
2269 #endif
2270 }
2271 
2273 {
2274  HRESULT hr = S_OK;
2275  LPITEMIDLIST pidlNew = NULL;
2277 
2278  /*
2279  * Not both 'pidl' and 'pszFile' should be set.
2280  * But either one or both can be NULL.
2281  */
2282  if (pidl && pszFile)
2283  return E_FAIL;
2284 
2285  if (pidl)
2286  {
2287  /* Clone the PIDL */
2288  pidlNew = ILClone(pidl);
2289  if (!pidlNew)
2290  return E_FAIL;
2291  }
2292  else if (pszFile)
2293  {
2294  /* Build a PIDL for this path target */
2295  hr = SHILCreateFromPathW(pszFile, &pidlNew, NULL);
2296  if (FAILED(hr))
2297  {
2298  /* This failed, try to resolve the path, then create a simple PIDL */
2299 
2300  StringCchCopyW(szPath, _countof(szPath), pszFile);
2301  // FIXME: Because PathResolve is unimplemented, we use our hackish implementation!
2303 
2304  pidlNew = SHSimpleIDListFromPathW(szPath);
2305  /******************************************************/
2306  /* Question: Why this line is needed only for files?? */
2307  hr = (*szPath ? S_OK : E_INVALIDARG); // S_FALSE
2308  /******************************************************/
2309  }
2310  }
2311  // else if (!pidl && !pszFile) { pidlNew = NULL; hr = S_OK; }
2312 
2313  ILFree(m_pPidl);
2314  m_pPidl = pidlNew;
2315 
2316  if (!pszFile)
2317  {
2318  if (SHGetPathFromIDListW(pidlNew, szPath))
2319  pszFile = szPath;
2320  }
2321 
2322  // TODO: Fully update link info, tracker, file attribs...
2323 
2324  // if (pszFile)
2325  if (!pszFile)
2326  {
2327  *szPath = L'\0';
2328  pszFile = szPath;
2329  }
2330 
2331  /* Update the cached path (for link info) */
2332  ShellLink_GetVolumeInfo(pszFile, &volume);
2333 
2334  if (m_sPath)
2336 
2337  m_sPath = strdupW(pszFile);
2338  if (!m_sPath)
2339  return E_OUTOFMEMORY;
2340 
2341  m_bDirty = TRUE;
2342  return hr;
2343 }
2344 
2346 {
2347  LPWSTR unquoted = NULL;
2348  HRESULT hr = S_OK;
2349 
2350  TRACE("(%p)->(path=%s)\n", this, debugstr_w(pszFile));
2351 
2352  if (!pszFile)
2353  return E_INVALIDARG;
2354 
2355  /*
2356  * Allow upgrading Logo3 shortcuts (m_Header.dwFlags & SLDF_HAS_LOGO3ID),
2357  * but forbid upgrading Darwin ones.
2358  */
2360  return S_FALSE;
2361 
2362  /* quotes at the ends of the string are stripped */
2363  SIZE_T len = wcslen(pszFile);
2364  if (pszFile[0] == L'"' && pszFile[len-1] == L'"')
2365  {
2366  unquoted = strdupW(pszFile);
2367  PathUnquoteSpacesW(unquoted);
2368  pszFile = unquoted;
2369  }
2370 
2371  /* any other quote marks are invalid */
2372  if (wcschr(pszFile, L'"'))
2373  {
2374  hr = S_FALSE;
2375  goto end;
2376  }
2377 
2378  /* Clear the cached path */
2380  m_sPath = NULL;
2381 
2382  /* Check for an advertised target (Logo3 or Darwin) */
2383  if (SetAdvertiseInfo(pszFile) != S_OK)
2384  {
2385  /* This is not an advertised target, but a regular path */
2387 
2388  /*
2389  * Check whether the user-given file path contains unexpanded
2390  * environment variables. If so, create a target environment block.
2391  * Note that in this block we will store the user-given path.
2392  * It will contain the unexpanded environment variables, but
2393  * it can also contain already expanded path that the user does
2394  * not want to see them unexpanded (e.g. so that they always
2395  * refer to the same place even if the would-be corresponding
2396  * environment variable could change).
2397  */
2398  if (*pszFile)
2400  else
2401  *szPath = L'\0';
2402 
2403  if (*pszFile && (wcscmp(pszFile, szPath) != 0))
2404  {
2405  /*
2406  * The user-given file path contains unexpanded environment
2407  * variables, so we need a target environment block.
2408  */
2410  LPEXP_SZ_LINK pInfo;
2411 
2413  if (pInfo)
2414  {
2415  /* Make sure that the size of the structure is valid */
2416  if (pInfo->cbSize != sizeof(*pInfo))
2417  {
2418  ERR("Ooops. This structure is not as expected...\n");
2419 
2420  /* Invalid structure, remove it altogether */
2423 
2424  /* Reset the pointer and go use the static buffer */
2425  pInfo = NULL;
2426  }
2427  }
2428  if (!pInfo)
2429  {
2430  /* Use the static buffer */
2431  pInfo = &buffer;
2432  buffer.cbSize = sizeof(buffer);
2433  buffer.dwSignature = EXP_SZ_LINK_SIG;
2434  }
2435 
2436  lstrcpynW(pInfo->szwTarget, pszFile, _countof(pInfo->szwTarget));
2437  WideCharToMultiByte(CP_ACP, 0, pszFile, -1,
2438  pInfo->szTarget, _countof(pInfo->szTarget), NULL, NULL);
2439 
2440  hr = S_OK;
2441  if (pInfo == &buffer)
2442  hr = AddDataBlock(pInfo);
2443  if (hr == S_OK)
2445 
2446  /* Now, make pszFile point to the expanded path */
2447  pszFile = szPath;
2448  }
2449  else
2450  {
2451  /*
2452  * The user-given file path does not contain unexpanded environment
2453  * variables, so we need to remove any target environment block.
2454  */
2457 
2458  /* pszFile points to the user path */
2459  }
2460 
2461  /* Set the target */
2462  hr = SetTargetFromPIDLOrPath(NULL, pszFile);
2463  }
2464 
2465  m_bDirty = TRUE;
2466 
2467 end:
2468  HeapFree(GetProcessHeap(), 0, unquoted);
2469  return hr;
2470 }
2471 
2473 {
2474  if (SHAddDataBlock(&m_pDBList, (DATABLOCK_HEADER*)pDataBlock))
2475  {
2476  m_bDirty = TRUE;
2477  return S_OK;
2478  }
2479  return S_FALSE;
2480 }
2481 
2483 {
2484  DATABLOCK_HEADER* pBlock;
2485  PVOID pDataBlock;
2486 
2487  TRACE("%p %08x %p\n", this, dwSig, ppDataBlock);
2488 
2489  *ppDataBlock = NULL;
2490 
2491  pBlock = SHFindDataBlock(m_pDBList, dwSig);
2492  if (!pBlock)
2493  {
2494  ERR("unknown datablock %08x (not found)\n", dwSig);
2495  return E_FAIL;
2496  }
2497 
2498  pDataBlock = LocalAlloc(LMEM_ZEROINIT, pBlock->cbSize);
2499  if (!pDataBlock)
2500  return E_OUTOFMEMORY;
2501 
2502  CopyMemory(pDataBlock, pBlock, pBlock->cbSize);
2503 
2504  *ppDataBlock = pDataBlock;
2505  return S_OK;
2506 }
2507 
2509 {
2510  if (SHRemoveDataBlock(&m_pDBList, dwSig))
2511  {
2512  m_bDirty = TRUE;
2513  return S_OK;
2514  }
2515  return S_FALSE;
2516 }
2517 
2519 {
2520  TRACE("%p %p\n", this, pdwFlags);
2521  *pdwFlags = m_Header.dwFlags;
2522  return S_OK;
2523 }
2524 
2526 {
2527 #if 0 // FIXME!
2529  m_bDirty = TRUE;
2530  return S_OK;
2531 #else
2532  FIXME("\n");
2533  return E_NOTIMPL;
2534 #endif
2535 }
2536 
2537 /**************************************************************************
2538  * CShellLink implementation of IShellExtInit::Initialize()
2539  *
2540  * Loads the shelllink from the dataobject the shell is pointing to.
2541  */
2543 {
2544  TRACE("%p %p %p %p\n", this, pidlFolder, pdtobj, hkeyProgID);
2545 
2546  if (!pdtobj)
2547  return E_FAIL;
2548 
2549  FORMATETC format;
2550  format.cfFormat = CF_HDROP;
2551  format.ptd = NULL;
2552  format.dwAspect = DVASPECT_CONTENT;
2553  format.lindex = -1;
2554  format.tymed = TYMED_HGLOBAL;
2555 
2556  STGMEDIUM stgm;
2557  HRESULT hr = pdtobj->GetData(&format, &stgm);
2558  if (FAILED(hr))
2559  return hr;
2560 
2561  UINT count = DragQueryFileW((HDROP)stgm.hGlobal, -1, NULL, 0);
2562  if (count == 1)
2563  {
2564  count = DragQueryFileW((HDROP)stgm.hGlobal, 0, NULL, 0);
2565  count++;
2566  LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
2567  if (path)
2568  {
2569  count = DragQueryFileW((HDROP)stgm.hGlobal, 0, path, count);
2570  hr = Load(path, 0);
2571  HeapFree(GetProcessHeap(), 0, path);
2572  }
2573  }
2574  ReleaseStgMedium(&stgm);
2575 
2576  return S_OK;
2577 }
2578 
2580 {
2581  INT id = 0;
2582 
2583  m_idCmdFirst = idCmdFirst;
2584 
2585  TRACE("%p %p %u %u %u %u\n", this,
2586  hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
2587 
2588  if (!hMenu)
2589  return E_INVALIDARG;
2590 
2593 
2594  MENUITEMINFOW mii;
2595  ZeroMemory(&mii, sizeof(mii));
2596  mii.cbSize = sizeof(mii);
2597  mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
2598  mii.dwTypeData = strOpen.GetBuffer();
2599  mii.cch = wcslen(mii.dwTypeData);
2600  mii.wID = idCmdFirst + id++;
2601  mii.fState = MFS_DEFAULT | MFS_ENABLED;
2602  mii.fType = MFT_STRING;
2603  if (!InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii))
2604  return E_FAIL;
2605 
2606  mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
2607  mii.dwTypeData = strOpenFileLoc.GetBuffer();
2608  mii.cch = wcslen(mii.dwTypeData);
2609  mii.wID = idCmdFirst + id++;
2610  mii.fState = MFS_ENABLED;
2611  mii.fType = MFT_STRING;
2612  if (!InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii))
2613  return E_FAIL;
2614 
2615  UNREFERENCED_PARAMETER(indexMenu);
2616 
2617  return MAKE_HRESULT(SEVERITY_SUCCESS, 0, id);
2618 }
2619 
2621 {
2622  WCHAR szParams[MAX_PATH + 64];
2623  StringCbPrintfW(szParams, sizeof(szParams), L"/select,%s", m_sPath);
2624 
2625  INT_PTR ret;
2626  ret = reinterpret_cast<INT_PTR>(ShellExecuteW(NULL, NULL, L"explorer.exe", szParams,
2628  if (ret <= 32)
2629  {
2630  ERR("ret: %08lX\n", ret);
2631  return E_FAIL;
2632  }
2633 
2634  return S_OK;
2635 }
2636 
2638 {
2639  TRACE("%p %p\n", this, lpici);
2640 
2641  if (lpici->cbSize < sizeof(CMINVOKECOMMANDINFO))
2642  return E_INVALIDARG;
2643 
2644  // NOTE: We could use lpici->hwnd (certainly in case lpici->fMask doesn't contain CMIC_MASK_FLAG_NO_UI)
2645  // as the parent window handle... ?
2646  /* FIXME: get using interface set from IObjectWithSite?? */
2647  // NOTE: We might need an extended version of Resolve that provides us with paths...
2648  HRESULT hr = Resolve(lpici->hwnd, 0);
2649  if (FAILED(hr))
2650  {
2651  TRACE("failed to resolve component with error 0x%08x", hr);
2652  return hr;
2653  }
2654 
2655  UINT idCmd = LOWORD(lpici->lpVerb);
2656  TRACE("idCmd: %d\n", idCmd);
2657 
2658  switch (idCmd)
2659  {
2660  case IDCMD_OPEN:
2661  return DoOpen(lpici);
2663  return DoOpenFileLocation();
2664  default:
2665  return E_NOTIMPL;
2666  }
2667 }
2668 
2670 {
2671  HRESULT hr;
2672  LPWSTR args = NULL;
2674 
2675  if ( lpici->cbSize == sizeof(CMINVOKECOMMANDINFOEX) &&
2676  (lpici->fMask & CMIC_MASK_UNICODE) )
2677  {
2679  SIZE_T len = 2;
2680 
2681  if (m_sArgs)
2682  len += wcslen(m_sArgs);
2683  if (iciex->lpParametersW)
2684  len += wcslen(iciex->lpParametersW);
2685 
2686  args = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2687  *args = 0;
2688  if (m_sArgs)
2689  wcscat(args, m_sArgs);
2690  if (iciex->lpParametersW)
2691  {
2692  wcscat(args, L" ");
2693  wcscat(args, iciex->lpParametersW);
2694  }
2695  }
2696  else if (m_sArgs != NULL)
2697  {
2698  args = strdupW(m_sArgs);
2699  }
2700 
2701  SHELLEXECUTEINFOW sei;
2702  ZeroMemory(&sei, sizeof(sei));
2703  sei.cbSize = sizeof(sei);
2706  sei.lpFile = path;
2707  sei.lpClass = m_sLinkPath;
2708  sei.nShow = m_Header.nShowCommand;
2709  sei.lpDirectory = m_sWorkDir;
2710  sei.lpParameters = args;
2711  sei.lpVerb = L"open";
2712 
2713  // HACK for ShellExecuteExW
2714  if (m_sPath && wcsstr(m_sPath, L".cpl"))
2715  sei.lpVerb = L"cplopen";
2716 
2717  if (ShellExecuteExW(&sei))
2718  hr = S_OK;
2719  else
2720  hr = E_FAIL;
2721 
2722  HeapFree(GetProcessHeap(), 0, args);
2723  HeapFree(GetProcessHeap(), 0, path);
2724 
2725  return hr;
2726 }
2727 
2729 {
2730  FIXME("%p %lu %u %p %p %u\n", this, idCmd, uType, pwReserved, pszName, cchMax);
2731  return E_NOTIMPL;
2732 }
2733 
2736 {
2737  switch(uMsg)
2738  {
2739  case WM_INITDIALOG:
2740  if (lParam)
2741  {
2742  HWND hDlgCtrl = GetDlgItem(hwndDlg, IDC_SHORTEX_RUN_DIFFERENT);
2743  SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0);
2744  }
2745  return TRUE;
2746  case WM_COMMAND:
2747  {
2748  HWND hDlgCtrl = GetDlgItem(hwndDlg, IDC_SHORTEX_RUN_DIFFERENT);
2749  if (LOWORD(wParam) == IDOK)
2750  {
2751  if (SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED)
2752  EndDialog(hwndDlg, 1);
2753  else
2754  EndDialog(hwndDlg, 0);
2755  }
2756  else if (LOWORD(wParam) == IDCANCEL)
2757  {
2758  EndDialog(hwndDlg, -1);
2759  }
2761  {
2762  if (SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED)
2763  SendMessage(hDlgCtrl, BM_SETCHECK, BST_UNCHECKED, 0);
2764  else
2765  SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0);
2766  }
2767  }
2768  }
2769  return FALSE;
2770 }
2771 
2773 WINAPI
2775  UINT cidl,
2776  PCUITEMID_CHILD_ARRAY apidl,
2777  DWORD dwFlags);
2778 
2779 /**************************************************************************
2780 * SH_GetTargetTypeByPath
2781 *
2782 * Function to get target type by passing full path to it
2783 */
2785 {
2786  LPCWSTR pwszExt;
2787  static WCHAR wszBuf[MAX_PATH];
2788 
2789  /* Get file information */
2790  SHFILEINFOW fi;
2791  if (!SHGetFileInfoW(lpcwFullPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES))
2792  {
2793  ERR("SHGetFileInfoW failed for %ls (%lu)\n", lpcwFullPath, GetLastError());
2794  fi.szTypeName[0] = L'\0';
2795  fi.hIcon = NULL;
2796  }
2797 
2798  pwszExt = PathFindExtensionW(lpcwFullPath);
2799  if (pwszExt[0])
2800  {
2801  if (!fi.szTypeName[0])
2802  {
2803  /* The file type is unknown, so default to string "FileExtension File" */
2804  size_t cchRemaining = 0;
2805  LPWSTR pwszEnd = NULL;
2806 
2807  StringCchPrintfExW(wszBuf, _countof(wszBuf), &pwszEnd, &cchRemaining, 0, L"%s ", pwszExt + 1);
2808  }
2809  else
2810  {
2811  /* Update file type */
2812  StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s (%s)", fi.szTypeName, pwszExt);
2813  }
2814  }
2815 
2816  return wszBuf;
2817 }
2818 
2820 {
2821  TRACE("CShellLink::OnInitDialog(hwnd %p hwndFocus %p lParam %p)\n", hwndDlg, hwndFocus, lParam);
2822 
2823  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,
2825 
2826  m_bInInit = TRUE;
2827 
2828  /* Get file information */
2829  // FIXME! FIXME! Shouldn't we use m_sIcoPath, m_Header.nIconIndex instead???
2830  SHFILEINFOW fi;
2831  if (!SHGetFileInfoW(m_sLinkPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME | SHGFI_ICON))
2832  {
2833  ERR("SHGetFileInfoW failed for %ls (%lu)\n", m_sLinkPath, GetLastError());
2834  fi.szTypeName[0] = L'\0';
2835  fi.hIcon = NULL;
2836  }
2837 
2838  if (fi.hIcon)
2839  {
2840  if (m_hIcon)
2842  m_hIcon = fi.hIcon;
2844  }
2845  else
2846  ERR("ExtractIconW failed %ls %u\n", m_sIcoPath, m_Header.nIconIndex);
2847 
2848  /* Target type */
2849  if (m_sPath)
2851 
2852  /* Target location */
2853  if (m_sPath)
2854  {
2859  }
2860 
2861  /* Target path */
2862  if (m_sPath)
2863  {
2864  WCHAR newpath[2*MAX_PATH] = L"\0";
2865  if (wcschr(m_sPath, ' '))
2866  StringCchPrintfExW(newpath, _countof(newpath), NULL, NULL, 0, L"\"%ls\"", m_sPath);
2867  else
2868  StringCchCopyExW(newpath, _countof(newpath), m_sPath, NULL, NULL, 0);
2869 
2870  if (m_sArgs && m_sArgs[0])
2871  {
2872  StringCchCatW(newpath, _countof(newpath), L" ");
2873  StringCchCatW(newpath, _countof(newpath), m_sArgs);
2874  }
2875  SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, newpath);
2876  }
2877 
2878  /* Working dir */
2879  if (m_sWorkDir)
2881 
2882  /* Description */
2883  if (m_sDescription)
2885 
2886  m_bInInit = FALSE;
2887 
2888  return TRUE;
2889 }
2890 
2891 void CShellLink::OnCommand(HWND hwndDlg, int id, HWND hwndCtl, UINT codeNotify)
2892 {
2893  switch (id)
2894  {
2895  case IDC_SHORTCUT_FIND:
2901  return;
2902 
2904  {
2905  WCHAR wszPath[MAX_PATH] = L"";
2906 
2907  if (m_sIcoPath)
2908  wcscpy(wszPath, m_sIcoPath);
2909  else
2910  FindExecutableW(m_sPath, NULL, wszPath);
2911 
2913  if (PickIconDlg(hwndDlg, wszPath, _countof(wszPath), &IconIndex))
2914  {
2915  SetIconLocation(wszPath, IconIndex);
2916  PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
2917 
2918  HICON hIconLarge = CreateShortcutIcon(wszPath, IconIndex);
2919  if (hIconLarge)
2920  {
2921  if (m_hIcon)
2923  m_hIcon = hIconLarge;
2925  }
2926  }
2927  return;
2928  }
2929 
2930  case IDC_SHORTCUT_ADVANCED:
2931  {
2933  if (result == 1 || result == 0)
2934  {
2935  if (m_bRunAs != result)
2936  {
2937  PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
2938  }
2939 
2940  m_bRunAs = result;
2941  }
2942  return;
2943  }
2944  }
2945  if (codeNotify == EN_CHANGE)
2946  {
2947  if (!m_bInInit)
2948  PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
2949  }
2950 }
2951 
2952 LRESULT CShellLink::OnNotify(HWND hwndDlg, int idFrom, LPNMHDR pnmhdr)
2953 {
2954  WCHAR wszBuf[MAX_PATH];
2955  LPPSHNOTIFY lppsn = (LPPSHNOTIFY)pnmhdr;
2956 
2957  if (lppsn->hdr.code == PSN_APPLY)
2958  {
2959  /* set working directory */
2960  GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_START_IN_EDIT, wszBuf, _countof(wszBuf));
2961  SetWorkingDirectory(wszBuf);
2962 
2963  /* set link destination */
2964  GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, wszBuf, _countof(wszBuf));
2965  LPWSTR lpszArgs = NULL;
2966  LPWSTR unquoted = strdupW(wszBuf);
2967  StrTrimW(unquoted, L" ");
2968 
2969  if (!PathFileExistsW(unquoted))
2970  {
2971  lpszArgs = PathGetArgsW(unquoted);
2972  PathRemoveArgsW(unquoted);
2973  StrTrimW(lpszArgs, L" ");
2974  }
2975  if (unquoted[0] == '"' && unquoted[wcslen(unquoted) - 1] == '"')
2976  PathUnquoteSpacesW(unquoted);
2977 
2978  WCHAR *pwszExt = PathFindExtensionW(unquoted);
2979  if (!wcsicmp(pwszExt, L".lnk"))
2980  {
2981  // FIXME load localized error msg
2982  MessageBoxW(hwndDlg, L"You cannot create a link to a shortcut", L"Error", MB_ICONERROR);
2984  return TRUE;
2985  }
2986 
2987  if (!PathFileExistsW(unquoted))
2988  {
2989  // FIXME load localized error msg
2990  MessageBoxW(hwndDlg, L"The specified file name in the target box is invalid", L"Error", MB_ICONERROR);
2992  return TRUE;
2993  }
2994 
2995  SetPath(unquoted);
2996  if (lpszArgs)
2997  SetArguments(lpszArgs);
2998  else
2999  SetArguments(L"\0");
3000 
3001  HeapFree(GetProcessHeap(), 0, unquoted);
3002 
3003  TRACE("This %p m_sLinkPath %S\n", this, m_sLinkPath);
3004  Save(m_sLinkPath, TRUE);
3007  return TRUE;
3008  }
3009  return FALSE;
3010 }
3011 
3013 {
3014  if (m_hIcon)
3015  {
3017  m_hIcon = NULL;
3018  }
3019 }
3020 
3021 /**************************************************************************
3022  * SH_ShellLinkDlgProc
3023  *
3024  * dialog proc of the shortcut property dialog
3025  */
3026 
3029 {
3030  LPPROPSHEETPAGEW ppsp;
3031  CShellLink *pThis = reinterpret_cast<CShellLink *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
3032 
3033  switch (uMsg)
3034  {
3035  case WM_INITDIALOG:
3036  ppsp = (LPPROPSHEETPAGEW)lParam;
3037  if (ppsp == NULL)
3038  break;
3039 
3040  pThis = reinterpret_cast<CShellLink *>(ppsp->lParam);
3041  SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pThis);
3042  return pThis->OnInitDialog(hwndDlg, (HWND)(wParam), lParam);
3043 
3044  case WM_NOTIFY:
3045  return pThis->OnNotify(hwndDlg, (int)wParam, (NMHDR *)lParam);
3046 
3047  case WM_COMMAND:
3048  pThis->OnCommand(hwndDlg, LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
3049  break;
3050 
3051  case WM_DESTROY:
3052  pThis->OnDestroy(hwndDlg);
3053  break;
3054 
3055  default:
3056  break;
3057  }
3058 
3059  return FALSE;
3060 }
3061 
3062 /**************************************************************************
3063  * ShellLink_IShellPropSheetExt interface
3064  */
3065 
3067 {
3069  if (hPage == NULL)
3070  {
3071  ERR("failed to create property sheet page\n");
3072  return E_FAIL;
3073  }
3074 
3075  if (!pfnAddPage(hPage, lParam))
3076  return E_FAIL;
3077 
3078  return S_OK;
3079 }
3080 
3082 {
3083  TRACE("(%p) (uPageID %u, pfnReplacePage %p lParam %p\n", this, uPageID, pfnReplacePage, lParam);
3084  return E_NOTIMPL;
3085 }
3086 
3088 {
3089  TRACE("%p %p\n", this, punk);
3090 
3091  m_site = punk;
3092 
3093  return S_OK;
3094 }
3095 
3097 {
3098  TRACE("%p %s %p\n", this, debugstr_guid(&iid), ppvSite);
3099 
3100  if (m_site == NULL)
3101  return E_FAIL;
3102 
3103  return m_site->QueryInterface(iid, ppvSite);
3104 }
3105 
3107  DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
3108 {
3109  TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
3110 
3111  if (*pdwEffect == DROPEFFECT_NONE)
3112  return S_OK;
3113 
3114  LPCITEMIDLIST pidlLast;
3116 
3117  HRESULT hr = SHBindToParent(m_pPidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
3118 
3119  if (SUCCEEDED(hr))
3120  {
3121  hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_NULL_PPV_ARG(IDropTarget, &m_DropTarget));
3122 
3123  if (SUCCEEDED(hr))
3124  hr = m_DropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect);
3125  else
3126  *pdwEffect = DROPEFFECT_NONE;
3127  }
3128  else
3129  *pdwEffect = DROPEFFECT_NONE;
3130 
3131  return S_OK;
3132 }
3133 
3135  DWORD *pdwEffect)
3136 {
3137  TRACE("(%p)\n", this);
3138  HRESULT hr = S_OK;
3139  if (m_DropTarget)
3140  hr = m_DropTarget->DragOver(dwKeyState, pt, pdwEffect);
3141  return hr;
3142 }
3143 
3145 {
3146  TRACE("(%p)\n", this);
3147  HRESULT hr = S_OK;
3148  if (m_DropTarget)
3149  {
3150  hr = m_DropTarget->DragLeave();
3152  }
3153 
3154  return hr;
3155 }
3156 
3158  DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
3159 {
3160  TRACE("(%p)\n", this);
3161  HRESULT hr = S_OK;
3162  if (m_DropTarget)
3163  hr = m_DropTarget->Drop(pDataObject, dwKeyState, pt, pdwEffect);
3164 
3165  return hr;
3166 }
3167 
3168 /**************************************************************************
3169  * IShellLink_ConstructFromFile
3170  */
3172 {
3174  HRESULT hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IPersistFile, &ppf));
3175  if (FAILED(hr))
3176  return hr;
3177 
3178  hr = ppf->Load(path, 0);
3179  if (FAILED(hr))
3180  return hr;
3181 
3182  return ppf->QueryInterface(riid, ppv);
3183 }
3184 
3186 {
3187  WCHAR path[MAX_PATH];
3188  if (!ILGetDisplayNameExW(psf, pidl, path, 0))
3189  return E_FAIL;
3190 
3192 }
3193 
3195 {
3197  const COLORREF crMask = GetSysColor(COLOR_3DFACE);
3198  HDC hDC;
3200  HICON hIcon = NULL, hNewIcon = NULL;
3202  IMAGE_ICON, cx, cy, 0);
3203 
3204  ::ExtractIconExW(wszIconPath, IconIndex, &hIcon, NULL, 1);
3205  if (!hIcon || !hShortcut || !himl)
3206  goto cleanup;
3207 
3209  if (hDC)
3210  {
3211  // create 32bpp bitmap
3212  BITMAPINFO bi;
3213  ZeroMemory(&bi, sizeof(bi));
3214  bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
3215  bi.bmiHeader.biWidth = cx;
3216  bi.bmiHeader.biHeight = cy;
3217  bi.bmiHeader.biPlanes = 1;
3218  bi.bmiHeader.biBitCount = 32;
3219  LPVOID pvBits;
3220  HBITMAP hbm = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0);
3221  if (hbm)
3222  {
3223  // draw the icon image
3224  HGDIOBJ hbmOld = SelectObject(hDC, hbm);
3225  {
3226  HBRUSH hbr = CreateSolidBrush(crMask);
3227  RECT rc = { 0, 0, cx, cy };
3228  FillRect(hDC, &rc, hbr);
3229  DeleteObject(hbr);
3230 
3231  DrawIconEx(hDC, 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL);
3232  DrawIconEx(hDC, 0, 0, hShortcut, cx, cy, 0, NULL, DI_NORMAL);
3233  }
3234  SelectObject(hDC, hbmOld);
3235 
3236  INT iAdded = ImageList_AddMasked(himl, hbm, crMask);
3237  hNewIcon = ImageList_GetIcon(himl, iAdded, ILD_NORMAL | ILD_TRANSPARENT);
3238 
3239  DeleteObject(hbm);
3240  }
3241  DeleteDC(hDC);
3242  }
3243 
3244 cleanup:
3245  if (hIcon)
3246  DestroyIcon(hIcon);
3247  if (hShortcut)
3248  DestroyIcon(hShortcut);
3249  if (himl)
3251 
3252  return hNewIcon;
3253 }
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:55
#define IN
Definition: typedefs.h:38
static HICON
Definition: imagelist.c:84
UINT WINAPI GetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount)
Definition: dialog.c:2265
BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
Definition: path.c:624
#define MFT_STRING
Definition: winuser.h:741
#define REFIID
Definition: guiddef.h:118
#define TRUE
Definition: types.h:120
uint16_t size
Definition: btrfs_drv.h:556
#define IDOK
Definition: winuser.h:824
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:925
#define IDC_SHORTCUT_TYPE_EDIT
Definition: shresdef.h:400
#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:404
#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:101
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 UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
#define pt(x, y)
Definition: drawing.c:79
GLsizei const GLchar ** path
Definition: glext.h:7234
#define IDD_SHORTCUT_EXTENDED_PROPERTIES
Definition: shresdef.h:344
_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:54
#define CP_ACP
Definition: compat.h:99
#define PRF_DONTFINDLNK
Definition: PathResolve.cpp:33
#define IDS_OPENFILELOCATION
Definition: shresdef.h:231
#define _countof(array)
Definition: fontsub.cpp:30
struct tagBITMAPINFOHEADER BITMAPINFOHEADER
#define LOCALE_USER_DEFAULT
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define IDC_SHORTCUT_ICON
Definition: shresdef.h:397
#define DATE_SHORTDATE
Definition: winnls.h:193
#define PRF_VERIFYEXISTS
Definition: PathResolve.cpp:29
#define WARN(fmt,...)
Definition: debug.h:111
#define STGM_CREATE
Definition: objbase.h:925
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1280
static HDC
Definition: imagelist.c:92
#define EXP_SZ_ICON_SIG
Definition: shlobj.h:1889
#define CALLBACK
Definition: compat.h:27
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:1497
#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:1059
#define ZeroMemory
Definition: winbase.h:1642
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:309
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:414
#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:62
#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:415
#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:56
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:405
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:402
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:418
NMHDR hdr
Definition: prsht.h:312
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:1885
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
HINSTANCE shell32_hInstance
Definition: misc.cpp:82
#define UNICODE_NULL
const PCUITEMID_CHILD * PCUITEMID_CHILD_ARRAY
Definition: shtypes.idl:71
_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:424
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:802
BOOL WINAPI PickIconDlg(HWND hWndOwner, LPWSTR lpstrFile, UINT nMaxFile, INT *lpdwIconIndex)
Definition: dialogs.cpp:350
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:110
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:412
_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:2235
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:505
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:403
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:1111
__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:410
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:326
LONG HRESULT
Definition: typedefs.h:77
DWORD COLORREF
Definition: windef.h:300
#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:580
#define MAX_PATH
Definition: compat.h:26
#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:1640
#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:338
static const WCHAR IconIndex[]
Definition: install.c:52
#define PSNRET_NOERROR
Definition: prsht.h:129
static PIXELFORMATDESCRIPTOR pfd
Definition: ssstars.c:67
HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
Definition: shlexec.cpp:1250
int ret
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:218
static __inline const char * debugstr_an(const char *s, int n)
Definition: compat.h:47
#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
void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
Definition: changenotify.c:340
#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
#define wcsicmp
Definition: string.h:1152
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:1755
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:413
#define ERR(fmt,...)
Definition: debug.h:109
#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:78
_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:59
struct IContextMenu::tagCMInvokeCommandInfoEx * LPCMINVOKECOMMANDINFOEX
#define SW_SHOWNORMAL
Definition: winuser.h:764
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:415
BOOL WINAPI DeleteDC(_In_ HDC)
HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
Definition: pidl.c:1323
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:254
_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:123
#define EXP_SZ_LINK_SIG
Definition: shlobj.h:1881
#define IDC_SHORTCUT_START_IN_EDIT
Definition: shresdef.h:406
#define MultiByteToWideChar
Definition: compat.h:100
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:39
GLuint res
Definition: glext.h:9613
HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
Definition: shlexec.cpp:2246
HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id)
Definition: compobj.c:2338
#define HIWORD(l)
Definition: typedefs.h:246
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:51
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define ILD_NORMAL
Definition: commctrl.h:413
#define GetWindowLongPtr
Definition: treelist.c:73
#define SHCNE_UPDATEITEM
Definition: shlobj.h:1733
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 EXTERN_C
Definition: basetyps.h:12
#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:65
#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:404
#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:402
_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:57
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
#define EN_CHANGE
Definition: winuser.h:2004