ReactOS 0.4.16-dev-555-g690643f
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-2024 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
191static 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;
206 return p;
207}
208
209static 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{
223 m_pPidl = NULL;
224
226 m_sPath = NULL;
227 ZeroMemory(&volume, sizeof(volume));
228
236 m_sArgs = 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
264 m_Header.wHotKey = 0;
265
266 m_pPidl = NULL;
267
268 m_sPath = NULL;
269 ZeroMemory(&volume, sizeof(volume));
270
274 m_sArgs = NULL;
276 m_bRunAs = FALSE;
277 m_bDirty = FALSE;
278 m_pDBList = NULL;
280 m_hIcon = NULL;
281 m_idCmdFirst = 0;
282
284
286}
287
289{
290 TRACE("-- destroying IShellLink(%p)\n", this);
291
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)
330
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
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
416static 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;
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 {
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
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)
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
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
750 if (pSpecial && pSpecial->cbSize == sizeof(*pSpecial) && ILGetSize(m_pPidl) > pSpecial->cbOffset)
751 {
753 {
754 LPITEMIDLIST pidl = ILCombine(folder, (LPITEMIDLIST)((char*)m_pPidl + pSpecial->cbOffset));
755 if (pidl)
756 {
758 m_pPidl = pidl;
759 TRACE("Replaced pidl base with CSIDL %u up to %ub.\n", pSpecial->idSpecialFolder, pSpecial->cbOffset);
760 }
761 ILFree(folder);
762 }
763 }
764
765 if (TRACE_ON(shell))
766 {
767#if (NTDDI_VERSION < NTDDI_LONGHORN)
769 {
770 hr = GetAdvertiseInfo(&sProduct, EXP_LOGO3_ID_SIG);
771 if (SUCCEEDED(hr))
772 TRACE("Product -> %s\n", debugstr_w(sProduct));
773 }
774#endif
776 {
778 if (SUCCEEDED(hr))
779 TRACE("Component -> %s\n", debugstr_w(sComponent));
780 }
781 }
782
784 m_bRunAs = TRUE;
785 else
786 m_bRunAs = FALSE;
787
788 TRACE("OK\n");
789
790 pdump(m_pPidl);
791
792 return S_OK;
793}
794
795/************************************************************************
796 * Stream_WriteString
797 *
798 * Helper function for IPersistStream_Save. Writes a unicode string
799 * with terminating nul byte to a stream, preceded by the its length.
800 */
802{
804 USHORT len;
805 DWORD count;
806
807 length = wcslen(str) + 1;
808 if (length > MAXUSHORT)
809 {
810 return E_INVALIDARG;
811 }
812
813 len = (USHORT)length;
814 HRESULT hr = stm->Write(&len, sizeof(len), &count);
815 if (FAILED(hr))
816 return hr;
817
818 length *= sizeof(WCHAR);
819
820 hr = stm->Write(str, (ULONG)length, &count);
821 if (FAILED(hr))
822 return hr;
823
824 return S_OK;
825}
826
827/************************************************************************
828 * Stream_WriteLocationInfo
829 *
830 * Writes the location info to a stream
831 *
832 * FIXME: One day we might want to write the network volume information
833 * and the final path.
834 * Figure out how Windows deals with unicode paths here.
835 */
838{
840 LOCATION_INFO *loc;
841
842 TRACE("%p %s %p\n", stm, debugstr_w(path), volume);
843
844 /* figure out the size of everything */
845 DWORD label_size = WideCharToMultiByte(CP_ACP, 0, volume->label, -1,
846 NULL, 0, NULL, NULL);
847 DWORD path_size = WideCharToMultiByte(CP_ACP, 0, path, -1,
848 NULL, 0, NULL, NULL);
849 DWORD volume_info_size = sizeof(*vol) + label_size;
850 DWORD final_path_size = 1;
851 DWORD total_size = sizeof(*loc) + volume_info_size + path_size + final_path_size;
852
853 /* create pointers to everything */
854 loc = static_cast<LOCATION_INFO *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, total_size));
855 vol = (LOCAL_VOLUME_INFO*) &loc[1];
856 LPSTR szLabel = (LPSTR) &vol[1];
857 LPSTR szPath = &szLabel[label_size];
858 LPSTR szFinalPath = &szPath[path_size];
859
860 /* fill in the location information header */
861 loc->dwTotalSize = total_size;
862 loc->dwHeaderSize = sizeof(*loc);
863 loc->dwFlags = 1;
864 loc->dwVolTableOfs = sizeof(*loc);
865 loc->dwLocalPathOfs = sizeof(*loc) + volume_info_size;
866 loc->dwNetworkVolTableOfs = 0;
867 loc->dwFinalPathOfs = sizeof(*loc) + volume_info_size + path_size;
868
869 /* fill in the volume information */
870 vol->dwSize = volume_info_size;
871 vol->dwType = volume->type;
872 vol->dwVolSerial = volume->serial;
873 vol->dwVolLabelOfs = sizeof(*vol);
874
875 /* copy in the strings */
876 WideCharToMultiByte(CP_ACP, 0, volume->label, -1,
877 szLabel, label_size, NULL, NULL);
879 szPath, path_size, NULL, NULL);
880 *szFinalPath = 0;
881
882 ULONG count = 0;
883 HRESULT hr = stm->Write(loc, total_size, &count);
884 HeapFree(GetProcessHeap(), 0, loc);
885
886 return hr;
887}
888
889/************************************************************************
890 * IPersistStream_Save (IPersistStream)
891 *
892 * FIXME: makes assumptions about byte order
893 */
895{
896 TRACE("%p %p %x\n", this, stm, fClearDirty);
897
898 m_Header.dwSize = sizeof(m_Header);
899 m_Header.clsid = CLSID_ShellLink;
900
901 /* Store target attributes */
902 WIN32_FIND_DATAW wfd = {};
903 WCHAR FsTarget[MAX_PATH];
904 if (GetPath(FsTarget, _countof(FsTarget), NULL, 0) == S_OK && PathFileExistsW(FsTarget))
905 {
906 HANDLE hFind = FindFirstFileW(FsTarget, &wfd);
907 if (hFind != INVALID_HANDLE_VALUE)
908 FindClose(hFind);
909 }
910 m_Header.dwFileAttributes = wfd.dwFileAttributes;
911 m_Header.ftCreationTime = wfd.ftCreationTime;
912 m_Header.ftLastAccessTime = wfd.ftLastAccessTime;
913 m_Header.ftLastWriteTime = wfd.ftLastWriteTime;
914 m_Header.nFileSizeLow = wfd.nFileSizeLow;
915
916 /*
917 * Reset the flags: keep only the flags related to data blocks as they were
918 * already set in accordance by the different mutator member functions.
919 * The other flags will be determined now by the presence or absence of data.
920 */
923#if (NTDDI_VERSION < NTDDI_LONGHORN)
925#endif
927 // TODO: When we will support Vista+ functionality, add other flags to this list.
928
929 /* The stored strings are in UNICODE */
931
932 if (m_pPidl)
938 if (m_sPathRel && *m_sPathRel)
940 if (m_sWorkDir && *m_sWorkDir)
942 if (m_sArgs && *m_sArgs)
944 if (m_sIcoPath && *m_sIcoPath)
946 if (m_bRunAs)
948
949 /* Write the shortcut header */
950 ULONG count;
951 HRESULT hr = stm->Write(&m_Header, sizeof(m_Header), &count);
952 if (FAILED(hr))
953 {
954 ERR("Write failed\n");
955 return hr;
956 }
957
958 /* Save the data in order */
959
960 if (m_pPidl)
961 {
962 hr = ILSaveToStream(stm, m_pPidl);
963 if (FAILED(hr))
964 {
965 ERR("Failed to write PIDL\n");
966 return hr;
967 }
968 }
969
971 {
973 if (FAILED(hr))
974 return hr;
975 }
976
978 {
980 if (FAILED(hr))
981 return hr;
982 }
983
985 {
987 if (FAILED(hr))
988 return hr;
989 }
990
992 {
994 if (FAILED(hr))
995 return hr;
996 }
997
999 {
1001 if (FAILED(hr))
1002 return hr;
1003 }
1004
1006 {
1008 if (FAILED(hr))
1009 return hr;
1010 }
1011
1012 /*
1013 * Now save the data block list.
1014 *
1015 * NOTE that both advertised Product and Component are already saved
1016 * inside Logo3 and Darwin data blocks in the m_pDBList list, and the
1017 * m_Header.dwFlags is suitably initialized.
1018 */
1020 if (FAILED(hr))
1021 return hr;
1022
1023 /* Clear the dirty bit if requested */
1024 if (fClearDirty)
1025 m_bDirty = FALSE;
1026
1027 return hr;
1028}
1029
1030/************************************************************************
1031 * IPersistStream_GetSizeMax (IPersistStream)
1032 */
1034{
1035 TRACE("(%p)\n", this);
1036 return E_NOTIMPL;
1037}
1038
1040{
1042 return FALSE;
1043
1044 return TRUE;
1045}
1046
1047/**************************************************************************
1048 * ShellLink_UpdatePath
1049 * update absolute path in sPath using relative path in sPathRel
1050 */
1051static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath)
1052{
1053 if (!path || !psPath)
1054 return E_INVALIDARG;
1055
1056 if (!*psPath && sPathRel)
1057 {
1058 WCHAR buffer[2*MAX_PATH], abs_path[2*MAX_PATH];
1059 LPWSTR final = NULL;
1060
1061 /* first try if [directory of link file] + [relative path] finds an existing file */
1062
1063 GetFullPathNameW(path, MAX_PATH * 2, buffer, &final);
1064 if (!final)
1065 final = buffer;
1066 wcscpy(final, sPathRel);
1067
1068 *abs_path = '\0';
1069
1071 {
1072 if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
1073 wcscpy(abs_path, buffer);
1074 }
1075 else
1076 {
1077 /* try if [working directory] + [relative path] finds an existing file */
1078 if (sWorkDir)
1079 {
1080 wcscpy(buffer, sWorkDir);
1081 wcscpy(PathAddBackslashW(buffer), sPathRel);
1082
1084 if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
1085 wcscpy(abs_path, buffer);
1086 }
1087 }
1088
1089 /* FIXME: This is even not enough - not all shell links can be resolved using this algorithm. */
1090 if (!*abs_path)
1091 wcscpy(abs_path, sPathRel);
1092
1093 *psPath = strdupW(abs_path);
1094 if (!*psPath)
1095 return E_OUTOFMEMORY;
1096 }
1097
1098 return S_OK;
1099}
1100
1102{
1103 HRESULT hr;
1104 LPWSTR pszFileW;
1105 WIN32_FIND_DATAW wfd;
1106
1107 TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
1108 this, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(m_sPath));
1109
1110 /* Allocate a temporary UNICODE buffer */
1111 pszFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, max(cchMaxPath, MAX_PATH) * sizeof(WCHAR));
1112 if (!pszFileW)
1113 return E_OUTOFMEMORY;
1114
1115 /* Call the UNICODE function */
1116 hr = GetPath(pszFileW, cchMaxPath, &wfd, fFlags);
1117
1118 /* Convert the file path back to ANSI */
1119 WideCharToMultiByte(CP_ACP, 0, pszFileW, -1,
1120 pszFile, cchMaxPath, NULL, NULL);
1121
1122 /* Free the temporary buffer */
1123 HeapFree(GetProcessHeap(), 0, pszFileW);
1124
1125 if (pfd)
1126 {
1127 ZeroMemory(pfd, sizeof(*pfd));
1128
1129 /* Copy the file data if a file path was returned */
1130 if (*pszFile)
1131 {
1132 DWORD len;
1133
1134 /* Copy the fixed part */
1135 CopyMemory(pfd, &wfd, FIELD_OFFSET(WIN32_FIND_DATAA, cFileName));
1136
1137 /* Convert the file names to ANSI */
1138 len = lstrlenW(wfd.cFileName);
1139 WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, len + 1,
1140 pfd->cFileName, sizeof(pfd->cFileName), NULL, NULL);
1141 len = lstrlenW(wfd.cAlternateFileName);
1142 WideCharToMultiByte(CP_ACP, 0, wfd.cAlternateFileName, len + 1,
1143 pfd->cAlternateFileName, sizeof(pfd->cAlternateFileName), NULL, NULL);
1144 }
1145 }
1146
1147 return hr;
1148}
1149
1151{
1152 TRACE("(%p)->(ppidl=%p)\n", this, ppidl);
1153
1154 if (!m_pPidl)
1155 {
1156 *ppidl = NULL;
1157 return S_FALSE;
1158 }
1159
1160 *ppidl = ILClone(m_pPidl);
1161 return S_OK;
1162}
1163
1165{
1166 TRACE("(%p)->(pidl=%p)\n", this, pidl);
1167 return SetTargetFromPIDLOrPath(pidl, NULL);
1168}
1169
1171{
1172 TRACE("(%p)->(%p len=%u)\n", this, pszName, cchMaxName);
1173
1174 if (cchMaxName)
1175 *pszName = 0;
1176
1177 if (m_sDescription)
1179 pszName, cchMaxName, NULL, NULL);
1180
1181 return S_OK;
1182}
1183
1185{
1186 TRACE("(%p)->(pName=%s)\n", this, pszName);
1187
1190
1191 if (pszName)
1192 {
1194 if (!m_sDescription)
1195 return E_OUTOFMEMORY;
1196 }
1197 m_bDirty = TRUE;
1198
1199 return S_OK;
1200}
1201
1203{
1204 TRACE("(%p)->(%p len=%u)\n", this, pszDir, cchMaxPath);
1205
1206 if (cchMaxPath)
1207 *pszDir = 0;
1208
1209 if (m_sWorkDir)
1211 pszDir, cchMaxPath, NULL, NULL);
1212
1213 return S_OK;
1214}
1215
1217{
1218 TRACE("(%p)->(dir=%s)\n", this, pszDir);
1219
1221 m_sWorkDir = NULL;
1222
1223 if (pszDir)
1224 {
1226 if (!m_sWorkDir)
1227 return E_OUTOFMEMORY;
1228 }
1229 m_bDirty = TRUE;
1230
1231 return S_OK;
1232}
1233
1235{
1236 TRACE("(%p)->(%p len=%u)\n", this, pszArgs, cchMaxPath);
1237
1238 if (cchMaxPath)
1239 *pszArgs = 0;
1240
1241 if (m_sArgs)
1243 pszArgs, cchMaxPath, NULL, NULL);
1244
1245 return S_OK;
1246}
1247
1249{
1250 TRACE("(%p)->(args=%s)\n", this, pszArgs);
1251
1253 m_sArgs = NULL;
1254
1255 if (pszArgs)
1256 {
1257 m_sArgs = HEAP_strdupAtoW(GetProcessHeap(), 0, pszArgs);
1258 if (!m_sArgs)
1259 return E_OUTOFMEMORY;
1260 }
1261 m_bDirty = TRUE;
1262
1263 return S_OK;
1264}
1265
1267{
1268 TRACE("(%p)->(%p)(0x%08x)\n", this, pwHotkey, m_Header.wHotKey);
1269 *pwHotkey = m_Header.wHotKey;
1270 return S_OK;
1271}
1272
1274{
1275 TRACE("(%p)->(hotkey=%x)\n", this, wHotkey);
1276
1277 m_Header.wHotKey = wHotkey;
1278 m_bDirty = TRUE;
1279
1280 return S_OK;
1281}
1282
1284{
1285 TRACE("(%p)->(%p) %d\n", this, piShowCmd, m_Header.nShowCommand);
1286 *piShowCmd = m_Header.nShowCommand;
1287 return S_OK;
1288}
1289
1291{
1292 TRACE("(%p) %d\n", this, iShowCmd);
1293
1294 m_Header.nShowCommand = iShowCmd;
1295 m_bDirty = TRUE;
1296
1297 return S_OK;
1298}
1299
1301{
1302 HRESULT hr;
1303 LPWSTR pszIconPathW;
1304
1305 TRACE("(%p)->(%p len=%u iicon=%p)\n", this, pszIconPath, cchIconPath, piIcon);
1306
1307 /* Allocate a temporary UNICODE buffer */
1308 pszIconPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchIconPath * sizeof(WCHAR));
1309 if (!pszIconPathW)
1310 return E_OUTOFMEMORY;
1311
1312 /* Call the UNICODE function */
1313 hr = GetIconLocation(pszIconPathW, cchIconPath, piIcon);
1314
1315 /* Convert the file path back to ANSI */
1316 WideCharToMultiByte(CP_ACP, 0, pszIconPathW, -1,
1317 pszIconPath, cchIconPath, NULL, NULL);
1318
1319 /* Free the temporary buffer */
1320 HeapFree(GetProcessHeap(), 0, pszIconPathW);
1321
1322 return hr;
1323}
1324
1326{
1327 HRESULT hr;
1328 LPWSTR pszIconFileW;
1329
1330 TRACE("(%p)->(%u %p len=%u piIndex=%p pwFlags=%p)\n", this, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1331
1332 /* Allocate a temporary UNICODE buffer */
1333 pszIconFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchMax * sizeof(WCHAR));
1334 if (!pszIconFileW)
1335 return E_OUTOFMEMORY;
1336
1337 /* Call the UNICODE function */
1338 hr = GetIconLocation(uFlags, pszIconFileW, cchMax, piIndex, pwFlags);
1339
1340 /* Convert the file path back to ANSI */
1341 WideCharToMultiByte(CP_ACP, 0, pszIconFileW, -1,
1342 pszIconFile, cchMax, NULL, NULL);
1343
1344 /* Free the temporary buffer */
1345 HeapFree(GetProcessHeap(), 0, pszIconFileW);
1346
1347 return hr;
1348}
1349
1350HRESULT STDMETHODCALLTYPE CShellLink::Extract(PCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
1351{
1352 TRACE("(%p)->(path=%s iicon=%u)\n", this, pszFile, nIconIndex);
1353
1354 LPWSTR str = NULL;
1355 if (pszFile)
1356 {
1357 str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
1358 if (!str)
1359 return E_OUTOFMEMORY;
1360 }
1361
1362 HRESULT hr = Extract(str, nIconIndex, phiconLarge, phiconSmall, nIconSize);
1363
1364 if (str)
1366
1367 return hr;
1368}
1369
1371{
1372 TRACE("(%p)->(path=%s iicon=%u)\n", this, pszIconPath, iIcon);
1373
1374 LPWSTR str = NULL;
1375 if (pszIconPath)
1376 {
1377 str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath);
1378 if (!str)
1379 return E_OUTOFMEMORY;
1380 }
1381
1382 HRESULT hr = SetIconLocation(str, iIcon);
1383
1384 if (str)
1386
1387 return hr;
1388}
1389
1391{
1392 TRACE("(%p)->(path=%s %x)\n", this, pszPathRel, dwReserved);
1393
1395 m_sPathRel = NULL;
1396
1397 if (pszPathRel)
1398 {
1399 m_sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
1400 m_bDirty = TRUE;
1401 }
1402
1404}
1405
1406static LPWSTR
1408{
1409 DWORD Result, sz = 0;
1410
1411 Result = CommandLineFromMsiDescriptor(component, NULL, &sz);
1412 if (Result != ERROR_SUCCESS)
1413 return NULL;
1414
1415 sz++;
1416 LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR));
1417 Result = CommandLineFromMsiDescriptor(component, path, &sz);
1418 if (Result != ERROR_SUCCESS)
1419 {
1421 path = NULL;
1422 }
1423
1424 TRACE("returning %s\n", debugstr_w(path));
1425
1426 return path;
1427}
1428
1430{
1431 HRESULT hr = S_OK;
1432 BOOL bSuccess;
1433
1434 TRACE("(%p)->(hwnd=%p flags=%x)\n", this, hwnd, fFlags);
1435
1436 /* FIXME: use IResolveShellLink interface? */
1437
1438 // FIXME: See InvokeCommand().
1439
1440#if (NTDDI_VERSION < NTDDI_LONGHORN)
1441 // NOTE: For Logo3 (EXP_LOGO3_ID_SIG), check also for SHRestricted(REST_NOLOGO3CHANNELNOTIFY)
1443 {
1444 FIXME("Logo3 links are not supported yet!\n");
1445 return E_FAIL;
1446 }
1447#endif
1448
1449 /* Resolve Darwin (MSI) target */
1451 {
1452 LPWSTR component = NULL;
1453 hr = GetAdvertiseInfo(&component, EXP_DARWIN_ID_SIG);
1454 if (FAILED(hr))
1455 return E_FAIL;
1456
1457 /* Clear the cached path */
1460 if (!m_sPath)
1461 return E_FAIL;
1462 }
1463
1464 if (!m_sPath && m_pPidl)
1465 {
1467
1469 if (bSuccess && *buffer)
1470 {
1472 if (!m_sPath)
1473 return E_OUTOFMEMORY;
1474
1475 m_bDirty = TRUE;
1476 }
1477 else
1478 {
1479 hr = S_OK; /* don't report an error occurred while just caching information */
1480 }
1481 }
1482
1483 // FIXME: Strange to do that here...
1484 if (!m_sIcoPath && m_sPath)
1485 {
1487 if (!m_sIcoPath)
1488 return E_OUTOFMEMORY;
1489
1490 m_Header.nIconIndex = 0;
1491
1492 m_bDirty = TRUE;
1493 }
1494
1495 return hr;
1496}
1497
1499{
1500 TRACE("(%p)->(path=%s)\n", this, pszFile);
1501
1502 if (!pszFile)
1503 return E_INVALIDARG;
1504
1505 LPWSTR str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
1506 if (!str)
1507 return E_OUTOFMEMORY;
1508
1509 HRESULT hr = SetPath(str);
1511
1512 return hr;
1513}
1514
1516{
1518
1519 TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
1520 this, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(m_sPath));
1521
1522 if (cchMaxPath)
1523 *pszFile = 0;
1524 // FIXME: What if cchMaxPath == 0 , or pszFile == NULL ??
1525
1526 // FIXME: What about Darwin??
1527
1528 /*
1529 * Retrieve the path to the target from the PIDL (if we have one).
1530 * NOTE: Do NOT use the cached path (m_sPath from link info).
1531 */
1533 {
1534 if (fFlags & SLGP_SHORTPATH)
1536 // FIXME: Add support for SLGP_UNCPRIORITY
1537 }
1538 else
1539 {
1540 *buffer = 0;
1541 }
1542
1543 /* If we have a FindData structure, initialize it */
1544 if (pfd)
1545 {
1546 ZeroMemory(pfd, sizeof(*pfd));
1547
1548 /* Copy the file data if the target is a file path */
1549 if (*buffer)
1550 {
1551 pfd->dwFileAttributes = m_Header.dwFileAttributes;
1552 pfd->ftCreationTime = m_Header.ftCreationTime;
1553 pfd->ftLastAccessTime = m_Header.ftLastAccessTime;
1554 pfd->ftLastWriteTime = m_Header.ftLastWriteTime;
1555 pfd->nFileSizeHigh = 0;
1556 pfd->nFileSizeLow = m_Header.nFileSizeLow;
1557
1558 /*
1559 * Build temporarily a short path in pfd->cFileName (of size MAX_PATH),
1560 * then extract and store the short file name in pfd->cAlternateFileName.
1561 */
1562 GetShortPathNameW(buffer, pfd->cFileName, _countof(pfd->cFileName));
1563 lstrcpynW(pfd->cAlternateFileName,
1564 PathFindFileNameW(pfd->cFileName),
1565 _countof(pfd->cAlternateFileName));
1566
1567 /* Now extract and store the long file name in pfd->cFileName */
1568 lstrcpynW(pfd->cFileName,
1570 _countof(pfd->cFileName));
1571 }
1572 }
1573
1574 /* Finally check if we have a raw path the user actually wants to retrieve */
1575 if ((fFlags & SLGP_RAWPATH) && (m_Header.dwFlags & SLDF_HAS_EXP_SZ))
1576 {
1577 /* Search for a target environment block */
1578 LPEXP_SZ_LINK pInfo;
1580 if (pInfo && (pInfo->cbSize == sizeof(*pInfo)))
1581 lstrcpynW(buffer, pInfo->szwTarget, cchMaxPath);
1582 }
1583
1584 /* For diagnostics purposes only... */
1585 // NOTE: SLGP_UNCPRIORITY is unsupported
1586 fFlags &= ~(SLGP_RAWPATH | SLGP_SHORTPATH);
1587 if (fFlags) FIXME("(%p): Unsupported flags %lu\n", this, fFlags);
1588
1589 /* Copy the data back to the user */
1590 if (*buffer)
1591 lstrcpynW(pszFile, buffer, cchMaxPath);
1592
1593 return (*buffer ? S_OK : S_FALSE);
1594}
1595
1597{
1598 TRACE("(%p)->(%p len=%u)\n", this, pszName, cchMaxName);
1599
1600 *pszName = 0;
1601 if (m_sDescription)
1602 lstrcpynW(pszName, m_sDescription, cchMaxName);
1603
1604 return S_OK;
1605}
1606
1608{
1609 TRACE("(%p)->(desc=%s)\n", this, debugstr_w(pszName));
1610
1613
1614 if (pszName)
1615 {
1616 m_sDescription = strdupW(pszName);
1617 if (!m_sDescription)
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, pszDir, cchMaxPath);
1628
1629 if (cchMaxPath)
1630 *pszDir = 0;
1631
1632 if (m_sWorkDir)
1633 lstrcpynW(pszDir, m_sWorkDir, cchMaxPath);
1634
1635 return S_OK;
1636}
1637
1639{
1640 TRACE("(%p)->(dir=%s)\n", this, debugstr_w(pszDir));
1641
1643 m_sWorkDir = NULL;
1644
1645 if (pszDir)
1646 {
1648 if (!m_sWorkDir)
1649 return E_OUTOFMEMORY;
1650 }
1651 m_bDirty = TRUE;
1652
1653 return S_OK;
1654}
1655
1657{
1658 TRACE("(%p)->(%p len=%u)\n", this, pszArgs, cchMaxPath);
1659
1660 if (cchMaxPath)
1661 *pszArgs = 0;
1662
1663 if (m_sArgs)
1664 lstrcpynW(pszArgs, m_sArgs, cchMaxPath);
1665
1666 return S_OK;
1667}
1668
1670{
1671 TRACE("(%p)->(args=%s)\n", this, debugstr_w(pszArgs));
1672
1674 m_sArgs = NULL;
1675
1676 if (pszArgs)
1677 {
1678 m_sArgs = strdupW(pszArgs);
1679 if (!m_sArgs)
1680 return E_OUTOFMEMORY;
1681 }
1682 m_bDirty = TRUE;
1683
1684 return S_OK;
1685}
1686
1688{
1689 TRACE("(%p)->(%p len=%u iicon=%p)\n", this, pszIconPath, cchIconPath, piIcon);
1690
1691 if (cchIconPath)
1692 *pszIconPath = 0;
1693
1694 *piIcon = 0;
1695
1696 /* Update the original icon path location */
1698 {
1700
1701 /* Search for an icon environment block */
1702 LPEXP_SZ_LINK pInfo;
1704 if (pInfo && (pInfo->cbSize == sizeof(*pInfo)))
1705 {
1707
1708 m_Header.dwFlags &= ~SLDF_HAS_ICONLOCATION;
1710
1712 if (!m_sIcoPath)
1713 return E_OUTOFMEMORY;
1714
1716
1717 m_bDirty = TRUE;
1718 }
1719 }
1720
1721 *piIcon = m_Header.nIconIndex;
1722
1723 if (m_sIcoPath)
1724 lstrcpynW(pszIconPath, m_sIcoPath, cchIconPath);
1725
1726 return S_OK;
1727}
1728
1730 UINT uFlags, PWSTR pszIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
1731{
1735 return hr;
1736 hr = pei->GetIconLocation(uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1738 return hr;
1739
1740 return S_OK;
1741}
1742
1744{
1745 HRESULT hr;
1746
1747 pszIconFile[0] = UNICODE_NULL;
1748
1749 /*
1750 * It is possible for a shell link to point to another shell link,
1751 * and in particular there is the possibility to point to itself.
1752 * Now, suppose we ask such a link to retrieve its associated icon.
1753 * This function would be called, and due to COM would be called again
1754 * recursively. To solve this issue, we forbid calling GetIconLocation()
1755 * with GIL_FORSHORTCUT set in uFlags, as done by Windows (shown by tests).
1756 */
1757 if (uFlags & GIL_FORSHORTCUT)
1758 return E_INVALIDARG;
1759
1760 /*
1761 * Now, we set GIL_FORSHORTCUT so that: i) we allow the icon extractor
1762 * of the target to give us a suited icon, and ii) we protect ourselves
1763 * against recursive call.
1764 */
1765 uFlags |= GIL_FORSHORTCUT;
1766
1767 if (uFlags & GIL_DEFAULTICON)
1768 return S_FALSE;
1769
1770 hr = GetIconLocation(pszIconFile, cchMax, piIndex);
1771 if (FAILED(hr) || pszIconFile[0] == UNICODE_NULL)
1772 {
1773 hr = SHELL_PidlGetIconLocationW(m_pPidl, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1774 }
1775 else
1776 {
1777 *pwFlags = GIL_NOTFILENAME | GIL_PERCLASS;
1778 }
1779
1780 return hr;
1781}
1782
1784CShellLink::Extract(PCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
1785{
1786 HRESULT hr = NOERROR;
1787 UINT cxyLarge = LOWORD(nIconSize), cxySmall = HIWORD(nIconSize);
1788
1789 if (phiconLarge)
1790 {
1791 *phiconLarge = NULL;
1792 PrivateExtractIconsW(pszFile, nIconIndex, cxyLarge, cxyLarge, phiconLarge, NULL, 1, 0);
1793
1794 if (*phiconLarge == NULL)
1795 hr = S_FALSE;
1796 }
1797
1798 if (phiconSmall)
1799 {
1800 *phiconSmall = NULL;
1801 PrivateExtractIconsW(pszFile, nIconIndex, cxySmall, cxySmall, phiconSmall, NULL, 1, 0);
1802
1803 if (*phiconSmall == NULL)
1804 hr = S_FALSE;
1805 }
1806
1807 if (hr == S_FALSE)
1808 {
1809 if (phiconLarge && *phiconLarge)
1810 {
1811 DestroyIcon(*phiconLarge);
1812 *phiconLarge = NULL;
1813 }
1814 if (phiconSmall && *phiconSmall)
1815 {
1816 DestroyIcon(*phiconSmall);
1817 *phiconSmall = NULL;
1818 }
1819 }
1820
1821 return hr;
1822}
1823
1824#if 0
1825/* Extends the functionality of PathUnExpandEnvStringsW */
1826BOOL PathFullyUnExpandEnvStringsW(
1827 _In_ LPCWSTR pszPath,
1828 _Out_ LPWSTR pszBuf,
1829 _In_ UINT cchBuf)
1830{
1831 BOOL Ret = FALSE; // Set to TRUE as soon as PathUnExpandEnvStrings starts unexpanding.
1832 BOOL res;
1833 LPCWSTR p;
1834
1835 // *pszBuf = L'\0';
1836 while (*pszPath && cchBuf > 0)
1837 {
1838 /* Attempt unexpanding the path */
1839 res = PathUnExpandEnvStringsW(pszPath, pszBuf, cchBuf);
1840 if (!res)
1841 {
1842 /* The unexpansion failed. Try to find a path delimiter. */
1843 p = wcspbrk(pszPath, L" /\\:*?\"<>|%");
1844 if (!p) /* None found, we will copy the remaining path */
1845 p = pszPath + wcslen(pszPath);
1846 else /* Found one, we will copy the delimiter and skip it */
1847 ++p;
1848 /* If we overflow, we cannot unexpand more, so return FALSE */
1849 if (p - pszPath >= cchBuf)
1850 return FALSE; // *pszBuf = L'\0';
1851
1852 /* Copy the untouched portion of path up to the delimiter, included */
1853 wcsncpy(pszBuf, pszPath, p - pszPath);
1854 pszBuf[p - pszPath] = L'\0'; // NULL-terminate
1855
1856 /* Advance the pointers and decrease the remaining buffer size */
1857 cchBuf -= (p - pszPath);
1858 pszBuf += (p - pszPath);
1859 pszPath += (p - pszPath);
1860 }
1861 else
1862 {
1863 /*
1864 * The unexpansion succeeded. Skip the unexpanded part by trying
1865 * to find where the original path and the unexpanded string
1866 * become different.
1867 * NOTE: An alternative(?) would be to stop also at the last
1868 * path delimiter encountered in the loop (i.e. would be the
1869 * first path delimiter in the strings).
1870 */
1871 LPWSTR q;
1872
1873 /*
1874 * The algorithm starts at the end of the strings and loops back
1875 * while the characters are equal, until it finds a discrepancy.
1876 */
1877 p = pszPath + wcslen(pszPath);
1878 q = pszBuf + wcslen(pszBuf); // This wcslen should be < cchBuf
1879 while ((*p == *q) && (p > pszPath) && (q > pszBuf))
1880 {
1881 --p; --q;
1882 }
1883 /* Skip discrepancy */
1884 ++p; ++q;
1885
1886 /* Advance the pointers and decrease the remaining buffer size */
1887 cchBuf -= (q - pszBuf);
1888 pszBuf = q;
1889 pszPath = p;
1890
1891 Ret = TRUE;
1892 }
1893 }
1894
1895 return Ret;
1896}
1897#endif
1898
1900{
1901 HRESULT hr = E_FAIL;
1902 WCHAR szIconPath[MAX_PATH];
1903
1904 TRACE("(%p)->(path=%s iicon=%u)\n", this, debugstr_w(pszIconPath), iIcon);
1905
1906 if (pszIconPath)
1907 {
1908 /*
1909 * Check whether the user-given file path contains unexpanded
1910 * environment variables. If so, create a target environment block.
1911 * Note that in this block we will store the user-given path.
1912 * It will contain the unexpanded environment variables, but
1913 * it can also contain already expanded path that the user does
1914 * not want to see them unexpanded (e.g. so that they always
1915 * refer to the same place even if the would-be corresponding
1916 * environment variable could change).
1917 */
1918#ifdef ICON_LINK_WINDOWS_COMPAT
1919 /* Try to fully unexpand the icon path */
1920 // if (PathFullyUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath)))
1921 BOOL bSuccess = PathUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath));
1922 if (bSuccess && wcscmp(pszIconPath, szIconPath) != 0)
1923#else
1924 /*
1925 * In some situations, described in http://stackoverflow.com/questions/2976489/ishelllinkseticonlocation-translates-my-icon-path-into-program-files-which-i
1926 * the result of PathUnExpandEnvStringsW() could be wrong, and instead
1927 * one would have to store the actual provided icon location path, while
1928 * creating an icon environment block ONLY if that path already contains
1929 * environment variables. This is what the present case is trying to implement.
1930 */
1931 SHExpandEnvironmentStringsW(pszIconPath, szIconPath, _countof(szIconPath));
1932 if (wcscmp(pszIconPath, szIconPath) != 0)
1933#endif
1934 {
1935 /*
1936 * The user-given file path contains unexpanded environment
1937 * variables, so we need an icon environment block.
1938 */
1940 LPEXP_SZ_LINK pInfo;
1941
1942#ifdef ICON_LINK_WINDOWS_COMPAT
1943 /* Make pszIconPath point to the unexpanded path */
1944 LPCWSTR pszOrgIconPath = pszIconPath;
1945 pszIconPath = szIconPath;
1946#endif
1948 if (pInfo)
1949 {
1950 /* Make sure that the size of the structure is valid */
1951 if (pInfo->cbSize != sizeof(*pInfo))
1952 {
1953 ERR("Ooops. This structure is not as expected...\n");
1954
1955 /* Invalid structure, remove it altogether */
1956 m_Header.dwFlags &= ~SLDF_HAS_EXP_ICON_SZ;
1958
1959 /* Reset the pointer and go use the static buffer */
1960 pInfo = NULL;
1961 }
1962 }
1963 if (!pInfo)
1964 {
1965 /* Use the static buffer */
1966 pInfo = &buffer;
1967 buffer.cbSize = sizeof(buffer);
1968 buffer.dwSignature = EXP_SZ_ICON_SIG;
1969 }
1970
1971 lstrcpynW(pInfo->szwTarget, pszIconPath, _countof(pInfo->szwTarget));
1972 WideCharToMultiByte(CP_ACP, 0, pszIconPath, -1,
1973 pInfo->szTarget, _countof(pInfo->szTarget), NULL, NULL);
1974
1975 hr = S_OK;
1976 if (pInfo == &buffer)
1977 hr = AddDataBlock(pInfo);
1978 if (hr == S_OK)
1980
1981#ifdef ICON_LINK_WINDOWS_COMPAT
1982 /* Set pszIconPath back to the original one */
1983 pszIconPath = pszOrgIconPath;
1984#else
1985 /* Now, make pszIconPath point to the expanded path */
1986 pszIconPath = szIconPath;
1987#endif
1988 }
1989 else
1990 {
1991 /*
1992 * The user-given file path does not contain unexpanded environment
1993 * variables, so we need to remove any icon environment block.
1994 */
1995 m_Header.dwFlags &= ~SLDF_HAS_EXP_ICON_SZ;
1997
1998 /* pszIconPath points to the user path */
1999 }
2000 }
2001
2002#ifdef ICON_LINK_WINDOWS_COMPAT
2003 /* Store the original icon path location (may contain unexpanded environment strings) */
2004#endif
2005 if (pszIconPath)
2006 {
2007 m_Header.dwFlags &= ~SLDF_HAS_ICONLOCATION;
2009
2010 m_sIcoPath = strdupW(pszIconPath);
2011 if (!m_sIcoPath)
2012 return E_OUTOFMEMORY;
2013
2015 }
2016
2017 hr = S_OK;
2018
2019 m_Header.nIconIndex = iIcon;
2020 m_bDirty = TRUE;
2021
2022 return hr;
2023}
2024
2026{
2027 TRACE("(%p)->(path=%s %x)\n", this, debugstr_w(pszPathRel), dwReserved);
2028
2030 m_sPathRel = NULL;
2031
2032 if (pszPathRel)
2033 {
2034 m_sPathRel = strdupW(pszPathRel);
2035 if (!m_sPathRel)
2036 return E_OUTOFMEMORY;
2037 }
2038 m_bDirty = TRUE;
2039
2041}
2042
2044{
2045 if (!str)
2046 return NULL;
2047
2048 LPCWSTR p = wcschr(str, L':');
2049 if (!p)
2050 return NULL;
2051
2052 DWORD len = p - str;
2053 LPWSTR ret = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (len + 1));
2054 if (!ret)
2055 return ret;
2056
2057 memcpy(ret, str, sizeof(WCHAR)*len);
2058 ret[len] = 0;
2059 return ret;
2060}
2061
2063{
2065 LPEXP_DARWIN_LINK pInfo;
2066
2067 if ( (dwSig != EXP_DARWIN_ID_SIG)
2069 && (dwSig != EXP_LOGO3_ID_SIG)
2070#endif
2071 )
2072 {
2073 return E_INVALIDARG;
2074 }
2075
2076 if (!string)
2077 return S_FALSE;
2078
2080 if (pInfo)
2081 {
2082 /* Make sure that the size of the structure is valid */
2083 if (pInfo->dbh.cbSize != sizeof(*pInfo))
2084 {
2085 ERR("Ooops. This structure is not as expected...\n");
2086
2087 /* Invalid structure, remove it altogether */
2088 if (dwSig == EXP_DARWIN_ID_SIG)
2089 m_Header.dwFlags &= ~SLDF_HAS_DARWINID;
2090#if (NTDDI_VERSION < NTDDI_LONGHORN)
2091 else if (dwSig == EXP_LOGO3_ID_SIG)
2092 m_Header.dwFlags &= ~SLDF_HAS_LOGO3ID;
2093#endif
2094 RemoveDataBlock(dwSig);
2095
2096 /* Reset the pointer and go use the static buffer */
2097 pInfo = NULL;
2098 }
2099 }
2100 if (!pInfo)
2101 {
2102 /* Use the static buffer */
2103 pInfo = &buffer;
2104 buffer.dbh.cbSize = sizeof(buffer);
2105 buffer.dbh.dwSignature = dwSig;
2106 }
2107
2108 lstrcpynW(pInfo->szwDarwinID, string, _countof(pInfo->szwDarwinID));
2109 WideCharToMultiByte(CP_ACP, 0, string, -1,
2110 pInfo->szDarwinID, _countof(pInfo->szDarwinID), NULL, NULL);
2111
2112 HRESULT hr = S_OK;
2113 if (pInfo == &buffer)
2114 hr = AddDataBlock(pInfo);
2115 if (hr == S_OK)
2116 {
2117 if (dwSig == EXP_DARWIN_ID_SIG)
2119#if (NTDDI_VERSION < NTDDI_LONGHORN)
2120 else if (dwSig == EXP_LOGO3_ID_SIG)
2122#endif
2123 }
2124
2125 return hr;
2126}
2127
2129{
2130 HRESULT hr;
2131 LPCWSTR szComponent = NULL, szProduct = NULL, p;
2132 INT len;
2133 GUID guid;
2134 WCHAR szGuid[38+1];
2135
2137
2138 while (str[0])
2139 {
2140 /* each segment must start with two colons */
2141 if (str[0] != ':' || str[1] != ':')
2142 return E_FAIL;
2143
2144 /* the last segment is just two colons */
2145 if (!str[2])
2146 break;
2147 str += 2;
2148
2149 /* there must be a colon straight after a guid */
2150 p = wcschr(str, L':');
2151 if (!p)
2152 return E_FAIL;
2153 len = p - str;
2154 if (len != 38)
2155 return E_FAIL;
2156
2157 /* get the guid, and check if it's validly formatted */
2158 memcpy(szGuid, str, sizeof(WCHAR)*len);
2159 szGuid[len] = 0;
2160
2162 if (hr != S_OK)
2163 return hr;
2164 str = p + 1;
2165
2166 /* match it up to a guid that we care about */
2167 if (IsEqualGUID(guid, SHELL32_AdvtShortcutComponent) && !szComponent)
2168 szComponent = str; /* Darwin */
2169 else if (IsEqualGUID(guid, SHELL32_AdvtShortcutProduct) && !szProduct)
2170 szProduct = str; /* Logo3 */
2171 else
2172 return E_FAIL;
2173
2174 /* skip to the next field */
2175 str = wcschr(str, L':');
2176 if (!str)
2177 return E_FAIL;
2178 }
2179
2180 /* we have to have a component for an advertised shortcut */
2181 if (!szComponent)
2182 return E_FAIL;
2183
2184 szComponent = GetAdvertisedArg(szComponent);
2185 szProduct = GetAdvertisedArg(szProduct);
2186
2187 hr = WriteAdvertiseInfo(szComponent, EXP_DARWIN_ID_SIG);
2188 // if (FAILED(hr))
2189 // return hr;
2190#if (NTDDI_VERSION < NTDDI_LONGHORN)
2191 hr = WriteAdvertiseInfo(szProduct, EXP_LOGO3_ID_SIG);
2192 // if (FAILED(hr))
2193 // return hr;
2194#endif
2195
2196 HeapFree(GetProcessHeap(), 0, (PVOID)szComponent);
2197 HeapFree(GetProcessHeap(), 0, (PVOID)szProduct);
2198
2199 if (TRACE_ON(shell))
2200 {
2202 TRACE("Component = %s\n", debugstr_w(sComponent));
2203#if (NTDDI_VERSION < NTDDI_LONGHORN)
2204 GetAdvertiseInfo(&sProduct, EXP_LOGO3_ID_SIG);
2205 TRACE("Product = %s\n", debugstr_w(sProduct));
2206#endif
2207 }
2208
2209 return S_OK;
2210}
2211
2213{
2214 HRESULT hr = S_OK;
2215 LPITEMIDLIST pidlNew = NULL;
2217
2218 /*
2219 * Not both 'pidl' and 'pszFile' should be set.
2220 * But either one or both can be NULL.
2221 */
2222 if (pidl && pszFile)
2223 return E_FAIL;
2224
2225 if (pidl)
2226 {
2227 /* Clone the PIDL */
2228 pidlNew = ILClone(pidl);
2229 if (!pidlNew)
2230 return E_FAIL;
2231 }
2232 else if (pszFile)
2233 {
2234 /* Build a PIDL for this path target */
2235 hr = SHILCreateFromPathW(pszFile, &pidlNew, NULL);
2236 if (FAILED(hr))
2237 {
2238 /* This failed, try to resolve the path, then create a simple PIDL */
2239
2242
2244 {
2245 hr = E_INVALIDARG;
2246 szPath[0] = 0;
2247 }
2248 else
2249 {
2250 hr = S_OK;
2252 // NOTE: Don't make it failed here even if pidlNew was NULL.
2253 // We don't fail on purpose even if SHSimpleIDListFromPathW returns NULL.
2254 // This behaviour has been verified with tests.
2255 }
2256 }
2257 }
2258 // else if (!pidl && !pszFile) { pidlNew = NULL; hr = S_OK; }
2259
2260 ILFree(m_pPidl);
2261 m_pPidl = pidlNew;
2262
2263 if (!pszFile)
2264 {
2265 if (SHGetPathFromIDListW(pidlNew, szPath))
2266 pszFile = szPath;
2267 }
2268
2269 // TODO: Fully update link info, tracker, file attribs...
2270
2271 // if (pszFile)
2272 if (!pszFile)
2273 {
2274 *szPath = L'\0';
2275 pszFile = szPath;
2276 }
2277
2278 /* Update the cached path (for link info) */
2280
2281 if (m_sPath)
2283
2284 m_sPath = strdupW(pszFile);
2285 if (!m_sPath)
2286 return E_OUTOFMEMORY;
2287
2288 m_bDirty = TRUE;
2289 return hr;
2290}
2291
2293{
2294 LPWSTR unquoted = NULL;
2295 HRESULT hr = S_OK;
2296
2297 TRACE("(%p)->(path=%s)\n", this, debugstr_w(pszFile));
2298
2299 if (!pszFile)
2300 return E_INVALIDARG;
2301
2302 /*
2303 * Allow upgrading Logo3 shortcuts (m_Header.dwFlags & SLDF_HAS_LOGO3ID),
2304 * but forbid upgrading Darwin ones.
2305 */
2307 return S_FALSE;
2308
2309 /* quotes at the ends of the string are stripped */
2310 SIZE_T len = wcslen(pszFile);
2311 if (pszFile[0] == L'"' && pszFile[len-1] == L'"')
2312 {
2313 unquoted = strdupW(pszFile);
2314 PathUnquoteSpacesW(unquoted);
2315 pszFile = unquoted;
2316 }
2317
2318 /* any other quote marks are invalid */
2319 if (wcschr(pszFile, L'"'))
2320 {
2321 hr = S_FALSE;
2322 goto end;
2323 }
2324
2325 /* Clear the cached path */
2327 m_sPath = NULL;
2328
2329 /* Check for an advertised target (Logo3 or Darwin) */
2330 if (SetAdvertiseInfo(pszFile) != S_OK)
2331 {
2332 /* This is not an advertised target, but a regular path */
2334
2335 /*
2336 * Check whether the user-given file path contains unexpanded
2337 * environment variables. If so, create a target environment block.
2338 * Note that in this block we will store the user-given path.
2339 * It will contain the unexpanded environment variables, but
2340 * it can also contain already expanded path that the user does
2341 * not want to see them unexpanded (e.g. so that they always
2342 * refer to the same place even if the would-be corresponding
2343 * environment variable could change).
2344 */
2345 if (*pszFile)
2347 else
2348 *szPath = L'\0';
2349
2350 if (*pszFile && (wcscmp(pszFile, szPath) != 0))
2351 {
2352 /*
2353 * The user-given file path contains unexpanded environment
2354 * variables, so we need a target environment block.
2355 */
2357 LPEXP_SZ_LINK pInfo;
2358
2360 if (pInfo)
2361 {
2362 /* Make sure that the size of the structure is valid */
2363 if (pInfo->cbSize != sizeof(*pInfo))
2364 {
2365 ERR("Ooops. This structure is not as expected...\n");
2366
2367 /* Invalid structure, remove it altogether */
2368 m_Header.dwFlags &= ~SLDF_HAS_EXP_SZ;
2370
2371 /* Reset the pointer and go use the static buffer */
2372 pInfo = NULL;
2373 }
2374 }
2375 if (!pInfo)
2376 {
2377 /* Use the static buffer */
2378 pInfo = &buffer;
2379 buffer.cbSize = sizeof(buffer);
2380 buffer.dwSignature = EXP_SZ_LINK_SIG;
2381 }
2382
2383 lstrcpynW(pInfo->szwTarget, pszFile, _countof(pInfo->szwTarget));
2384 WideCharToMultiByte(CP_ACP, 0, pszFile, -1,
2385 pInfo->szTarget, _countof(pInfo->szTarget), NULL, NULL);
2386
2387 hr = S_OK;
2388 if (pInfo == &buffer)
2389 hr = AddDataBlock(pInfo);
2390 if (hr == S_OK)
2392
2393 /* Now, make pszFile point to the expanded path */
2394 pszFile = szPath;
2395 }
2396 else
2397 {
2398 /*
2399 * The user-given file path does not contain unexpanded environment
2400 * variables, so we need to remove any target environment block.
2401 */
2402 m_Header.dwFlags &= ~SLDF_HAS_EXP_SZ;
2404
2405 /* pszFile points to the user path */
2406 }
2407
2408 /* Set the target */
2409 hr = SetTargetFromPIDLOrPath(NULL, pszFile);
2410 }
2411
2412 m_bDirty = TRUE;
2413
2414end:
2415 HeapFree(GetProcessHeap(), 0, unquoted);
2416 return hr;
2417}
2418
2420{
2421 if (SHAddDataBlock(&m_pDBList, (DATABLOCK_HEADER*)pDataBlock))
2422 {
2423 m_bDirty = TRUE;
2424 return S_OK;
2425 }
2426 return S_FALSE;
2427}
2428
2430{
2431 DATABLOCK_HEADER* pBlock;
2432 PVOID pDataBlock;
2433
2434 TRACE("%p %08x %p\n", this, dwSig, ppDataBlock);
2435
2436 *ppDataBlock = NULL;
2437
2438 pBlock = SHFindDataBlock(m_pDBList, dwSig);
2439 if (!pBlock)
2440 {
2441 ERR("unknown datablock %08x (not found)\n", dwSig);
2442 return E_FAIL;
2443 }
2444
2445 pDataBlock = LocalAlloc(LMEM_ZEROINIT, pBlock->cbSize);
2446 if (!pDataBlock)
2447 return E_OUTOFMEMORY;
2448
2449 CopyMemory(pDataBlock, pBlock, pBlock->cbSize);
2450
2451 *ppDataBlock = pDataBlock;
2452 return S_OK;
2453}
2454
2456{
2457 if (SHRemoveDataBlock(&m_pDBList, dwSig))
2458 {
2459 m_bDirty = TRUE;
2460 return S_OK;
2461 }
2462 return S_FALSE;
2463}
2464
2466{
2467 TRACE("%p %p\n", this, pdwFlags);
2468 *pdwFlags = m_Header.dwFlags;
2469 return S_OK;
2470}
2471
2473{
2474#if 0 // FIXME!
2476 m_bDirty = TRUE;
2477 return S_OK;
2478#else
2479 FIXME("\n");
2480 return E_NOTIMPL;
2481#endif
2482}
2483
2484/**************************************************************************
2485 * CShellLink implementation of IShellExtInit::Initialize()
2486 *
2487 * Loads the shelllink from the dataobject the shell is pointing to.
2488 */
2490{
2491 TRACE("%p %p %p %p\n", this, pidlFolder, pdtobj, hkeyProgID);
2492
2493 if (!pdtobj)
2494 return E_FAIL;
2495
2496 FORMATETC format;
2497 format.cfFormat = CF_HDROP;
2498 format.ptd = NULL;
2499 format.dwAspect = DVASPECT_CONTENT;
2500 format.lindex = -1;
2501 format.tymed = TYMED_HGLOBAL;
2502
2503 STGMEDIUM stgm;
2504 HRESULT hr = pdtobj->GetData(&format, &stgm);
2505 if (FAILED(hr))
2506 return hr;
2507
2508 UINT count = DragQueryFileW((HDROP)stgm.hGlobal, -1, NULL, 0);
2509 if (count == 1)
2510 {
2511 count = DragQueryFileW((HDROP)stgm.hGlobal, 0, NULL, 0);
2512 count++;
2513 LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
2514 if (path)
2515 {
2516 count = DragQueryFileW((HDROP)stgm.hGlobal, 0, path, count);
2517 hr = Load(path, 0);
2519 }
2520 }
2521 ReleaseStgMedium(&stgm);
2522
2523 return S_OK;
2524}
2525
2527{
2528 INT id = 0;
2529
2530 m_idCmdFirst = idCmdFirst;
2531
2532 TRACE("%p %p %u %u %u %u\n", this,
2533 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
2534
2535 if (!hMenu)
2536 return E_INVALIDARG;
2537
2540
2541 MENUITEMINFOW mii;
2542 ZeroMemory(&mii, sizeof(mii));
2543 mii.cbSize = sizeof(mii);
2545 mii.dwTypeData = strOpen.GetBuffer();
2546 mii.cch = wcslen(mii.dwTypeData);
2547 mii.wID = idCmdFirst + id++;
2549 mii.fType = MFT_STRING;
2550 if (!InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii))
2551 return E_FAIL;
2552
2554 mii.dwTypeData = strOpenFileLoc.GetBuffer();
2555 mii.cch = wcslen(mii.dwTypeData);
2556 mii.wID = idCmdFirst + id++;
2557 mii.fState = MFS_ENABLED;
2558 mii.fType = MFT_STRING;
2559 if (!InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii))
2560 return E_FAIL;
2561
2562 UNREFERENCED_PARAMETER(indexMenu);
2563
2564 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, id);
2565}
2566
2568{
2569 WCHAR szParams[MAX_PATH + 64];
2570 StringCbPrintfW(szParams, sizeof(szParams), L"/select,%s", m_sPath);
2571
2572 INT_PTR ret;
2573 ret = reinterpret_cast<INT_PTR>(ShellExecuteW(NULL, NULL, L"explorer.exe", szParams,
2575 if (ret <= 32)
2576 {
2577 ERR("ret: %08lX\n", ret);
2578 return E_FAIL;
2579 }
2580
2581 return S_OK;
2582}
2583
2585{
2586 TRACE("%p %p\n", this, lpici);
2587
2588 if (lpici->cbSize < sizeof(CMINVOKECOMMANDINFO))
2589 return E_INVALIDARG;
2590
2591 // NOTE: We could use lpici->hwnd (certainly in case lpici->fMask doesn't contain CMIC_MASK_FLAG_NO_UI)
2592 // as the parent window handle... ?
2593 /* FIXME: get using interface set from IObjectWithSite?? */
2594 // NOTE: We might need an extended version of Resolve that provides us with paths...
2595 HRESULT hr = Resolve(lpici->hwnd, (lpici->fMask & CMIC_MASK_FLAG_NO_UI) ? SLR_NO_UI : 0);
2596 if (FAILED(hr))
2597 {
2598 TRACE("failed to resolve component error 0x%08x\n", hr);
2599 return hr;
2600 }
2601
2602 UINT idCmd = LOWORD(lpici->lpVerb);
2603 TRACE("idCmd: %d\n", idCmd);
2604
2605 switch (idCmd)
2606 {
2607 case IDCMD_OPEN:
2608 return DoOpen(lpici);
2610 return DoOpenFileLocation();
2611 default:
2612 return E_NOTIMPL;
2613 }
2614}
2615
2617{
2619 const BOOL unicode = IsUnicode(*lpici);
2620
2621 CStringW args;
2622 if (m_sArgs)
2623 args = m_sArgs;
2624
2625 if (unicode)
2626 {
2627 if (!StrIsNullOrEmpty(iciex->lpParametersW))
2628 {
2629 args += L' ';
2630 args += iciex->lpParametersW;
2631 }
2632 }
2633 else
2634 {
2635 CComHeapPtr<WCHAR> pszParams;
2636 if (!StrIsNullOrEmpty(lpici->lpParameters) && __SHCloneStrAtoW(&pszParams, lpici->lpParameters))
2637 {
2638 args += L' ';
2639 args += pszParams;
2640 }
2641 }
2642
2644 SHELLEXECUTEINFOW sei = { sizeof(sei) };
2647 sei.lpDirectory = m_sWorkDir;
2648 if (m_pPidl)
2649 {
2650 sei.lpIDList = m_pPidl;
2652 }
2653 else
2654 {
2655 sei.lpFile = m_sPath;
2657 {
2658 sei.fMask &= ~SEE_MASK_DOENVSUBST; // The link does not want to expand lpFile
2660 sei.lpDirectory = dir;
2661 }
2662 }
2663 sei.lpParameters = args;
2664 sei.lpClass = m_sLinkPath;
2666 if (lpici->nShow != SW_SHOWNORMAL && lpici->nShow != SW_SHOW)
2667 sei.nShow = lpici->nShow; // Allow invoker to override .lnk show mode
2668
2669 // Use the invoker specified working directory if the link did not specify one
2670 if (StrIsNullOrEmpty(sei.lpDirectory) || !PathIsDirectoryW(sei.lpDirectory))
2671 {
2672 LPCSTR pszDirA = lpici->lpDirectory;
2673 if (unicode && !StrIsNullOrEmpty(iciex->lpDirectoryW))
2674 sei.lpDirectory = iciex->lpDirectoryW;
2675 else if (pszDirA && SHAnsiToUnicode(pszDirA, dir, _countof(dir)))
2676 sei.lpDirectory = dir;
2677 }
2678 return (ShellExecuteExW(&sei) ? S_OK : E_FAIL);
2679}
2680
2682{
2683 FIXME("%p %lu %u %p %p %u\n", this, idCmd, uType, pwReserved, pszName, cchMax);
2684 return E_NOTIMPL;
2685}
2686
2689{
2690 switch(uMsg)
2691 {
2692 case WM_INITDIALOG:
2693 if (lParam)
2694 {
2695 HWND hDlgCtrl = GetDlgItem(hwndDlg, IDC_SHORTEX_RUN_DIFFERENT);
2696 SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0);
2697 }
2698 return TRUE;
2699 case WM_COMMAND:
2700 {
2701 HWND hDlgCtrl = GetDlgItem(hwndDlg, IDC_SHORTEX_RUN_DIFFERENT);
2702 if (LOWORD(wParam) == IDOK)
2703 {
2704 if (SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED)
2705 EndDialog(hwndDlg, 1);
2706 else
2707 EndDialog(hwndDlg, 0);
2708 }
2709 else if (LOWORD(wParam) == IDCANCEL)
2710 {
2711 EndDialog(hwndDlg, -1);
2712 }
2714 {
2715 if (SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED)
2716 SendMessage(hDlgCtrl, BM_SETCHECK, BST_UNCHECKED, 0);
2717 else
2718 SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0);
2719 }
2720 }
2721 }
2722 return FALSE;
2723}
2724
2725static void GetTypeDescriptionByPath(PCWSTR pszFullPath, DWORD fAttributes, PWSTR szBuf, UINT cchBuf)
2726{
2727 if (fAttributes == INVALID_FILE_ATTRIBUTES && !PathFileExistsAndAttributesW(pszFullPath, &fAttributes))
2728 fAttributes = 0;
2729
2730 SHFILEINFOW fi;
2731 if (!SHGetFileInfoW(pszFullPath, fAttributes, &fi, sizeof(fi), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES))
2732 {
2733 ERR("SHGetFileInfoW failed for %ls (%lu)\n", pszFullPath, GetLastError());
2734 fi.szTypeName[0] = UNICODE_NULL;
2735 }
2736
2737 BOOL fFolder = (fAttributes & FILE_ATTRIBUTE_DIRECTORY);
2738 LPCWSTR pwszExt = fFolder ? L"" : PathFindExtensionW(pszFullPath);
2739 if (pwszExt[0])
2740 {
2741 if (!fi.szTypeName[0])
2742 StringCchPrintfW(szBuf, cchBuf, L"%s", pwszExt + 1);
2743 else
2744 StringCchPrintfW(szBuf, cchBuf, L"%s (%s)", fi.szTypeName, pwszExt);
2745 }
2746 else
2747 {
2748 StringCchPrintfW(szBuf, cchBuf, L"%s", fi.szTypeName);
2749 }
2750}
2751
2753{
2754 TRACE("CShellLink::OnInitDialog(hwnd %p hwndFocus %p lParam %p)\n", hwndDlg, hwndFocus, lParam);
2755
2757
2758 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,
2760
2761 m_bInInit = TRUE;
2763
2764 /* Get file information */
2765 // FIXME! FIXME! Shouldn't we use m_sIcoPath, m_Header.nIconIndex instead???
2766 SHFILEINFOW fi;
2767 if (!SHGetFileInfoW(m_sLinkPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME | SHGFI_ICON))
2768 {
2769 ERR("SHGetFileInfoW failed for %ls (%lu)\n", m_sLinkPath, GetLastError());
2770 fi.szTypeName[0] = L'\0';
2771 fi.hIcon = NULL;
2772 }
2773
2774 if (fi.hIcon)
2775 {
2776 if (m_hIcon)
2778 m_hIcon = fi.hIcon;
2780 }
2781 else
2782 ERR("ExtractIconW failed %ls %u\n", m_sIcoPath, m_Header.nIconIndex);
2783
2784 if (!SHGetFileInfoW(m_sLinkPath, 0, &fi, sizeof(fi), SHGFI_DISPLAYNAME))
2787
2788 /* Target type */
2789 if (m_sPath)
2790 {
2794 }
2795
2796 /* Target location */
2797 if (m_sPath)
2798 {
2803 }
2804
2805 /* Target path */
2806 if (m_sPath)
2807 {
2808 WCHAR newpath[MAX_PATH * 2];
2809 newpath[0] = UNICODE_NULL;
2810 if (wcschr(m_sPath, ' '))
2811 StringCchPrintfExW(newpath, _countof(newpath), NULL, NULL, 0, L"\"%ls\"", m_sPath);
2812 else
2813 StringCchCopyExW(newpath, _countof(newpath), m_sPath, NULL, NULL, 0);
2814
2815 if (m_sArgs && m_sArgs[0])
2816 {
2817 StringCchCatW(newpath, _countof(newpath), L" ");
2818 StringCchCatW(newpath, _countof(newpath), m_sArgs);
2819 }
2820 SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, newpath);
2821 }
2822
2823 /* Working dir */
2824 if (m_sWorkDir)
2826
2827 /* Description */
2828 if (m_sDescription)
2830
2831 /* Hot key */
2833
2834 /* Run */
2836 const DWORD runshowcmd[] = { SW_SHOWNORMAL, SW_SHOWMINNOACTIVE, SW_SHOWMAXIMIZED };
2837 HWND hRunCombo = GetDlgItem(hwndDlg, IDC_SHORTCUT_RUN_COMBO);
2838 for (UINT i = 0; i < _countof(runstrings); ++i)
2839 {
2841 if (!LoadStringW(shell32_hInstance, runstrings[i], buf, _countof(buf)))
2842 break;
2843
2844 int index = SendMessageW(hRunCombo, CB_ADDSTRING, 0, (LPARAM)buf);
2845 if (index < 0)
2846 continue;
2847 SendMessageW(hRunCombo, CB_SETITEMDATA, index, runshowcmd[i]);
2848 if (!i || m_Header.nShowCommand == runshowcmd[i])
2849 SendMessageW(hRunCombo, CB_SETCURSEL, index, 0);
2850 }
2851
2852 BOOL disablecontrols = FALSE;
2853 if (darwin)
2854 {
2855 disablecontrols = TRUE;
2858 }
2859 else
2860 {
2861 WCHAR path[MAX_PATH * 2];
2862 path[0] = UNICODE_NULL;
2864 if (FAILED(hr))
2865 hr = GetPath(path, _countof(path), NULL, 0);
2866#if DBG
2867 if (GetKeyState(VK_CONTROL) < 0) // Allow inspection of PIDL parsing path
2868 {
2869 hr = S_OK;
2870 path[0] = UNICODE_NULL;
2871 }
2872#endif
2873 if (hr != S_OK)
2874 {
2875 disablecontrols = TRUE;
2876 LPITEMIDLIST pidl;
2877 if (GetIDList(&pidl) == S_OK)
2878 {
2879 path[0] = UNICODE_NULL;
2880 SHGetNameAndFlagsW(pidl, SHGDN_FORADDRESSBAR | SHGDN_FORPARSING, path, _countof(path), NULL);
2883 ILRemoveLastID(pidl);
2884 path[0] = UNICODE_NULL;
2886 SHGetNameAndFlagsW(pidl, SHGDN_NORMAL, path, _countof(path), NULL);
2888 ILFree(pidl);
2889 }
2892 }
2893 else
2894 {
2895 ASSERT(FAILED(hr) || !(path[0] == ':' && path[1] == ':' && path[2] == '{'));
2896 }
2897 }
2898
2899 HWND hWndTarget = GetDlgItem(hwndDlg, IDC_SHORTCUT_TARGET_TEXT);
2900 EnableWindow(hWndTarget, !disablecontrols);
2901 PostMessage(hWndTarget, EM_SETSEL, 0, -1); // Fix caret bug when first opening the tab
2902
2903 /* auto-completion */
2904 SHAutoComplete(hWndTarget, SHACF_DEFAULT);
2906
2907 m_bInInit = FALSE;
2908
2909 return TRUE;
2910}
2911
2912void CShellLink::OnCommand(HWND hwndDlg, int id, HWND hwndCtl, UINT codeNotify)
2913{
2914 switch (id)
2915 {
2916 case IDC_SHORTCUT_FIND:
2918 return;
2919
2921 {
2922 WCHAR wszPath[MAX_PATH] = L"";
2923
2924 if (m_sIcoPath)
2925 wcscpy(wszPath, m_sIcoPath);
2926 else
2927 FindExecutableW(m_sPath, NULL, wszPath);
2928
2930 if (PickIconDlg(hwndDlg, wszPath, _countof(wszPath), &IconIndex))
2931 {
2932 SetIconLocation(wszPath, IconIndex);
2933 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
2934
2935 HICON hIconLarge = CreateShortcutIcon(wszPath, IconIndex);
2936 if (hIconLarge)
2937 {
2938 if (m_hIcon)
2940 m_hIcon = hIconLarge;
2942 }
2943 }
2944 return;
2945 }
2946
2948 {
2950 if (result == 1 || result == 0)
2951 {
2952 if (m_bRunAs != result)
2953 {
2954 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
2955 }
2956
2957 m_bRunAs = result;
2958 }
2959 return;
2960 }
2961 }
2962 if (codeNotify == EN_CHANGE || codeNotify == CBN_SELCHANGE)
2963 {
2964 if (!m_bInInit)
2965 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
2966 }
2967}
2968
2969LRESULT CShellLink::OnNotify(HWND hwndDlg, int idFrom, LPNMHDR pnmhdr)
2970{
2971 WCHAR wszBuf[MAX_PATH];
2972 LPPSHNOTIFY lppsn = (LPPSHNOTIFY)pnmhdr;
2973
2974 if (lppsn->hdr.code == PSN_APPLY)
2975 {
2976 /* set working directory */
2977 GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_START_IN_EDIT, wszBuf, _countof(wszBuf));
2978 SetWorkingDirectory(wszBuf);
2979
2980 /* set link destination */
2981 GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, wszBuf, _countof(wszBuf));
2982 LPWSTR lpszArgs = NULL;
2983 LPWSTR unquoted = strdupW(wszBuf);
2984 StrTrimW(unquoted, L" ");
2985
2986 if (!PathFileExistsW(unquoted))
2987 {
2988 lpszArgs = PathGetArgsW(unquoted);
2989 PathRemoveArgsW(unquoted);
2990 StrTrimW(lpszArgs, L" ");
2991 }
2992 if (unquoted[0] == '"' && unquoted[wcslen(unquoted) - 1] == '"')
2993 PathUnquoteSpacesW(unquoted);
2994
2995 WCHAR *pwszExt = PathFindExtensionW(unquoted);
2996 if (!_wcsicmp(pwszExt, L".lnk"))
2997 {
2998 // FIXME load localized error msg
2999 MessageBoxW(hwndDlg, L"You cannot create a link to a shortcut", L"Error", MB_ICONERROR);
3001 return TRUE;
3002 }
3003
3004 if (!PathFileExistsW(unquoted))
3005 {
3006 // FIXME load localized error msg
3007 MessageBoxW(hwndDlg, L"The specified file name in the target box is invalid", L"Error", MB_ICONERROR);
3009 return TRUE;
3010 }
3011
3012 SetPath(unquoted);
3013 if (lpszArgs)
3014 SetArguments(lpszArgs);
3015 else
3016 SetArguments(L"\0");
3017
3018 HeapFree(GetProcessHeap(), 0, unquoted);
3019
3021
3023 if (index != CB_ERR)
3024 {
3026 }
3027
3028 TRACE("This %p m_sLinkPath %S\n", this, m_sLinkPath);
3032 return TRUE;
3033 }
3034 return FALSE;
3035}
3036
3038{
3039 if (m_hIcon)
3040 {
3042 m_hIcon = NULL;
3043 }
3044}
3045
3046/**************************************************************************
3047 * SH_ShellLinkDlgProc
3048 *
3049 * dialog proc of the shortcut property dialog
3050 */
3051
3054{
3055 LPPROPSHEETPAGEW ppsp;
3056 CShellLink *pThis = reinterpret_cast<CShellLink *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
3057
3058 switch (uMsg)
3059 {
3060 case WM_INITDIALOG:
3061 ppsp = (LPPROPSHEETPAGEW)lParam;
3062 if (ppsp == NULL)
3063 break;
3064
3065 pThis = reinterpret_cast<CShellLink *>(ppsp->lParam);
3066 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pThis);
3067 return pThis->OnInitDialog(hwndDlg, (HWND)(wParam), lParam);
3068
3069 case WM_NOTIFY:
3070 return pThis->OnNotify(hwndDlg, (int)wParam, (NMHDR *)lParam);
3071
3072 case WM_COMMAND:
3073 pThis->OnCommand(hwndDlg, LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
3074 break;
3075
3076 case WM_DESTROY:
3077 pThis->OnDestroy(hwndDlg);
3078 break;
3079
3080 default:
3081 break;
3082 }
3083
3084 return FALSE;
3085}
3086
3087/**************************************************************************
3088 * ShellLink_IShellPropSheetExt interface
3089 */
3090
3092{
3094 (LPARAM)this, NULL, &PropSheetPageLifetimeCallback<CShellLink>);
3095 HRESULT hr = AddPropSheetPage(hPage, pfnAddPage, lParam);
3097 return hr;
3098 else
3099 AddRef(); // For PropSheetPageLifetimeCallback
3100 enum { CShellLink_PageIndex_Shortcut = 0 };
3101 return 1 + CShellLink_PageIndex_Shortcut; // Make this page the default (one-based)
3102}
3103
3105{
3106 TRACE("(%p) (uPageID %u, pfnReplacePage %p lParam %p\n", this, uPageID, pfnReplacePage, lParam);
3107 return E_NOTIMPL;
3108}
3109
3111{
3112 TRACE("%p %p\n", this, punk);
3113
3114 m_site = punk;
3115
3116 return S_OK;
3117}
3118
3120{
3121 TRACE("%p %s %p\n", this, debugstr_guid(&iid), ppvSite);
3122
3123 if (m_site == NULL)
3124 return E_FAIL;
3125
3126 return m_site->QueryInterface(iid, ppvSite);
3127}
3128
3130 DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
3131{
3132 TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
3133
3134 if (*pdwEffect == DROPEFFECT_NONE)
3135 return S_OK;
3136
3138 if (SUCCEEDED(hr))
3139 hr = m_DropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect);
3140 else
3141 *pdwEffect = DROPEFFECT_NONE;
3142
3143 return S_OK;
3144}
3145
3147 DWORD *pdwEffect)
3148{
3149 TRACE("(%p)\n", this);
3150 HRESULT hr = S_OK;
3151 if (m_DropTarget)
3152 hr = m_DropTarget->DragOver(dwKeyState, pt, pdwEffect);
3153 return hr;
3154}
3155
3157{
3158 TRACE("(%p)\n", this);
3159 HRESULT hr = S_OK;
3160 if (m_DropTarget)
3161 {
3162 hr = m_DropTarget->DragLeave();
3164 }
3165
3166 return hr;
3167}
3168
3170 DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
3171{
3172 TRACE("(%p)\n", this);
3173 HRESULT hr = S_OK;
3174 if (m_DropTarget)
3175 hr = m_DropTarget->Drop(pDataObject, dwKeyState, pt, pdwEffect);
3176
3177 return hr;
3178}
3179
3180/**************************************************************************
3181 * IShellLink_ConstructFromFile
3182 */
3184{
3186 HRESULT hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IPersistFile, &ppf));
3187 if (FAILED(hr))
3188 return hr;
3189
3190 hr = ppf->Load(path, 0);
3191 if (FAILED(hr))
3192 return hr;
3193
3194 return ppf->QueryInterface(riid, ppv);
3195}
3196
3198{
3200 if (!ILGetDisplayNameExW(psf, pidl, path, 0))
3201 return E_FAIL;
3202
3204}
3205
3207{
3209 const COLORREF crMask = GetSysColor(COLOR_3DFACE);
3210 WCHAR wszLnkIcon[MAX_PATH];
3211 int lnk_idx;
3212 HDC hDC;
3214 HICON hIcon = NULL, hNewIcon = NULL, hShortcut;
3215
3216 if (HLM_GetIconW(IDI_SHELL_SHORTCUT - 1, wszLnkIcon, _countof(wszLnkIcon), &lnk_idx))
3217 {
3218 ::ExtractIconExW(wszLnkIcon, lnk_idx, &hShortcut, NULL, 1);
3219 }
3220 else
3221 {
3223 IMAGE_ICON, cx, cy, 0);
3224 }
3225
3226 ::ExtractIconExW(wszIconPath, IconIndex, &hIcon, NULL, 1);
3227 if (!hIcon || !hShortcut || !himl)
3228 goto cleanup;
3229
3231 if (hDC)
3232 {
3233 // create 32bpp bitmap
3234 BITMAPINFO bi;
3235 ZeroMemory(&bi, sizeof(bi));
3236 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
3237 bi.bmiHeader.biWidth = cx;
3238 bi.bmiHeader.biHeight = cy;
3239 bi.bmiHeader.biPlanes = 1;
3240 bi.bmiHeader.biBitCount = 32;
3241 LPVOID pvBits;
3242 HBITMAP hbm = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0);
3243 if (hbm)
3244 {
3245 // draw the icon image
3246 HGDIOBJ hbmOld = SelectObject(hDC, hbm);
3247 {
3248 HBRUSH hbr = CreateSolidBrush(crMask);
3249 RECT rc = { 0, 0, cx, cy };
3250 FillRect(hDC, &rc, hbr);
3251 DeleteObject(hbr);
3252
3253 DrawIconEx(hDC, 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL);
3254 DrawIconEx(hDC, 0, 0, hShortcut, cx, cy, 0, NULL, DI_NORMAL);
3255 }
3256 SelectObject(hDC, hbmOld);
3257
3258 INT iAdded = ImageList_AddMasked(himl, hbm, crMask);
3259 hNewIcon = ImageList_GetIcon(himl, iAdded, ILD_NORMAL | ILD_TRANSPARENT);
3260
3262 }
3263 DeleteDC(hDC);
3264 }
3265
3266cleanup:
3267 if (hIcon)
3269 if (hShortcut)
3270 DestroyIcon(hShortcut);
3271 if (himl)
3273
3274 return hNewIcon;
3275}
static HDC hDC
Definition: 3dtext.c:33
#define PRF_TRYPROGRAMEXTENSIONS
Definition: PathResolve.cpp:40
#define shell32_hInstance
UINT cchMax
unsigned int dir
Definition: maze.c:112
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
static WCHAR * strdupW(const WCHAR *src)
Definition: main.c:92
#define CF_HDROP
Definition: constants.h:410
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define STDMETHODCALLTYPE
Definition: bdasup.h:9
HIMAGELIST himl
EXTERN_C void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
void Release()
Definition: atlcomcli.h:170
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
wcsncpy
wcscpy
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
void pdump(LPCITEMIDLIST pidl)
Definition: debughlp.cpp:322
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
DWORD WINAPI CommandLineFromMsiDescriptor(WCHAR *szDescriptor, WCHAR *szCommandLine, DWORD *pcchCommandLine)
Definition: msi.c:22
UINT uFlags
Definition: api.c:59
BOOL WINAPI ImageList_Destroy(HIMAGELIST himl)
Definition: imagelist.c:928
HICON WINAPI ImageList_GetIcon(HIMAGELIST himl, INT i, UINT fStyle)
Definition: imagelist.c:1963
INT WINAPI ImageList_AddMasked(HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
Definition: imagelist.c:563
HIMAGELIST WINAPI ImageList_Create(INT cx, INT cy, UINT flags, INT cInitial, INT cGrow)
Definition: imagelist.c:804
#define wcschr
Definition: compat.h:17
#define GetProcessHeap()
Definition: compat.h:736
#define CP_ACP
Definition: compat.h:109
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define HeapAlloc
Definition: compat.h:733
static __inline const char * debugstr_an(const char *s, int n)
Definition: compat.h:55
#define TRACE_ON(x)
Definition: compat.h:75
#define MAX_PATH
Definition: compat.h:34
#define HeapFree(x, y, z)
Definition: compat.h:735
#define CALLBACK
Definition: compat.h:35
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
#define lstrcpynW
Definition: compat.h:738
#define lstrlenW
Definition: compat.h:750
#define FAILED_UNEXPECTEDLY(hr)
Definition: precomp.h:121
static void cleanup(void)
Definition: main.c:1335
DWORD WINAPI ExpandEnvironmentStringsW(IN LPCWSTR lpSrc, IN LPWSTR lpDst, IN DWORD nSize)
Definition: environ.c:519
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
UINT WINAPI GetDriveTypeW(IN LPCWSTR lpRootPathName)
Definition: disk.c:497
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:652
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
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
DWORD WINAPI GetShortPathNameW(IN LPCWSTR lpszLongPath, OUT LPWSTR lpszShortPath, IN DWORD cchBuffer)
Definition: path.c:1833
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1106
BOOL WINAPI FileTimeToSystemTime(IN CONST FILETIME *lpFileTime, OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:188
HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id)
Definition: compobj.c:2338
void WINAPI ReleaseStgMedium(STGMEDIUM *pmedium)
Definition: ole2.c:2033
static const WCHAR IconIndex[]
Definition: install.c:52
BOOL WINAPI PickIconDlg(HWND hWndOwner, LPWSTR lpstrFile, UINT nMaxFile, INT *lpdwIconIndex)
Definition: dialogs.cpp:362
static BOOLEAN bSuccess
Definition: drive.cpp:355
HRESULT SHGetNameAndFlagsW(_In_ LPCITEMIDLIST pidl, _In_ DWORD dwFlags, _Out_opt_ LPWSTR pszText, _In_ UINT cchBuf, _Inout_opt_ DWORD *pdwAttributes)
Definition: utils.cpp:476
const GUID SHELL32_AdvtShortcutProduct
static HRESULT AddPropSheetPage(HPROPSHEETPAGE hPage, LPFNSVADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
Definition: precomp.h:150
EXTERN_C HRESULT SHELL_GetUIObjectOfAbsoluteItem(_In_opt_ HWND hWnd, _In_ PCIDLIST_ABSOLUTE pidl, _In_ REFIID riid, _Out_ void **ppvObj)
Definition: utils.cpp:379
const GUID SHELL32_AdvtShortcutComponent
UINT WINAPI DragQueryFileW(HDROP hDrop, UINT lFile, LPWSTR lpszwFile, UINT lLength)
Definition: shellole.c:622
BOOL WINAPI PathResolveW(_Inout_ LPWSTR path, _Inout_opt_ LPCWSTR *dirs, _In_ DWORD flags)
Definition: shellpath.c:883
DATABLOCK_HEADER *WINAPI SHFindDataBlock(LPDBLIST lpList, DWORD dwSignature)
Definition: clist.c:424
HRESULT WINAPI SHReadDataBlockList(IStream *lpStream, LPDBLIST *lppList)
Definition: clist.c:235
VOID WINAPI SHFreeDataBlockList(LPDBLIST lpList)
Definition: clist.c:331
BOOL WINAPI SHAddDataBlock(LPDBLIST *lppList, const DATABLOCK_HEADER *lpNewItem)
Definition: clist.c:68
HRESULT WINAPI SHWriteDataBlockList(IStream *lpStream, LPDBLIST lpList)
Definition: clist.c:179
BOOL WINAPI SHRemoveDataBlock(LPDBLIST *lppList, DWORD dwSignature)
Definition: clist.c:355
HRESULT WINAPI SHCreateStreamOnFileW(LPCWSTR lpszPath, DWORD dwMode, IStream **lppStream)
Definition: istream.c:484
void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
Definition: path.c:779
BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
Definition: path.c:629
LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
Definition: path.c:394
BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR path, LPWSTR buffer, UINT buf_len)
Definition: path.c:4181
LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath)
Definition: path.c:447
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1783
VOID WINAPI PathUnquoteSpacesW(LPWSTR lpszPath)
Definition: path.c:1040
BOOL WINAPI PathIsFileSpecW(LPCWSTR lpszPath)
Definition: path.c:2139
BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr)
Definition: path.c:1838
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1729
LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath)
Definition: path.c:506
DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
Definition: string.c:2673
BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
Definition: string.c:1883
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define assert(x)
Definition: debug.h:53
#define MAKE_HRESULT(sev, fac, code)
Definition: dmerror.h:30
#define pt(x, y)
Definition: drawing.c:79
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
pKey DeleteObject()
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLenum src
Definition: glext.h:6340
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
GLuint index
Definition: glext.h:6031
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLenum target
Definition: glext.h:7315
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
HLOCAL NTAPI LocalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:1390
UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIcons)
Definition: iconcache.cpp:849
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: ifs.c:426
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
REFIID riid
Definition: atlbase.h:39
REFIID LPVOID * ppv
Definition: atlbase.h:39
struct IContextMenu::tagCMInvokeCommandInfoEx * LPCMINVOKECOMMANDINFOEX
HRESULT GetData([in, unique] FORMATETC *pformatetcIn, [out] STGMEDIUM *pmedium)
const DWORD DROPEFFECT_NONE
Definition: oleidl.idl:929
HRESULT Write([in, size_is(cb)] const void *pv, [in] ULONG cb, [out] ULONG *pcbWritten)
HRESULT Read([out, size_is(cb), length_is(*pcbRead)] void *pv, [in] ULONG cb, [out] ULONG *pcbRead)
ULONG AddRef()
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define NTDDI_VERSION
Definition: k32.h:33
#define debugstr_guid
Definition: kernel32.h:35
#define debugstr_w
Definition: kernel32.h:32
INT WINAPI GetDateFormatW(LCID lcid, DWORD dwFlags, const SYSTEMTIME *lpTime, LPCWSTR lpFormat, LPWSTR lpDateStr, INT cchOut)
Definition: lcformat.c:993
if(dx< 0)
Definition: linetemp.h:194
const GUID * guid
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define ASSERT(a)
Definition: mode.c:44
int DoOpen(void)
Definition: cmds.c:2168
LPCWSTR szPath
Definition: env.c:37
static HBITMAP
Definition: button.c:44
static HDC
Definition: imagelist.c:88
static HICON
Definition: imagelist.c:80
static const WCHAR label[]
Definition: itemdlg.c:1546
static char * dest
Definition: rtl.c:135
static const WCHAR szGuid[]
Definition: rtlstr.c:1892
static LPOLESTR
Definition: stg_prop.c:27
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:63
HICON hIcon
Definition: msconfig.c:44
struct _PSP * HPROPSHEETPAGE
Definition: mstask.idl:90
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
_In_ HANDLE _In_ DWORD _In_ DWORD _Inout_opt_ LPOVERLAPPED _In_opt_ LPTRANSMIT_FILE_BUFFERS _In_ DWORD dwReserved
Definition: mswsock.h:95
unsigned int UINT
Definition: ndis.h:50
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define LOCALE_USER_DEFAULT
#define UNICODE_NULL
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
_In_ HBITMAP hbm
Definition: ntgdi.h:2776
#define L(x)
Definition: ntvdm.h:50
#define STGM_CREATE
Definition: objbase.h:926
#define STGM_READWRITE
Definition: objbase.h:919
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:923
#define STGM_SHARE_DENY_WRITE
Definition: objbase.h:922
#define STGM_READ
Definition: objbase.h:917
#define PathAddBackslashW
Definition: pathcch.h:301
#define LOWORD(l)
Definition: pedump.c:82
unsigned short USHORT
Definition: pedump.c:61
LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner, int nFolder, BOOL fCreate)
Definition: pidl.c:445
LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl)
Definition: pidl.c:237
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:1044
HRESULT WINAPI SHILCreateFromPathW(LPCWSTR path, LPITEMIDLIST *ppidl, DWORD *attributes)
Definition: pidl.c:403
LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:816
BOOL WINAPI ILRemoveLastID(LPITEMIDLIST pidl)
Definition: pidl.c:221
HRESULT WINAPI ILSaveToStream(IStream *pStream, LPCITEMIDLIST pPidl)
Definition: pidl.c:353
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1454
HRESULT WINAPI ILLoadFromStream(IStream *pStream, LPITEMIDLIST *ppPidl)
Definition: pidl.c:293
LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath)
Definition: pidl.c:1238
BOOL ILGetDisplayNameExW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPWSTR path, DWORD type)
Definition: pidl.c:100
#define PSNRET_INVALID_NOCHANGEPAGE
Definition: prsht.h:131
#define PropSheet_Changed(d, w)
Definition: prsht.h:344
#define PSN_APPLY
Definition: prsht.h:117
#define PSNRET_NOERROR
Definition: prsht.h:129
struct _PROPSHEETPAGEW * LPPROPSHEETPAGEW
BOOL(CALLBACK * LPFNADDPROPSHEETPAGE)(HPROPSHEETPAGE, LPARAM)
Definition: prsht.h:327
struct _PSHNOTIFY * LPPSHNOTIFY
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:586
#define ILD_NORMAL
Definition: commctrl.h:417
_Out_opt_ int * cx
Definition: commctrl.h:585
#define ILC_COLOR32
Definition: commctrl.h:358
#define HKM_SETHOTKEY
Definition: commctrl.h:2236
#define ILD_TRANSPARENT
Definition: commctrl.h:418
#define ILC_MASK
Definition: commctrl.h:351
#define HKM_GETHOTKEY
Definition: commctrl.h:2237
#define IsEqualGUID(rguid1, rguid2)
Definition: guiddef.h:147
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
#define REFIID
Definition: guiddef.h:118
#define WM_NOTIFY
Definition: richedit.h:61
const WCHAR * str
static calc_node_t temp
Definition: rpn_ieee.c:38
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcspbrk(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
static HANDLE heap
Definition: heap.c:65
#define NTDDI_LONGHORN
Definition: sdkddkver.h:102
DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path, DWORD dwFileAttributes, SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags)
Definition: shell32_main.c:430
static __inline LPWSTR __SHCloneStrAtoW(WCHAR **target, const char *source)
Definition: shell32_main.h:175
#define SEE_MASK_DOENVSUBST
Definition: shellapi.h:35
#define SHGFI_DISPLAYNAME
Definition: shellapi.h:167
#define SEE_MASK_UNICODE
Definition: shellapi.h:37
#define SHGFI_ICON
Definition: shellapi.h:165
#define SHGFI_TYPENAME
Definition: shellapi.h:168
#define SHGFI_USEFILEATTRIBUTES
Definition: shellapi.h:182
#define SEE_MASK_ASYNCOK
Definition: shellapi.h:54
#define SEE_MASK_NOASYNC
Definition: shellapi.h:33
_In_ LPCSTR pszDir
Definition: shellapi.h:585
#define SEE_MASK_INVOKEIDLIST
Definition: shellapi.h:28
#define SEE_MASK_FLAG_NO_UI
Definition: shellapi.h:36
#define SEE_MASK_HASLINKNAME
Definition: shellapi.h:49
#define ILGetSize
Definition: shellclasses.h:638
HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
Definition: shlexec.cpp:1288
HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
Definition: shlexec.cpp:2500
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:2445
HRESULT hr
Definition: shlfolder.c:183
EXTERN_C HRESULT WINAPI SHOpenFolderAndSelectItems(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD dwFlags)
Definition: shlfolder.cpp:443
#define EXP_DARWIN_ID_SIG
Definition: shlobj.h:2055
#define SHCNE_UPDATEITEM
Definition: shlobj.h:1903
struct EXP_DARWIN_LINK * LPEXP_DARWIN_LINK
#define SHCNE_CREATE
Definition: shlobj.h:1891
#define EXP_SZ_LINK_SIG
Definition: shlobj.h:2051
@ SLDF_HAS_RELPATH
Definition: shlobj.h:1947
@ SLDF_HAS_EXP_SZ
Definition: shlobj.h:1953
@ SLDF_HAS_ID_LIST
Definition: shlobj.h:1944
@ SLDF_HAS_DARWINID
Definition: shlobj.h:1958
@ SLDF_RUN_IN_SEPARATE
Definition: shlobj.h:1954
@ SLDF_HAS_LINK_INFO
Definition: shlobj.h:1945
@ SLDF_HAS_WORKINGDIR
Definition: shlobj.h:1948
@ SLDF_HAS_ARGS
Definition: shlobj.h:1949
@ SLDF_FORCE_NO_LINKINFO
Definition: shlobj.h:1952
@ SLDF_HAS_EXP_ICON_SZ
Definition: shlobj.h:1960
@ SLDF_RUNAS_USER
Definition: shlobj.h:1959
@ SLDF_UNICODE
Definition: shlobj.h:1951
@ SLDF_RUN_WITH_SHIMLAYER
Definition: shlobj.h:1963
@ SLDF_HAS_ICONLOCATION
Definition: shlobj.h:1950
@ SLDF_HAS_NAME
Definition: shlobj.h:1946
#define EXP_SZ_ICON_SIG
Definition: shlobj.h:2059
#define EXP_SPECIAL_FOLDER_SIG
Definition: shlobj.h:2054
#define SHCNF_PATHW
Definition: shlobj.h:1925
struct EXP_SPECIAL_FOLDER * LPEXP_SPECIAL_FOLDER
struct EXP_SZ_LINK * LPEXP_SZ_LINK
HRESULT WINAPI SHAutoComplete(HWND hwndEdit, DWORD dwFlags)
Definition: autocomp.cpp:191
#define PathRemoveBackslash
Definition: shlwapi.h:1049
#define SHACF_DEFAULT
Definition: shlwapi.h:1939
DWORD WINAPI SHExpandEnvironmentStringsW(LPCWSTR, LPWSTR, DWORD)
#define IDC_SHORTCUT_FIND
Definition: shresdef.h:476
#define IDS_SHORTCUT_RUN_MAX
Definition: shresdef.h:263
#define IDC_SHORTCUT_ADVANCED
Definition: shresdef.h:478
#define IDS_OPEN_VERB
Definition: shresdef.h:212
#define IDC_SHORTCUT_RUN_COMBO
Definition: shresdef.h:473
#define IDS_OPENFILELOCATION
Definition: shresdef.h:246
#define IDS_SHORTCUT_RUN_MIN
Definition: shresdef.h:262
#define IDC_SHORTCUT_LOCATION_EDIT
Definition: shresdef.h:465
#define IDC_SHORTCUT_TEXT
Definition: shresdef.h:461
#define IDC_SHORTCUT_TARGET_TEXT
Definition: shresdef.h:467
#define IDC_SHORTCUT_ICON
Definition: shresdef.h:460
#define IDC_SHORTCUT_KEY_HOTKEY
Definition: shresdef.h:471
#define IDC_SHORTEX_RUN_DIFFERENT
Definition: shresdef.h:481
#define IDI_SHELL_SHORTCUT
Definition: shresdef.h:582
#define IDS_SHORTCUT_RUN_NORMAL
Definition: shresdef.h:261
#define IDD_SHORTCUT_PROPERTIES
Definition: shresdef.h:401
#define IDC_SHORTCUT_CHANGE_ICON
Definition: shresdef.h:477
#define IDD_SHORTCUT_EXTENDED_PROPERTIES
Definition: shresdef.h:407
#define IDC_SHORTCUT_TYPE_EDIT
Definition: shresdef.h:463
#define IDC_SHORTCUT_COMMENT_EDIT
Definition: shresdef.h:475
#define IDC_SHORTCUT_START_IN_EDIT
Definition: shresdef.h:469
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
#define _countof(array)
Definition: sndvol32.h:70
#define TRACE(s)
Definition: solgame.cpp:4
static PIXELFORMATDESCRIPTOR pfd
Definition: ssstars.c:67
STRSAFEAPI StringCchPrintfW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:530
STRSAFEAPI StringCchCopyExW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags)
Definition: strsafe.h:184
STRSAFEAPI StringCchCatW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:325
STRSAFEAPI StringCchPrintfExW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:585
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
STRSAFEAPI StringCbPrintfW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:557
DWORD idSpecialFolder
Definition: shlobj.h:2041
DWORD dwLocalPathOfs
Definition: CShellLink.cpp:167
DWORD dwHeaderSize
Definition: CShellLink.cpp:164
DWORD dwVolTableOfs
Definition: CShellLink.cpp:166
DWORD dwFinalPathOfs
Definition: CShellLink.cpp:169
DWORD dwNetworkVolTableOfs
Definition: CShellLink.cpp:168
LPARAM lParam
Definition: prsht.h:227
NMHDR hdr
Definition: prsht.h:330
LPCWSTR lpDirectory
Definition: shellapi.h:335
LPCWSTR lpParameters
Definition: shellapi.h:334
WCHAR szTypeName[80]
Definition: shellapi.h:377
WCHAR szDisplayName[MAX_PATH]
Definition: shellapi.h:376
HICON hIcon
Definition: shellapi.h:373
Definition: match.c:390
uint16_t size
Definition: btrfs_drv.h:563
Definition: fci.c:116
Definition: format.c:58