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