ReactOS 0.4.17-dev-116-ga4b6fe9
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://learn.microsoft.com/en-us/windows/win32/shell/links
44 *
45 *
46 * Details of the file format:
47 *
48 * - Official MSDN documentation "[MS-SHLLINK]: Shell Link (.LNK) Binary File Format":
49 * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/16cb4ca1-9339-4d0c-a68d-bf1d6cc0f943
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://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/ne-shlobj_core-shell_link_data_flags
59 * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/ae350202-3ba9-4790-9e9e-98935f4ee5af
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://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/6813269d-0cc8-4be2-933f-e96e8e3412dc
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://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/df8e3748-fba5-4524-968a-f72be06d71fc
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://learn.microsoft.com/en-us/previous-versions/dotnet/articles/aa302344(v=msdn.10)
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://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/48f8a4c4-99fe-4787-a39f-b1367103eba8
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://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741198(v=vs.85)
108 * and leveraged in Internet Explorer 4 with "Software Update Channels", see:
109 * https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa740931(v=vs.85)
110 * Applications supporting this technology could present shell links having
111 * a special target, see subsection "Modifying the Shortcut" in the article:
112 * https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741201(v=vs.85)#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://web.archive.org/web/20190110073640/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
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
220{
221 // Note: Don't call SHExpandEnvironmentStringsW here, we need the required length
222 WCHAR szStack[MAX_PATH];
223 DWORD cch = ExpandEnvironmentStringsW(pszPath, szStack, _countof(szStack));
224 if (cch <= _countof(szStack))
225 return cch && PathIsDirectory(szStack);
226
227 PWSTR szHeap = (PWSTR)SHAlloc(cch);
228 if (!szHeap)
229 return FALSE;
230 BOOL bResult = ExpandEnvironmentStringsW(pszPath, szHeap, cch) && PathIsDirectory(szHeap);
231 SHFree(szHeap);
232 return bResult;
233}
234
235// TODO: Use it for constructor & destructor too
237{
239 m_pPidl = NULL;
240
242 m_sPath = NULL;
243 ZeroMemory(&volume, sizeof(volume));
244
252 m_sArgs = NULL;
255
256 m_bRunAs = FALSE;
257 m_bDirty = FALSE;
258
259 if (m_pDBList)
261 m_pDBList = NULL;
262
264}
265
267{
268 m_Header.dwSize = sizeof(m_Header);
269 m_Header.clsid = CLSID_ShellLink;
270 m_Header.dwFlags = 0;
271
277
280 m_Header.wHotKey = 0;
281
282 m_pPidl = NULL;
283
284 m_sPath = NULL;
285 ZeroMemory(&volume, sizeof(volume));
286
290 m_sArgs = NULL;
292 m_bRunAs = FALSE;
293 m_bDirty = FALSE;
294 m_pDBList = NULL;
296 m_hIcon = NULL;
297
299
301}
302
304{
305 TRACE("-- destroying IShellLink(%p)\n", this);
306
308
310
318}
319
321{
322 TRACE("%p %p\n", this, pclsid);
323
324 if (pclsid == NULL)
325 return E_POINTER;
326 *pclsid = CLSID_ShellLink;
327 return S_OK;
328}
329
330/************************************************************************
331 * IPersistStream_IsDirty (IPersistStream)
332 */
334{
335 TRACE("(%p)\n", this);
336 return (m_bDirty ? S_OK : S_FALSE);
337}
338
340{
341 TRACE("(%p, %s, %x)\n", this, debugstr_w(pszFileName), dwMode);
342
343 if (dwMode == 0)
345
348 if (SUCCEEDED(hr))
349 {
352 hr = Load(stm);
354 m_bDirty = FALSE;
355 }
356 TRACE("-- returning hr %08x\n", hr);
357 return hr;
358}
359
361{
362 BOOL bAlreadyExists;
363 WCHAR szFullPath[MAX_PATH];
364
365 TRACE("(%p)->(%s)\n", this, debugstr_w(pszFileName));
366
367 if (!pszFileName)
368 return E_FAIL;
369
370 bAlreadyExists = PathFileExistsW(pszFileName);
371
374 if (SUCCEEDED(hr))
375 {
376 hr = Save(stm, FALSE);
377
378 if (SUCCEEDED(hr))
379 {
380 GetFullPathNameW(pszFileName, _countof(szFullPath), szFullPath, NULL);
381 if (bAlreadyExists)
383 else
385
386 if (m_sLinkPath)
388
390 m_bDirty = FALSE;
391 }
392 else
393 {
395 WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName));
396 }
397 }
398
399 return hr;
400}
401
403{
404 FIXME("(%p)->(%s)\n", this, debugstr_w(pszFileName));
405 return S_OK;
406}
407
409{
410 *ppszFileName = NULL;
411
412 if (!m_sLinkPath)
413 {
414 /* IPersistFile::GetCurFile called before IPersistFile::Save */
415 return S_FALSE;
416 }
417
418 *ppszFileName = (LPOLESTR)CoTaskMemAlloc((wcslen(m_sLinkPath) + 1) * sizeof(WCHAR));
419 if (!*ppszFileName)
420 {
421 /* out of memory */
422 return E_OUTOFMEMORY;
423 }
424
425 /* copy last saved filename */
426 wcscpy(*ppszFileName, m_sLinkPath);
427
428 return S_OK;
429}
430
431static HRESULT Stream_LoadString(IStream* stm, BOOL unicode, LPWSTR *pstr)
432{
433 TRACE("%p\n", stm);
434
435 USHORT len;
436 DWORD count = 0;
437 HRESULT hr = stm->Read(&len, sizeof(len), &count);
438 if (FAILED(hr) || count != sizeof(len))
439 return E_FAIL;
440
441 if (unicode)
442 len *= sizeof(WCHAR);
443
444 TRACE("reading %d\n", len);
445 LPSTR temp = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len + sizeof(WCHAR));
446 if (!temp)
447 return E_OUTOFMEMORY;
448 count = 0;
449 hr = stm->Read(temp, len, &count);
450 if (FAILED(hr) || count != len)
451 {
453 return E_FAIL;
454 }
455
456 TRACE("read %s\n", debugstr_an(temp, len));
457
458 /* convert to unicode if necessary */
459 LPWSTR str;
460 if (!unicode)
461 {
463 str = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (count + 1) * sizeof(WCHAR));
464 if (!str)
465 {
467 return E_OUTOFMEMORY;
468 }
471 }
472 else
473 {
474 count /= sizeof(WCHAR);
475 str = (LPWSTR)temp;
476 }
477 str[count] = 0;
478
479 *pstr = str;
480
481 return S_OK;
482}
483
484
485/*
486 * NOTE: The following 5 functions are part of LINKINFO.DLL
487 */
489{
490 WCHAR drive[4] = { path[0], ':', '\\', 0 };
491
492 volume->type = GetDriveTypeW(drive);
493 BOOL bRet = GetVolumeInformationW(drive, volume->label, _countof(volume->label), &volume->serial, NULL, NULL, NULL, 0);
494 TRACE("ret = %d type %d serial %08x name %s\n", bRet,
495 volume->type, volume->serial, debugstr_w(volume->label));
496 return bRet;
497}
498
500{
501 struct sized_chunk
502 {
503 DWORD size;
504 unsigned char data[1];
505 } *chunk;
506
507 TRACE("%p\n", stm);
508
509 DWORD size;
510 ULONG count;
511 HRESULT hr = stm->Read(&size, sizeof(size), &count);
512 if (FAILED(hr) || count != sizeof(size))
513 return E_FAIL;
514
515 chunk = static_cast<sized_chunk *>(HeapAlloc(GetProcessHeap(), 0, size));
516 if (!chunk)
517 return E_OUTOFMEMORY;
518
519 chunk->size = size;
520 hr = stm->Read(chunk->data, size - sizeof(size), &count);
521 if (FAILED(hr) || count != (size - sizeof(size)))
522 {
524 return E_FAIL;
525 }
526
527 TRACE("Read %d bytes\n", chunk->size);
528
529 *data = chunk;
530
531 return S_OK;
532}
533
535{
536 volume->serial = vol->dwVolSerial;
537 volume->type = vol->dwType;
538
539 if (!vol->dwVolLabelOfs)
540 return FALSE;
541 if (vol->dwSize <= vol->dwVolLabelOfs)
542 return FALSE;
543 INT len = vol->dwSize - vol->dwVolLabelOfs;
544
545 LPSTR label = (LPSTR)vol;
546 label += vol->dwVolLabelOfs; // FIXME: 0x14 Unicode
548
549 return TRUE;
550}
551
553{
554 UINT len = 0;
555
556 while (len < maxlen && p[len])
557 len++;
558
559 UINT wlen = MultiByteToWideChar(CP_ACP, 0, p, len, NULL, 0);
560 LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wlen + 1) * sizeof(WCHAR));
561 if (!path)
562 return NULL;
563 MultiByteToWideChar(CP_ACP, 0, p, len, path, wlen);
564 path[wlen] = 0;
565
566 return path;
567}
568
571{
572 char *p = NULL;
573 HRESULT hr = Stream_ReadChunk(stm, (LPVOID*) &p);
574 if (FAILED(hr))
575 return hr;
576
577 LOCATION_INFO *loc = reinterpret_cast<LOCATION_INFO *>(p);
578 if (loc->dwTotalSize < sizeof(LOCATION_INFO))
579 {
581 return E_FAIL;
582 }
583
584 /* if there's valid local volume information, load it */
585 if (loc->dwVolTableOfs &&
586 ((loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO)) <= loc->dwTotalSize))
587 {
589
592 }
593
594 /* if there's a local path, load it */
595 DWORD n = loc->dwLocalPathOfs;
596 if (n && n < loc->dwTotalSize)
597 *path = Stream_LoadPath(&p[n], loc->dwTotalSize - n); // FIXME: Unicode offset (if present)
598
599 TRACE("type %d serial %08x name %s path %s\n", volume->type,
600 volume->serial, debugstr_w(volume->label), debugstr_w(*path));
601
603 return S_OK;
604}
605
606
607/*
608 * The format of the advertised shortcut info is:
609 *
610 * Offset Description
611 * ------ -----------
612 * 0 Length of the block (4 bytes, usually 0x314)
613 * 4 tag (dword)
614 * 8 string data in ASCII
615 * 8+0x104 string data in UNICODE
616 *
617 * In the original Win32 implementation the buffers are not initialized
618 * to zero, so data trailing the string is random garbage.
619 */
621{
622 LPEXP_DARWIN_LINK pInfo;
623
624 *str = NULL;
625
627 if (!pInfo)
628 return E_FAIL;
629
630 /* Make sure that the size of the structure is valid */
631 if (pInfo->dbh.cbSize != sizeof(*pInfo))
632 {
633 ERR("Ooops. This structure is not as expected...\n");
634 return E_FAIL;
635 }
636
637 TRACE("dwSig %08x string = '%s'\n", pInfo->dbh.dwSignature, debugstr_w(pInfo->szwDarwinID));
638
639 *str = pInfo->szwDarwinID;
640 return S_OK;
641}
642
643/************************************************************************
644 * IPersistStream_Load (IPersistStream)
645 */
647{
648 TRACE("%p %p\n", this, stm);
649
650 if (!stm)
652
653 /* Free all the old stuff */
654 Reset();
655
656 ULONG dwBytesRead = 0;
657 HRESULT hr = stm->Read(&m_Header, sizeof(m_Header), &dwBytesRead);
658 if (FAILED(hr))
659 return hr;
660
661 if (dwBytesRead != sizeof(m_Header))
662 return E_FAIL;
663 if (m_Header.dwSize != sizeof(m_Header))
664 return E_FAIL;
665 if (!IsEqualIID(m_Header.clsid, CLSID_ShellLink))
666 return E_FAIL;
667
668 /* Load the new data in order */
669
670 if (TRACE_ON(shell))
671 {
672 SYSTEMTIME stCreationTime;
673 SYSTEMTIME stLastAccessTime;
674 SYSTEMTIME stLastWriteTime;
675 WCHAR sTemp[MAX_PATH];
676
680
682 NULL, sTemp, _countof(sTemp));
683 TRACE("-- stCreationTime: %s\n", debugstr_w(sTemp));
685 NULL, sTemp, _countof(sTemp));
686 TRACE("-- stLastAccessTime: %s\n", debugstr_w(sTemp));
688 NULL, sTemp, _countof(sTemp));
689 TRACE("-- stLastWriteTime: %s\n", debugstr_w(sTemp));
690 }
691
692 /* load all the new stuff */
694 {
695 hr = ILLoadFromStream(stm, &m_pPidl);
696 if (FAILED(hr))
697 return hr;
698 }
699 pdump(m_pPidl);
700
701 /* Load the location information... */
703 {
705 if (FAILED(hr))
706 return hr;
707 }
708 /* ... but if it is required not to use it, clear it */
710 {
712 m_sPath = NULL;
713 ZeroMemory(&volume, sizeof(volume));
714 }
715
716 BOOL unicode = !!(m_Header.dwFlags & SLDF_UNICODE);
717
719 {
720 hr = Stream_LoadString(stm, unicode, &m_sDescription);
721 if (FAILED(hr))
722 return hr;
723 TRACE("Description -> %s\n", debugstr_w(m_sDescription));
724 }
725
727 {
728 hr = Stream_LoadString(stm, unicode, &m_sPathRel);
729 if (FAILED(hr))
730 return hr;
731 TRACE("Relative Path-> %s\n", debugstr_w(m_sPathRel));
732 }
733
735 {
736 hr = Stream_LoadString(stm, unicode, &m_sWorkDir);
737 if (FAILED(hr))
738 return hr;
740 TRACE("Working Dir -> %s\n", debugstr_w(m_sWorkDir));
741 }
742
744 {
745 hr = Stream_LoadString(stm, unicode, &m_sArgs);
746 if (FAILED(hr))
747 return hr;
748 TRACE("Arguments -> %s\n", debugstr_w(m_sArgs));
749 }
750
752 {
753 hr = Stream_LoadString(stm, unicode, &m_sIcoPath);
754 if (FAILED(hr))
755 return hr;
756 TRACE("Icon file -> %s\n", debugstr_w(m_sIcoPath));
757 }
758
759 /* Now load the optional data block list */
761 if (FAILED(hr)) // FIXME: Should we fail?
762 return hr;
763
765 if (pSpecial && pSpecial->cbSize == sizeof(*pSpecial) && ILGetSize(m_pPidl) > pSpecial->cbOffset)
766 {
768 {
769 LPITEMIDLIST pidl = ILCombine(folder, (LPITEMIDLIST)((char*)m_pPidl + pSpecial->cbOffset));
770 if (pidl)
771 {
773 m_pPidl = pidl;
774 TRACE("Replaced pidl base with CSIDL %u up to %ub.\n", pSpecial->idSpecialFolder, pSpecial->cbOffset);
775 }
776 ILFree(folder);
777 }
778 }
779
780 if (TRACE_ON(shell))
781 {
782#if (NTDDI_VERSION < NTDDI_LONGHORN)
784 {
785 hr = GetAdvertiseInfo(&sProduct, EXP_LOGO3_ID_SIG);
786 if (SUCCEEDED(hr))
787 TRACE("Product -> %s\n", debugstr_w(sProduct));
788 }
789#endif
791 {
793 if (SUCCEEDED(hr))
794 TRACE("Component -> %s\n", debugstr_w(sComponent));
795 }
796 }
797
799 m_bRunAs = TRUE;
800 else
801 m_bRunAs = FALSE;
802
803 TRACE("OK\n");
804
805 pdump(m_pPidl);
806
807 return S_OK;
808}
809
810/************************************************************************
811 * Stream_WriteString
812 *
813 * Helper function for IPersistStream_Save. Writes a unicode string
814 * with terminating nul byte to a stream, preceded by the its length.
815 */
817{
819 USHORT len;
820 DWORD count;
821
822 length = wcslen(str) + 1;
823 if (length > MAXUSHORT)
824 {
825 return E_INVALIDARG;
826 }
827
828 len = (USHORT)length;
829 HRESULT hr = stm->Write(&len, sizeof(len), &count);
830 if (FAILED(hr))
831 return hr;
832
833 length *= sizeof(WCHAR);
834
835 hr = stm->Write(str, (ULONG)length, &count);
836 if (FAILED(hr))
837 return hr;
838
839 return S_OK;
840}
841
842/************************************************************************
843 * Stream_WriteLocationInfo
844 *
845 * Writes the location info to a stream
846 *
847 * FIXME: One day we might want to write the network volume information
848 * and the final path.
849 * Figure out how Windows deals with unicode paths here.
850 */
852 CShellLink::volume_info *volume) // FIXME: Write Unicode strings
853{
855 LOCATION_INFO *loc;
856
857 TRACE("%p %s %p\n", stm, debugstr_w(path), volume);
858
859 /* figure out the size of everything */
860 DWORD label_size = WideCharToMultiByte(CP_ACP, 0, volume->label, -1,
861 NULL, 0, NULL, NULL);
862 DWORD path_size = WideCharToMultiByte(CP_ACP, 0, path, -1,
863 NULL, 0, NULL, NULL);
864 DWORD volume_info_size = sizeof(*vol) + label_size;
865 DWORD final_path_size = 1;
866 DWORD total_size = sizeof(*loc) + volume_info_size + path_size + final_path_size;
867
868 /* create pointers to everything */
869 loc = static_cast<LOCATION_INFO *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, total_size));
870 vol = (LOCAL_VOLUME_INFO*) &loc[1];
871 LPSTR szLabel = (LPSTR) &vol[1];
872 LPSTR szPath = &szLabel[label_size];
873 LPSTR szFinalPath = &szPath[path_size];
874
875 /* fill in the location information header */
876 loc->dwTotalSize = total_size;
877 loc->dwHeaderSize = sizeof(*loc);
878 loc->dwFlags = 1;
879 loc->dwVolTableOfs = sizeof(*loc);
880 loc->dwLocalPathOfs = sizeof(*loc) + volume_info_size;
881 loc->dwNetworkVolTableOfs = 0;
882 loc->dwFinalPathOfs = sizeof(*loc) + volume_info_size + path_size;
883
884 /* fill in the volume information */
885 vol->dwSize = volume_info_size;
886 vol->dwType = volume->type;
887 vol->dwVolSerial = volume->serial;
888 vol->dwVolLabelOfs = sizeof(*vol);
889
890 /* copy in the strings */
891 WideCharToMultiByte(CP_ACP, 0, volume->label, -1,
892 szLabel, label_size, NULL, NULL);
894 szPath, path_size, NULL, NULL);
895 *szFinalPath = 0;
896
897 ULONG count = 0;
898 HRESULT hr = stm->Write(loc, total_size, &count);
899 HeapFree(GetProcessHeap(), 0, loc);
900
901 return hr;
902}
903
904/************************************************************************
905 * IPersistStream_Save (IPersistStream)
906 *
907 * FIXME: makes assumptions about byte order
908 */
910{
911 TRACE("%p %p %x\n", this, stm, fClearDirty);
912
913 m_Header.dwSize = sizeof(m_Header);
914 m_Header.clsid = CLSID_ShellLink;
916
917 /* Store target attributes */
918 WIN32_FIND_DATAW wfd = {};
919 WCHAR FsTarget[MAX_PATH];
920 if (GetPath(FsTarget, _countof(FsTarget), NULL, 0) == S_OK && PathFileExistsW(FsTarget))
921 {
922 HANDLE hFind = FindFirstFileW(FsTarget, &wfd);
923 if (hFind != INVALID_HANDLE_VALUE)
924 FindClose(hFind);
925 }
931
932 /*
933 * Reset the flags: keep only the flags related to data blocks as they were
934 * already set in accordance by the different mutator member functions.
935 * The other flags will be determined now by the presence or absence of data.
936 */
937 UINT NT6SimpleFlags = LOBYTE(GetVersion()) > 6 ? (0x00040000 | 0x00400000 | 0x00800000 | 0x02000000) : 0;
939 SLDF_HAS_DARWINID | SLDF_FORCE_NO_LINKINFO | NT6SimpleFlags |
940#if (NTDDI_VERSION < NTDDI_LONGHORN)
942#endif
944 // TODO: When we will support Vista+ functionality, add other flags to this list.
945
946 /* The stored strings are in UNICODE */
948
949 if (m_pPidl)
955 if (m_sPathRel && *m_sPathRel)
957 if (m_sWorkDir && *m_sWorkDir)
959 if (m_sArgs && *m_sArgs)
961 if (m_sIcoPath && *m_sIcoPath)
963 if (m_bRunAs)
965
966 /* Write the shortcut header */
967 ULONG count;
968 HRESULT hr = stm->Write(&m_Header, sizeof(m_Header), &count);
969 if (FAILED(hr))
970 {
971 ERR("Write failed\n");
972 return hr;
973 }
974
975 /* Save the data in order */
976
977 if (m_pPidl)
978 {
979 hr = ILSaveToStream(stm, m_pPidl);
980 if (FAILED(hr))
981 {
982 ERR("Failed to write PIDL\n");
983 return hr;
984 }
985 }
986
988 {
990 if (FAILED(hr))
991 return hr;
992 }
993
995 {
997 if (FAILED(hr))
998 return hr;
999 }
1000
1002 {
1004 if (FAILED(hr))
1005 return hr;
1006 }
1007
1009 {
1011 if (FAILED(hr))
1012 return hr;
1013 }
1014
1016 {
1018 if (FAILED(hr))
1019 return hr;
1020 }
1021
1023 {
1025 if (FAILED(hr))
1026 return hr;
1027 }
1028
1029 /*
1030 * Now save the data block list.
1031 *
1032 * NOTE that both advertised Product and Component are already saved
1033 * inside Logo3 and Darwin data blocks in the m_pDBList list, and the
1034 * m_Header.dwFlags is suitably initialized.
1035 */
1037 if (FAILED(hr))
1038 return hr;
1039
1040 /* Clear the dirty bit if requested */
1041 if (fClearDirty)
1042 m_bDirty = FALSE;
1043
1044 return hr;
1045}
1046
1047/************************************************************************
1048 * IPersistStream_GetSizeMax (IPersistStream)
1049 */
1051{
1052 TRACE("(%p)\n", this);
1053 return E_NOTIMPL;
1054}
1055
1057{
1059 return FALSE;
1060
1061 return TRUE;
1062}
1063
1064/**************************************************************************
1065 * ShellLink_UpdatePath
1066 * update absolute path in sPath using relative path in sPathRel
1067 */
1068static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath)
1069{
1070 if (!path || !psPath)
1071 return E_INVALIDARG;
1072
1073 if (!*psPath && sPathRel)
1074 {
1075 WCHAR buffer[2*MAX_PATH], abs_path[2*MAX_PATH];
1076 LPWSTR final = NULL;
1077
1078 /* first try if [directory of link file] + [relative path] finds an existing file */
1079
1080 GetFullPathNameW(path, MAX_PATH * 2, buffer, &final);
1081 if (!final)
1082 final = buffer;
1083 wcscpy(final, sPathRel);
1084
1085 *abs_path = '\0';
1086
1088 {
1089 if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
1090 wcscpy(abs_path, buffer);
1091 }
1092 else
1093 {
1094 /* try if [working directory] + [relative path] finds an existing file */
1095 if (sWorkDir)
1096 {
1097 wcscpy(buffer, sWorkDir);
1098 wcscpy(PathAddBackslashW(buffer), sPathRel);
1099
1101 if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
1102 wcscpy(abs_path, buffer);
1103 }
1104 }
1105
1106 /* FIXME: This is even not enough - not all shell links can be resolved using this algorithm. */
1107 if (!*abs_path)
1108 wcscpy(abs_path, sPathRel);
1109
1110 *psPath = strdupW(abs_path);
1111 if (!*psPath)
1112 return E_OUTOFMEMORY;
1113 }
1114
1115 return S_OK;
1116}
1117
1119{
1120 HRESULT hr;
1121 LPWSTR pszFileW;
1122 WIN32_FIND_DATAW wfd;
1123
1124 TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
1125 this, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(m_sPath));
1126
1127 /* Allocate a temporary UNICODE buffer */
1128 pszFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, max(cchMaxPath, MAX_PATH) * sizeof(WCHAR));
1129 if (!pszFileW)
1130 return E_OUTOFMEMORY;
1131
1132 /* Call the UNICODE function */
1133 hr = GetPath(pszFileW, cchMaxPath, &wfd, fFlags);
1134
1135 /* Convert the file path back to ANSI */
1136 WideCharToMultiByte(CP_ACP, 0, pszFileW, -1,
1137 pszFile, cchMaxPath, NULL, NULL);
1138
1139 /* Free the temporary buffer */
1140 HeapFree(GetProcessHeap(), 0, pszFileW);
1141
1142 if (pfd)
1143 {
1144 ZeroMemory(pfd, sizeof(*pfd));
1145
1146 /* Copy the file data if a file path was returned */
1147 if (*pszFile)
1148 {
1149 DWORD len;
1150
1151 /* Copy the fixed part */
1152 CopyMemory(pfd, &wfd, FIELD_OFFSET(WIN32_FIND_DATAA, cFileName));
1153
1154 /* Convert the file names to ANSI */
1155 len = lstrlenW(wfd.cFileName);
1157 pfd->cFileName, sizeof(pfd->cFileName), NULL, NULL);
1160 pfd->cAlternateFileName, sizeof(pfd->cAlternateFileName), NULL, NULL);
1161 }
1162 }
1163
1164 return hr;
1165}
1166
1168{
1169 TRACE("(%p)->(ppidl=%p)\n", this, ppidl);
1170
1171 if (!m_pPidl)
1172 {
1173 *ppidl = NULL;
1174 return S_FALSE;
1175 }
1176
1177 *ppidl = ILClone(m_pPidl);
1178 return S_OK;
1179}
1180
1182{
1183 TRACE("(%p)->(pidl=%p)\n", this, pidl);
1184 return SetTargetFromPIDLOrPath(pidl, NULL);
1185}
1186
1188{
1189 TRACE("(%p)->(%p len=%u)\n", this, pszName, cchMaxName);
1190
1191 if (cchMaxName)
1192 *pszName = 0;
1193
1194 if (m_sDescription)
1196 pszName, cchMaxName, NULL, NULL);
1197
1198 return S_OK;
1199}
1200
1202{
1203 TRACE("(%p)->(pName=%s)\n", this, pszName);
1204
1207
1208 if (pszName)
1209 {
1211 if (!m_sDescription)
1212 return E_OUTOFMEMORY;
1213 }
1214 m_bDirty = TRUE;
1215
1216 return S_OK;
1217}
1218
1220{
1221 TRACE("(%p)->(%p len=%u)\n", this, pszDir, cchMaxPath);
1222
1223 if (cchMaxPath)
1224 *pszDir = 0;
1225
1226 if (m_sWorkDir)
1228 pszDir, cchMaxPath, NULL, NULL);
1229
1230 return S_OK;
1231}
1232
1234{
1235 TRACE("(%p)->(dir=%s)\n", this, pszDir);
1236
1238 m_sWorkDir = NULL;
1239
1240 if (pszDir)
1241 {
1243 if (!m_sWorkDir)
1244 return E_OUTOFMEMORY;
1245 }
1246 m_bDirty = TRUE;
1247
1248 return S_OK;
1249}
1250
1252{
1253 TRACE("(%p)->(%p len=%u)\n", this, pszArgs, cchMaxPath);
1254
1255 if (cchMaxPath)
1256 *pszArgs = 0;
1257
1258 if (m_sArgs)
1260 pszArgs, cchMaxPath, NULL, NULL);
1261
1262 return S_OK;
1263}
1264
1266{
1267 TRACE("(%p)->(args=%s)\n", this, pszArgs);
1268
1270 m_sArgs = NULL;
1271
1272 if (pszArgs)
1273 {
1274 m_sArgs = HEAP_strdupAtoW(GetProcessHeap(), 0, pszArgs);
1275 if (!m_sArgs)
1276 return E_OUTOFMEMORY;
1277 }
1278 m_bDirty = TRUE;
1279
1280 return S_OK;
1281}
1282
1284{
1285 TRACE("(%p)->(%p)(0x%08x)\n", this, pwHotkey, m_Header.wHotKey);
1286 *pwHotkey = m_Header.wHotKey;
1287 return S_OK;
1288}
1289
1291{
1292 TRACE("(%p)->(hotkey=%x)\n", this, wHotkey);
1293
1294 m_Header.wHotKey = wHotkey;
1295 m_bDirty = TRUE;
1296
1297 return S_OK;
1298}
1299
1301{
1302 TRACE("(%p)->(%p) %d\n", this, piShowCmd, m_Header.nShowCommand);
1303 *piShowCmd = m_Header.nShowCommand;
1304 return S_OK;
1305}
1306
1308{
1309 TRACE("(%p) %d\n", this, iShowCmd);
1310
1311 m_Header.nShowCommand = iShowCmd;
1312 m_bDirty = TRUE;
1313
1314 return S_OK;
1315}
1316
1318{
1319 HRESULT hr;
1320 LPWSTR pszIconPathW;
1321
1322 TRACE("(%p)->(%p len=%u iicon=%p)\n", this, pszIconPath, cchIconPath, piIcon);
1323
1324 /* Allocate a temporary UNICODE buffer */
1325 pszIconPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchIconPath * sizeof(WCHAR));
1326 if (!pszIconPathW)
1327 return E_OUTOFMEMORY;
1328
1329 /* Call the UNICODE function */
1330 hr = GetIconLocation(pszIconPathW, cchIconPath, piIcon);
1331
1332 /* Convert the file path back to ANSI */
1333 WideCharToMultiByte(CP_ACP, 0, pszIconPathW, -1,
1334 pszIconPath, cchIconPath, NULL, NULL);
1335
1336 /* Free the temporary buffer */
1337 HeapFree(GetProcessHeap(), 0, pszIconPathW);
1338
1339 return hr;
1340}
1341
1343{
1344 HRESULT hr;
1345 LPWSTR pszIconFileW;
1346
1347 TRACE("(%p)->(%u %p len=%u piIndex=%p pwFlags=%p)\n", this, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1348
1349 /* Allocate a temporary UNICODE buffer */
1350 pszIconFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchMax * sizeof(WCHAR));
1351 if (!pszIconFileW)
1352 return E_OUTOFMEMORY;
1353
1354 /* Call the UNICODE function */
1355 hr = GetIconLocation(uFlags, pszIconFileW, cchMax, piIndex, pwFlags);
1356
1357 /* Convert the file path back to ANSI */
1358 WideCharToMultiByte(CP_ACP, 0, pszIconFileW, -1,
1359 pszIconFile, cchMax, NULL, NULL);
1360
1361 /* Free the temporary buffer */
1362 HeapFree(GetProcessHeap(), 0, pszIconFileW);
1363
1364 return hr;
1365}
1366
1367HRESULT STDMETHODCALLTYPE CShellLink::Extract(PCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
1368{
1369 TRACE("(%p)->(path=%s iicon=%u)\n", this, pszFile, nIconIndex);
1370
1371 LPWSTR str = NULL;
1372 if (pszFile)
1373 {
1374 str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
1375 if (!str)
1376 return E_OUTOFMEMORY;
1377 }
1378
1379 HRESULT hr = Extract(str, nIconIndex, phiconLarge, phiconSmall, nIconSize);
1380
1381 if (str)
1383
1384 return hr;
1385}
1386
1388{
1389 TRACE("(%p)->(path=%s iicon=%d)\n", this, pszIconPath, iIcon);
1390
1391 LPWSTR str = NULL;
1392 if (pszIconPath)
1393 {
1394 str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath);
1395 if (!str)
1396 return E_OUTOFMEMORY;
1397 }
1398
1399 HRESULT hr = SetIconLocation(str, iIcon);
1400
1401 if (str)
1403
1404 return hr;
1405}
1406
1408{
1409 TRACE("(%p)->(path=%s %x)\n", this, pszPathRel, dwReserved);
1410
1412 m_sPathRel = NULL;
1413
1414 if (pszPathRel)
1415 {
1416 m_sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
1417 m_bDirty = TRUE;
1418 }
1419
1421}
1422
1423static LPWSTR
1425{
1426 DWORD Result, sz = 0;
1427
1428 Result = CommandLineFromMsiDescriptor(component, NULL, &sz);
1429 if (Result != ERROR_SUCCESS)
1430 return NULL;
1431
1432 sz++;
1433 LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR));
1434 Result = CommandLineFromMsiDescriptor(component, path, &sz);
1435 if (Result != ERROR_SUCCESS)
1436 {
1438 path = NULL;
1439 }
1440
1441 TRACE("returning %s\n", debugstr_w(path));
1442
1443 return path;
1444}
1445
1447{
1448 HRESULT hr = S_OK;
1449 BOOL bSuccess;
1450
1451 TRACE("(%p)->(hwnd=%p flags=%x)\n", this, hwnd, fFlags);
1452
1453 /* FIXME: use IResolveShellLink interface? */
1454
1455 // FIXME: See InvokeCommand().
1456
1457#if (NTDDI_VERSION < NTDDI_LONGHORN)
1458 // NOTE: For Logo3 (EXP_LOGO3_ID_SIG), check also for SHRestricted(REST_NOLOGO3CHANNELNOTIFY)
1460 {
1461 FIXME("Logo3 links are not supported yet!\n");
1462 return E_FAIL;
1463 }
1464#endif
1465
1466 /* Resolve Darwin (MSI) target */
1468 {
1469 LPWSTR component = NULL;
1470 hr = GetAdvertiseInfo(&component, EXP_DARWIN_ID_SIG);
1471 if (FAILED(hr))
1472 return E_FAIL;
1473
1474 /* Clear the cached path */
1477 if (!m_sPath)
1478 return E_FAIL;
1479 }
1480
1481 if (!m_sPath && m_pPidl)
1482 {
1484
1485 bSuccess = SHGetPathFromIDListW(m_pPidl, buffer);
1486 if (bSuccess && *buffer)
1487 {
1489 if (!m_sPath)
1490 return E_OUTOFMEMORY;
1491
1492 m_bDirty = TRUE;
1493 }
1494 else
1495 {
1496 hr = S_OK; /* don't report an error occurred while just caching information */
1497 }
1498 }
1499
1500 // FIXME: Strange to do that here...
1501 if (!m_sIcoPath && m_sPath)
1502 {
1504 if (!m_sIcoPath)
1505 return E_OUTOFMEMORY;
1506
1507 m_Header.nIconIndex = 0;
1508 m_bDirty = TRUE;
1509 }
1510
1511 return hr;
1512}
1513
1515{
1516 TRACE("(%p)->(path=%s)\n", this, pszFile);
1517
1518 if (!pszFile)
1519 return E_INVALIDARG;
1520
1521 LPWSTR str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
1522 if (!str)
1523 return E_OUTOFMEMORY;
1524
1525 HRESULT hr = SetPath(str);
1527
1528 return hr;
1529}
1530
1532{
1534
1535 TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
1536 this, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(m_sPath));
1537
1538 if (cchMaxPath)
1539 *pszFile = 0;
1540 // FIXME: What if cchMaxPath == 0 , or pszFile == NULL ??
1541
1542 // FIXME: What about Darwin??
1543
1544 /*
1545 * Retrieve the path to the target from the PIDL (if we have one).
1546 * NOTE: Do NOT use the cached path (m_sPath from link info).
1547 */
1549 {
1550 if (fFlags & SLGP_SHORTPATH)
1552 // FIXME: Add support for SLGP_UNCPRIORITY
1553 }
1554 else
1555 {
1556 *buffer = 0;
1557 }
1558
1559 /* If we have a FindData structure, initialize it */
1560 if (pfd)
1561 {
1562 ZeroMemory(pfd, sizeof(*pfd));
1563
1564 /* Copy the file data if the target is a file path */
1565 if (*buffer)
1566 {
1567 pfd->dwFileAttributes = m_Header.dwFileAttributes;
1568 pfd->ftCreationTime = m_Header.ftCreationTime;
1569 pfd->ftLastAccessTime = m_Header.ftLastAccessTime;
1570 pfd->ftLastWriteTime = m_Header.ftLastWriteTime;
1571 pfd->nFileSizeHigh = 0;
1572 pfd->nFileSizeLow = m_Header.nFileSizeLow;
1573
1574 /*
1575 * Build temporarily a short path in pfd->cFileName (of size MAX_PATH),
1576 * then extract and store the short file name in pfd->cAlternateFileName.
1577 */
1578 GetShortPathNameW(buffer, pfd->cFileName, _countof(pfd->cFileName));
1579 lstrcpynW(pfd->cAlternateFileName,
1580 PathFindFileNameW(pfd->cFileName),
1581 _countof(pfd->cAlternateFileName));
1582
1583 /* Now extract and store the long file name in pfd->cFileName */
1584 lstrcpynW(pfd->cFileName,
1586 _countof(pfd->cFileName));
1587 }
1588 }
1589
1590 /* Finally check if we have a raw path the user actually wants to retrieve */
1591 if ((fFlags & SLGP_RAWPATH) && (m_Header.dwFlags & SLDF_HAS_EXP_SZ))
1592 {
1593 /* Search for a target environment block */
1594 LPEXP_SZ_LINK pInfo;
1596 if (pInfo && (pInfo->cbSize == sizeof(*pInfo)))
1597 lstrcpynW(buffer, pInfo->szwTarget, cchMaxPath);
1598 }
1599
1600 /* For diagnostics purposes only... */
1601 // NOTE: SLGP_UNCPRIORITY is unsupported
1602 fFlags &= ~(SLGP_RAWPATH | SLGP_SHORTPATH);
1603 if (fFlags) FIXME("(%p): Unsupported flags %lu\n", this, fFlags);
1604
1605 /* Copy the data back to the user */
1606 if (*buffer)
1607 lstrcpynW(pszFile, buffer, cchMaxPath);
1608
1609 return (*buffer ? S_OK : S_FALSE);
1610}
1611
1613{
1614 TRACE("(%p)->(%p len=%u)\n", this, pszName, cchMaxName);
1615
1616 *pszName = 0;
1617 if (m_sDescription)
1618 lstrcpynW(pszName, m_sDescription, cchMaxName);
1619
1620 return S_OK;
1621}
1622
1624{
1625 TRACE("(%p)->(desc=%s)\n", this, debugstr_w(pszName));
1626
1629
1630 if (pszName)
1631 {
1632 m_sDescription = strdupW(pszName);
1633 if (!m_sDescription)
1634 return E_OUTOFMEMORY;
1635 }
1636 m_bDirty = TRUE;
1637
1638 return S_OK;
1639}
1640
1642{
1643 TRACE("(%p)->(%p len %u)\n", this, pszDir, cchMaxPath);
1644
1645 if (cchMaxPath)
1646 *pszDir = 0;
1647
1648 if (m_sWorkDir)
1649 lstrcpynW(pszDir, m_sWorkDir, cchMaxPath);
1650
1651 return S_OK;
1652}
1653
1655{
1656 TRACE("(%p)->(dir=%s)\n", this, debugstr_w(pszDir));
1657
1659 m_sWorkDir = NULL;
1660
1661 if (pszDir)
1662 {
1664 if (!m_sWorkDir)
1665 return E_OUTOFMEMORY;
1666 }
1667 m_bDirty = TRUE;
1668
1669 return S_OK;
1670}
1671
1673{
1674 TRACE("(%p)->(%p len=%u)\n", this, pszArgs, cchMaxPath);
1675
1676 if (cchMaxPath)
1677 *pszArgs = 0;
1678
1679 if (m_sArgs)
1680 lstrcpynW(pszArgs, m_sArgs, cchMaxPath);
1681
1682 return S_OK;
1683}
1684
1686{
1687 TRACE("(%p)->(args=%s)\n", this, debugstr_w(pszArgs));
1688
1690 m_sArgs = NULL;
1691
1692 if (pszArgs)
1693 {
1694 m_sArgs = strdupW(pszArgs);
1695 if (!m_sArgs)
1696 return E_OUTOFMEMORY;
1697 }
1698 m_bDirty = TRUE;
1699
1700 return S_OK;
1701}
1702
1704{
1705 TRACE("(%p)->(%p len=%u iicon=%p)\n", this, pszIconPath, cchIconPath, piIcon);
1706
1707 if (cchIconPath)
1708 *pszIconPath = 0;
1709
1710 *piIcon = 0;
1711
1712 /* Update the original icon path location */
1714 {
1716
1717 /* Search for an icon environment block */
1718 LPEXP_SZ_LINK pInfo;
1720 if (pInfo && (pInfo->cbSize == sizeof(*pInfo)))
1721 {
1723
1724 m_Header.dwFlags &= ~SLDF_HAS_ICONLOCATION;
1726
1728 if (!m_sIcoPath)
1729 return E_OUTOFMEMORY;
1730
1732
1733 m_bDirty = TRUE;
1734 }
1735 }
1736
1737 *piIcon = m_Header.nIconIndex;
1738
1739 if (m_sIcoPath)
1740 lstrcpynW(pszIconPath, m_sIcoPath, cchIconPath);
1741
1742 return S_OK;
1743}
1744
1746 UINT uFlags, PWSTR pszIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
1747{
1751 return hr;
1752 hr = pei->GetIconLocation(uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1754 return hr;
1755
1756 return S_OK;
1757}
1758
1760{
1761 HRESULT hr;
1762
1763 pszIconFile[0] = UNICODE_NULL;
1764
1765 /*
1766 * It is possible for a shell link to point to another shell link,
1767 * and in particular there is the possibility to point to itself.
1768 * Now, suppose we ask such a link to retrieve its associated icon.
1769 * This function would be called, and due to COM would be called again
1770 * recursively. To solve this issue, we forbid calling GetIconLocation()
1771 * with GIL_FORSHORTCUT set in uFlags, as done by Windows (shown by tests).
1772 */
1773 if (uFlags & GIL_FORSHORTCUT)
1774 return E_INVALIDARG;
1775
1776 /*
1777 * Now, we set GIL_FORSHORTCUT so that: i) we allow the icon extractor
1778 * of the target to give us a suited icon, and ii) we protect ourselves
1779 * against recursive call.
1780 */
1781 uFlags |= GIL_FORSHORTCUT;
1782
1783 if (uFlags & GIL_DEFAULTICON)
1784 return S_FALSE;
1785
1786 hr = GetIconLocation(pszIconFile, cchMax, piIndex);
1787 if (FAILED(hr) || pszIconFile[0] == UNICODE_NULL)
1788 {
1789 hr = SHELL_PidlGetIconLocationW(m_pPidl, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
1790 }
1791 else
1792 {
1793 // TODO: If GetIconLocation succeeded, why are we setting GIL_NOTFILENAME? And are we not PERINSTANCE?
1794 *pwFlags = GIL_NOTFILENAME | GIL_PERCLASS;
1795 }
1796
1797 return hr;
1798}
1799
1801CShellLink::Extract(PCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
1802{
1803 HRESULT hr = NOERROR;
1804 UINT cxyLarge = LOWORD(nIconSize), cxySmall = HIWORD(nIconSize);
1805
1806 if (phiconLarge)
1807 {
1808 *phiconLarge = NULL;
1809 PrivateExtractIconsW(pszFile, nIconIndex, cxyLarge, cxyLarge, phiconLarge, NULL, 1, 0);
1810
1811 if (*phiconLarge == NULL)
1812 hr = S_FALSE;
1813 }
1814
1815 if (phiconSmall)
1816 {
1817 *phiconSmall = NULL;
1818 PrivateExtractIconsW(pszFile, nIconIndex, cxySmall, cxySmall, phiconSmall, NULL, 1, 0);
1819
1820 if (*phiconSmall == NULL)
1821 hr = S_FALSE;
1822 }
1823
1824 if (hr == S_FALSE)
1825 {
1826 if (phiconLarge && *phiconLarge)
1827 {
1828 DestroyIcon(*phiconLarge);
1829 *phiconLarge = NULL;
1830 }
1831 if (phiconSmall && *phiconSmall)
1832 {
1833 DestroyIcon(*phiconSmall);
1834 *phiconSmall = NULL;
1835 }
1836 }
1837
1838 return hr;
1839}
1840
1841#if 0
1842/* Extends the functionality of PathUnExpandEnvStringsW */
1843BOOL PathFullyUnExpandEnvStringsW(
1844 _In_ LPCWSTR pszPath,
1845 _Out_ LPWSTR pszBuf,
1847{
1848 BOOL Ret = FALSE; // Set to TRUE as soon as PathUnExpandEnvStrings starts unexpanding.
1849 BOOL res;
1850 LPCWSTR p;
1851
1852 // *pszBuf = L'\0';
1853 while (*pszPath && cchBuf > 0)
1854 {
1855 /* Attempt unexpanding the path */
1856 res = PathUnExpandEnvStringsW(pszPath, pszBuf, cchBuf);
1857 if (!res)
1858 {
1859 /* The unexpansion failed. Try to find a path delimiter. */
1860 p = wcspbrk(pszPath, L" /\\:*?\"<>|%");
1861 if (!p) /* None found, we will copy the remaining path */
1862 p = pszPath + wcslen(pszPath);
1863 else /* Found one, we will copy the delimiter and skip it */
1864 ++p;
1865 /* If we overflow, we cannot unexpand more, so return FALSE */
1866 if (p - pszPath >= cchBuf)
1867 return FALSE; // *pszBuf = L'\0';
1868
1869 /* Copy the untouched portion of path up to the delimiter, included */
1870 wcsncpy(pszBuf, pszPath, p - pszPath);
1871 pszBuf[p - pszPath] = L'\0'; // NULL-terminate
1872
1873 /* Advance the pointers and decrease the remaining buffer size */
1874 cchBuf -= (p - pszPath);
1875 pszBuf += (p - pszPath);
1876 pszPath += (p - pszPath);
1877 }
1878 else
1879 {
1880 /*
1881 * The unexpansion succeeded. Skip the unexpanded part by trying
1882 * to find where the original path and the unexpanded string
1883 * become different.
1884 * NOTE: An alternative(?) would be to stop also at the last
1885 * path delimiter encountered in the loop (i.e. would be the
1886 * first path delimiter in the strings).
1887 */
1888 LPWSTR q;
1889
1890 /*
1891 * The algorithm starts at the end of the strings and loops back
1892 * while the characters are equal, until it finds a discrepancy.
1893 */
1894 p = pszPath + wcslen(pszPath);
1895 q = pszBuf + wcslen(pszBuf); // This wcslen should be < cchBuf
1896 while ((*p == *q) && (p > pszPath) && (q > pszBuf))
1897 {
1898 --p; --q;
1899 }
1900 /* Skip discrepancy */
1901 ++p; ++q;
1902
1903 /* Advance the pointers and decrease the remaining buffer size */
1904 cchBuf -= (q - pszBuf);
1905 pszBuf = q;
1906 pszPath = p;
1907
1908 Ret = TRUE;
1909 }
1910 }
1911
1912 return Ret;
1913}
1914#endif
1915
1917{
1918 HRESULT hr = E_FAIL;
1919 WCHAR szIconPath[MAX_PATH];
1920
1921 TRACE("(%p)->(path=%s iicon=%d)\n", this, debugstr_w(pszIconPath), iIcon);
1922
1923 if (pszIconPath)
1924 {
1925 /*
1926 * Check whether the user-given file path contains unexpanded
1927 * environment variables. If so, create a target environment block.
1928 * Note that in this block we will store the user-given path.
1929 * It will contain the unexpanded environment variables, but
1930 * it can also contain already expanded path that the user does
1931 * not want to see them unexpanded (e.g. so that they always
1932 * refer to the same place even if the would-be corresponding
1933 * environment variable could change).
1934 */
1935#ifdef ICON_LINK_WINDOWS_COMPAT
1936 /* Try to fully unexpand the icon path */
1937 // if (PathFullyUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath)))
1938 BOOL bSuccess = PathUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath));
1939 if (bSuccess && wcscmp(pszIconPath, szIconPath) != 0)
1940#else
1941 /*
1942 * In some situations, described in http://stackoverflow.com/questions/2976489/ishelllinkseticonlocation-translates-my-icon-path-into-program-files-which-i
1943 * the result of PathUnExpandEnvStringsW() could be wrong, and instead
1944 * one would have to store the actual provided icon location path, while
1945 * creating an icon environment block ONLY if that path already contains
1946 * environment variables. This is what the present case is trying to implement.
1947 */
1948 SHExpandEnvironmentStringsW(pszIconPath, szIconPath, _countof(szIconPath));
1949 if (wcscmp(pszIconPath, szIconPath) != 0)
1950#endif
1951 {
1952 /*
1953 * The user-given file path contains unexpanded environment
1954 * variables, so we need an icon environment block.
1955 */
1957 LPEXP_SZ_LINK pInfo;
1958
1959#ifdef ICON_LINK_WINDOWS_COMPAT
1960 /* Make pszIconPath point to the unexpanded path */
1961 LPCWSTR pszOrgIconPath = pszIconPath;
1962 pszIconPath = szIconPath;
1963#endif
1965 if (pInfo)
1966 {
1967 /* Make sure that the size of the structure is valid */
1968 if (pInfo->cbSize != sizeof(*pInfo))
1969 {
1970 ERR("Ooops. This structure is not as expected...\n");
1971
1972 /* Invalid structure, remove it altogether */
1973 m_Header.dwFlags &= ~SLDF_HAS_EXP_ICON_SZ;
1975
1976 /* Reset the pointer and go use the static buffer */
1977 pInfo = NULL;
1978 }
1979 }
1980 if (!pInfo)
1981 {
1982 /* Use the static buffer */
1983 pInfo = &buffer;
1984 buffer.cbSize = sizeof(buffer);
1985 buffer.dwSignature = EXP_SZ_ICON_SIG;
1986 }
1987
1988 lstrcpynW(pInfo->szwTarget, pszIconPath, _countof(pInfo->szwTarget));
1989 WideCharToMultiByte(CP_ACP, 0, pszIconPath, -1,
1990 pInfo->szTarget, _countof(pInfo->szTarget), NULL, NULL);
1991
1992 hr = S_OK;
1993 if (pInfo == &buffer)
1994 hr = AddDataBlock(pInfo);
1995 if (hr == S_OK)
1997
1998#ifdef ICON_LINK_WINDOWS_COMPAT
1999 /* Set pszIconPath back to the original one */
2000 pszIconPath = pszOrgIconPath;
2001#else
2002 /* Now, make pszIconPath point to the expanded path */
2003 pszIconPath = szIconPath;
2004#endif
2005 }
2006 else
2007 {
2008 /*
2009 * The user-given file path does not contain unexpanded environment
2010 * variables, so we need to remove any icon environment block.
2011 */
2012 m_Header.dwFlags &= ~SLDF_HAS_EXP_ICON_SZ;
2014
2015 /* pszIconPath points to the user path */
2016 }
2017 }
2018
2019#ifdef ICON_LINK_WINDOWS_COMPAT
2020 /* Store the original icon path location (may contain unexpanded environment strings) */
2021#endif
2022 if (pszIconPath)
2023 {
2024 m_Header.dwFlags &= ~SLDF_HAS_ICONLOCATION;
2026
2027 m_sIcoPath = strdupW(pszIconPath);
2028 if (!m_sIcoPath)
2029 return E_OUTOFMEMORY;
2030
2032 }
2033
2034 hr = S_OK;
2035
2036 m_Header.nIconIndex = iIcon;
2037 m_bDirty = TRUE;
2038
2039 return hr;
2040}
2041
2043{
2044 TRACE("(%p)->(path=%s %x)\n", this, debugstr_w(pszPathRel), dwReserved);
2045
2047 m_sPathRel = NULL;
2048
2049 if (pszPathRel)
2050 {
2051 m_sPathRel = strdupW(pszPathRel);
2052 if (!m_sPathRel)
2053 return E_OUTOFMEMORY;
2054 }
2055 m_bDirty = TRUE;
2056
2058}
2059
2061{
2062 if (!str)
2063 return NULL;
2064
2065 LPCWSTR p = wcschr(str, L':');
2066 if (!p)
2067 return NULL;
2068
2069 DWORD len = p - str;
2070 LPWSTR ret = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (len + 1));
2071 if (!ret)
2072 return ret;
2073
2074 memcpy(ret, str, sizeof(WCHAR)*len);
2075 ret[len] = 0;
2076 return ret;
2077}
2078
2080{
2082 LPEXP_DARWIN_LINK pInfo;
2083
2084 if ( (dwSig != EXP_DARWIN_ID_SIG)
2086 && (dwSig != EXP_LOGO3_ID_SIG)
2087#endif
2088 )
2089 {
2090 return E_INVALIDARG;
2091 }
2092
2093 if (!string)
2094 return S_FALSE;
2095
2097 if (pInfo)
2098 {
2099 /* Make sure that the size of the structure is valid */
2100 if (pInfo->dbh.cbSize != sizeof(*pInfo))
2101 {
2102 ERR("Ooops. This structure is not as expected...\n");
2103
2104 /* Invalid structure, remove it altogether */
2105 if (dwSig == EXP_DARWIN_ID_SIG)
2106 m_Header.dwFlags &= ~SLDF_HAS_DARWINID;
2107#if (NTDDI_VERSION < NTDDI_LONGHORN)
2108 else if (dwSig == EXP_LOGO3_ID_SIG)
2109 m_Header.dwFlags &= ~SLDF_HAS_LOGO3ID;
2110#endif
2111 RemoveDataBlock(dwSig);
2112
2113 /* Reset the pointer and go use the static buffer */
2114 pInfo = NULL;
2115 }
2116 }
2117 if (!pInfo)
2118 {
2119 /* Use the static buffer */
2120 pInfo = &buffer;
2121 buffer.dbh.cbSize = sizeof(buffer);
2122 buffer.dbh.dwSignature = dwSig;
2123 }
2124
2125 lstrcpynW(pInfo->szwDarwinID, string, _countof(pInfo->szwDarwinID));
2126 WideCharToMultiByte(CP_ACP, 0, string, -1,
2127 pInfo->szDarwinID, _countof(pInfo->szDarwinID), NULL, NULL);
2128
2129 HRESULT hr = S_OK;
2130 if (pInfo == &buffer)
2131 hr = AddDataBlock(pInfo);
2132 if (hr == S_OK)
2133 {
2134 if (dwSig == EXP_DARWIN_ID_SIG)
2136#if (NTDDI_VERSION < NTDDI_LONGHORN)
2137 else if (dwSig == EXP_LOGO3_ID_SIG)
2139#endif
2140 }
2141
2142 return hr;
2143}
2144
2146{
2147 HRESULT hr;
2148 LPCWSTR szComponent = NULL, szProduct = NULL, p;
2149 INT len;
2150 GUID guid;
2151 WCHAR szGuid[38+1];
2152
2154
2155 while (str[0])
2156 {
2157 /* each segment must start with two colons */
2158 if (str[0] != ':' || str[1] != ':')
2159 return E_FAIL;
2160
2161 /* the last segment is just two colons */
2162 if (!str[2])
2163 break;
2164 str += 2;
2165
2166 /* there must be a colon straight after a guid */
2167 p = wcschr(str, L':');
2168 if (!p)
2169 return E_FAIL;
2170 len = p - str;
2171 if (len != 38)
2172 return E_FAIL;
2173
2174 /* get the guid, and check if it's validly formatted */
2175 memcpy(szGuid, str, sizeof(WCHAR)*len);
2176 szGuid[len] = 0;
2177
2179 if (hr != S_OK)
2180 return hr;
2181 str = p + 1;
2182
2183 /* match it up to a guid that we care about */
2184 if (IsEqualGUID(guid, SHELL32_AdvtShortcutComponent) && !szComponent)
2185 szComponent = str; /* Darwin */
2186 else if (IsEqualGUID(guid, SHELL32_AdvtShortcutProduct) && !szProduct)
2187 szProduct = str; /* Logo3 */
2188 else
2189 return E_FAIL;
2190
2191 /* skip to the next field */
2192 str = wcschr(str, L':');
2193 if (!str)
2194 return E_FAIL;
2195 }
2196
2197 /* we have to have a component for an advertised shortcut */
2198 if (!szComponent)
2199 return E_FAIL;
2200
2201 szComponent = GetAdvertisedArg(szComponent);
2202 szProduct = GetAdvertisedArg(szProduct);
2203
2204 hr = WriteAdvertiseInfo(szComponent, EXP_DARWIN_ID_SIG);
2205 // if (FAILED(hr))
2206 // return hr;
2207#if (NTDDI_VERSION < NTDDI_LONGHORN)
2208 hr = WriteAdvertiseInfo(szProduct, EXP_LOGO3_ID_SIG);
2209 // if (FAILED(hr))
2210 // return hr;
2211#endif
2212
2213 HeapFree(GetProcessHeap(), 0, (PVOID)szComponent);
2214 HeapFree(GetProcessHeap(), 0, (PVOID)szProduct);
2215
2216 if (TRACE_ON(shell))
2217 {
2219 TRACE("Component = %s\n", debugstr_w(sComponent));
2220#if (NTDDI_VERSION < NTDDI_LONGHORN)
2221 GetAdvertiseInfo(&sProduct, EXP_LOGO3_ID_SIG);
2222 TRACE("Product = %s\n", debugstr_w(sProduct));
2223#endif
2224 }
2225
2226 return S_OK;
2227}
2228
2230{
2231 HRESULT hr = S_OK;
2232 LPITEMIDLIST pidlNew = NULL;
2234
2235 /*
2236 * Not both 'pidl' and 'pszFile' should be set.
2237 * But either one or both can be NULL.
2238 */
2239 if (pidl && pszFile)
2240 return E_FAIL;
2241
2242 if (pidl)
2243 {
2244 /* Clone the PIDL */
2245 pidlNew = ILClone(pidl);
2246 if (!pidlNew)
2247 return E_FAIL;
2248 }
2249 else if (pszFile)
2250 {
2251 /* Build a PIDL for this path target */
2252 hr = SHILCreateFromPathW(pszFile, &pidlNew, NULL);
2253 if (FAILED(hr))
2254 {
2255 /* This failed, try to resolve the path, then create a simple PIDL */
2256
2259
2261 {
2262 hr = E_INVALIDARG;
2263 szPath[0] = 0;
2264 }
2265 else
2266 {
2267 hr = S_OK;
2269 // NOTE: Don't make it failed here even if pidlNew was NULL.
2270 // We don't fail on purpose even if SHSimpleIDListFromPathW returns NULL.
2271 // This behaviour has been verified with tests.
2272 }
2273 }
2274 }
2275 // else if (!pidl && !pszFile) { pidlNew = NULL; hr = S_OK; }
2276
2277 ILFree(m_pPidl);
2278 m_pPidl = pidlNew;
2279
2280 if (!pszFile)
2281 {
2282 if (SHGetPathFromIDListW(pidlNew, szPath))
2283 pszFile = szPath;
2284 }
2285
2286 // TODO: Fully update link info, tracker, file attribs...
2287
2288 // if (pszFile)
2289 if (!pszFile)
2290 {
2291 *szPath = L'\0';
2292 pszFile = szPath;
2293 }
2294
2295 /* Update the cached path (for link info) */
2297
2298 if (m_sPath)
2300
2301 m_sPath = strdupW(pszFile);
2302 if (!m_sPath)
2303 return E_OUTOFMEMORY;
2304
2305 m_bDirty = TRUE;
2306 return hr;
2307}
2308
2310{
2311 LPWSTR unquoted = NULL;
2312 HRESULT hr = S_OK;
2313
2314 TRACE("(%p)->(path=%s)\n", this, debugstr_w(pszFile));
2315
2316 if (!pszFile)
2317 return E_INVALIDARG;
2318
2319 /*
2320 * Allow upgrading Logo3 shortcuts (m_Header.dwFlags & SLDF_HAS_LOGO3ID),
2321 * but forbid upgrading Darwin ones.
2322 */
2324 return S_FALSE;
2325
2326 /* quotes at the ends of the string are stripped */
2327 SIZE_T len = wcslen(pszFile);
2328 if (pszFile[0] == L'"' && pszFile[len-1] == L'"')
2329 {
2330 unquoted = strdupW(pszFile);
2331 PathUnquoteSpacesW(unquoted);
2332 pszFile = unquoted;
2333 }
2334
2335 /* any other quote marks are invalid */
2336 if (wcschr(pszFile, L'"'))
2337 {
2338 hr = S_FALSE;
2339 goto end;
2340 }
2341
2342 /* Clear the cached path */
2344 m_sPath = NULL;
2345
2346 /* Check for an advertised target (Logo3 or Darwin) */
2347 if (SetAdvertiseInfo(pszFile) != S_OK)
2348 {
2349 /* This is not an advertised target, but a regular path */
2351
2352 /*
2353 * Check whether the user-given file path contains unexpanded
2354 * environment variables. If so, create a target environment block.
2355 * Note that in this block we will store the user-given path.
2356 * It will contain the unexpanded environment variables, but
2357 * it can also contain already expanded path that the user does
2358 * not want to see them unexpanded (e.g. so that they always
2359 * refer to the same place even if the would-be corresponding
2360 * environment variable could change).
2361 */
2362 if (*pszFile)
2364 else
2365 *szPath = L'\0';
2366
2367 if (*pszFile && (wcscmp(pszFile, szPath) != 0))
2368 {
2369 /*
2370 * The user-given file path contains unexpanded environment
2371 * variables, so we need a target environment block.
2372 */
2374 LPEXP_SZ_LINK pInfo;
2375
2377 if (pInfo)
2378 {
2379 /* Make sure that the size of the structure is valid */
2380 if (pInfo->cbSize != sizeof(*pInfo))
2381 {
2382 ERR("Ooops. This structure is not as expected...\n");
2383
2384 /* Invalid structure, remove it altogether */
2385 m_Header.dwFlags &= ~SLDF_HAS_EXP_SZ;
2387
2388 /* Reset the pointer and go use the static buffer */
2389 pInfo = NULL;
2390 }
2391 }
2392 if (!pInfo)
2393 {
2394 /* Use the static buffer */
2395 pInfo = &buffer;
2396 buffer.cbSize = sizeof(buffer);
2397 buffer.dwSignature = EXP_SZ_LINK_SIG;
2398 }
2399
2400 lstrcpynW(pInfo->szwTarget, pszFile, _countof(pInfo->szwTarget));
2401 WideCharToMultiByte(CP_ACP, 0, pszFile, -1,
2402 pInfo->szTarget, _countof(pInfo->szTarget), NULL, NULL);
2403
2404 hr = S_OK;
2405 if (pInfo == &buffer)
2406 hr = AddDataBlock(pInfo);
2407 if (hr == S_OK)
2409
2410 /* Now, make pszFile point to the expanded path */
2411 pszFile = szPath;
2412 }
2413 else
2414 {
2415 /*
2416 * The user-given file path does not contain unexpanded environment
2417 * variables, so we need to remove any target environment block.
2418 */
2419 m_Header.dwFlags &= ~SLDF_HAS_EXP_SZ;
2421
2422 /* pszFile points to the user path */
2423 }
2424
2425 /* Set the target */
2426 hr = SetTargetFromPIDLOrPath(NULL, pszFile);
2427 }
2428
2429 m_bDirty = TRUE;
2430
2431end:
2432 HeapFree(GetProcessHeap(), 0, unquoted);
2433 return hr;
2434}
2435
2437{
2438 if (SHAddDataBlock(&m_pDBList, (DATABLOCK_HEADER*)pDataBlock))
2439 {
2440 m_bDirty = TRUE;
2441 return S_OK;
2442 }
2443 return S_FALSE;
2444}
2445
2447{
2448 DATABLOCK_HEADER* pBlock;
2449 PVOID pDataBlock;
2450
2451 TRACE("%p %08x %p\n", this, dwSig, ppDataBlock);
2452
2453 *ppDataBlock = NULL;
2454
2455 pBlock = SHFindDataBlock(m_pDBList, dwSig);
2456 if (!pBlock)
2457 {
2458 ERR("unknown datablock %08x (not found)\n", dwSig);
2459 return E_FAIL;
2460 }
2461
2462 pDataBlock = LocalAlloc(LMEM_ZEROINIT, pBlock->cbSize);
2463 if (!pDataBlock)
2464 return E_OUTOFMEMORY;
2465
2466 CopyMemory(pDataBlock, pBlock, pBlock->cbSize);
2467
2468 *ppDataBlock = pDataBlock;
2469 return S_OK;
2470}
2471
2473{
2474 if (SHRemoveDataBlock(&m_pDBList, dwSig))
2475 {
2476 m_bDirty = TRUE;
2477 return S_OK;
2478 }
2479 return S_FALSE;
2480}
2481
2483{
2484 TRACE("%p %p\n", this, pdwFlags);
2485 *pdwFlags = m_Header.dwFlags;
2486 return S_OK;
2487}
2488
2490{
2491 if (m_Header.dwFlags == dwFlags)
2492 return S_FALSE;
2494 m_bDirty = TRUE;
2495 return S_OK;
2496}
2497
2498/**************************************************************************
2499 * CShellLink implementation of IShellExtInit::Initialize()
2500 *
2501 * Loads the shelllink from the dataobject the shell is pointing to.
2502 */
2504{
2505 TRACE("%p %p %p %p\n", this, pidlFolder, pdtobj, hkeyProgID);
2506
2507 if (!pdtobj)
2508 return E_FAIL;
2509
2510 FORMATETC format;
2511 format.cfFormat = CF_HDROP;
2512 format.ptd = NULL;
2513 format.dwAspect = DVASPECT_CONTENT;
2514 format.lindex = -1;
2515 format.tymed = TYMED_HGLOBAL;
2516
2517 STGMEDIUM stgm;
2518 HRESULT hr = pdtobj->GetData(&format, &stgm);
2519 if (FAILED(hr))
2520 return hr;
2521
2522 UINT count = DragQueryFileW((HDROP)stgm.hGlobal, -1, NULL, 0);
2523 if (count == 1)
2524 {
2525 count = DragQueryFileW((HDROP)stgm.hGlobal, 0, NULL, 0);
2526 count++;
2527 LPWSTR path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
2528 if (path)
2529 {
2530 count = DragQueryFileW((HDROP)stgm.hGlobal, 0, path, count);
2531 hr = Load(path, 0);
2533 }
2534 }
2535 ReleaseStgMedium(&stgm);
2536
2537 return S_OK;
2538}
2539
2541{
2542 INT id = 0;
2543
2544 TRACE("%p %p %u %u %u %u\n", this,
2545 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
2546
2547 if (!hMenu)
2548 return E_INVALIDARG;
2549
2552
2553 MENUITEMINFOW mii;
2554 ZeroMemory(&mii, sizeof(mii));
2555 mii.cbSize = sizeof(mii);
2557 mii.dwTypeData = strOpen.GetBuffer();
2558 mii.cch = wcslen(mii.dwTypeData);
2559 mii.wID = idCmdFirst + id++;
2561 mii.fType = MFT_STRING;
2562 if (!InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii))
2563 return E_FAIL;
2564
2566 mii.dwTypeData = strOpenFileLoc.GetBuffer();
2567 mii.cch = wcslen(mii.dwTypeData);
2568 mii.wID = idCmdFirst + id++;
2569 mii.fState = MFS_ENABLED;
2570 mii.fType = MFT_STRING;
2571 if (!InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii))
2572 return E_FAIL;
2573
2574 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, id);
2575}
2576
2578{
2579 // TODO: SHOpenFolderAndSelectItems
2580 WCHAR szParams[MAX_PATH + 64];
2581 StringCbPrintfW(szParams, sizeof(szParams), L"/select,%s", m_sPath);
2582
2583 INT_PTR ret;
2584 ret = reinterpret_cast<INT_PTR>(ShellExecuteW(NULL, NULL, L"explorer.exe", szParams,
2586 if (ret <= 32)
2587 {
2588 ERR("ret: %08lX\n", ret);
2589 return E_FAIL;
2590 }
2591
2592 return S_OK;
2593}
2594
2596{
2597 TRACE("%p %p\n", this, lpici);
2598
2599 if (lpici->cbSize < sizeof(CMINVOKECOMMANDINFO))
2600 return E_INVALIDARG;
2601
2602 // NOTE: We could use lpici->hwnd (certainly in case lpici->fMask doesn't contain CMIC_MASK_FLAG_NO_UI)
2603 // as the parent window handle... ?
2604 /* FIXME: get using interface set from IObjectWithSite?? */
2605 // NOTE: We might need an extended version of Resolve that provides us with paths...
2606 HRESULT hr = Resolve(lpici->hwnd, (lpici->fMask & CMIC_MASK_FLAG_NO_UI) ? SLR_NO_UI : 0);
2607 if (FAILED(hr))
2608 {
2609 TRACE("failed to resolve component error 0x%08x\n", hr);
2610 return hr;
2611 }
2612
2613 UINT idCmd = LOWORD(lpici->lpVerb);
2614 TRACE("idCmd: %d\n", idCmd);
2615
2616 switch (idCmd)
2617 {
2618 case IDCMD_OPEN:
2619 return DoOpen(lpici);
2621 return DoOpenFileLocation();
2622 default:
2623 return E_NOTIMPL;
2624 }
2625}
2626
2628{
2630 const BOOL unicode = IsUnicode(*lpici);
2631
2632 CStringW args;
2633 if (m_sArgs)
2634 args = m_sArgs;
2635
2636 if (unicode)
2637 {
2638 if (!StrIsNullOrEmpty(iciex->lpParametersW))
2639 {
2640 args += L' ';
2641 args += iciex->lpParametersW;
2642 }
2643 }
2644 else
2645 {
2646 CComHeapPtr<WCHAR> pszParams;
2647 if (!StrIsNullOrEmpty(lpici->lpParameters) && __SHCloneStrAtoW(&pszParams, lpici->lpParameters))
2648 {
2649 args += L' ';
2650 args += pszParams;
2651 }
2652 }
2653
2655 SHELLEXECUTEINFOW sei = { sizeof(sei) };
2658 sei.lpDirectory = m_sWorkDir;
2659 if (m_pPidl)
2660 {
2661 sei.lpIDList = m_pPidl;
2663 }
2664 else
2665 {
2666 sei.lpFile = m_sPath;
2668 {
2669 sei.fMask &= ~SEE_MASK_DOENVSUBST; // The link does not want to expand lpFile
2671 sei.lpDirectory = dir;
2672 }
2673 }
2674 sei.lpParameters = args;
2675 sei.lpClass = m_sLinkPath;
2677 if (lpici->nShow != SW_SHOWNORMAL && lpici->nShow != SW_SHOW)
2678 sei.nShow = lpici->nShow; // Allow invoker to override .lnk show mode
2679
2680 // Use the invoker specified working directory if the link did not specify one
2681 if (StrIsNullOrEmpty(sei.lpDirectory) || !PathEnvSubstIsDirectory(sei.lpDirectory))
2682 {
2683 LPCSTR pszDirA = lpici->lpDirectory;
2684 if (unicode && !StrIsNullOrEmpty(iciex->lpDirectoryW))
2685 sei.lpDirectory = iciex->lpDirectoryW;
2686 else if (pszDirA && SHAnsiToUnicode(pszDirA, dir, _countof(dir)))
2687 sei.lpDirectory = dir;
2688 }
2689
2690 sei.dwHotKey = lpici->dwHotKey;
2691 sei.fMask |= CmicFlagsToSeeFlags(lpici->fMask & CMIC_MASK_HOTKEY);
2692 if (m_Header.wHotKey)
2693 {
2695 sei.fMask |= SEE_MASK_HOTKEY;
2696 }
2697 return (ShellExecuteExW(&sei) ? S_OK : E_FAIL);
2698}
2699
2701{
2702 FIXME("%p %lu %u %p %p %u\n", this, idCmd, uType, pwReserved, pszName, cchMax);
2703 return E_NOTIMPL;
2704}
2705
2708{
2709 switch(uMsg)
2710 {
2711 case WM_INITDIALOG:
2712 if (lParam)
2713 {
2714 HWND hDlgCtrl = GetDlgItem(hwndDlg, IDC_SHORTEX_RUN_DIFFERENT);
2715 SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0);
2716 }
2717 return TRUE;
2718 case WM_COMMAND:
2719 {
2720 HWND hDlgCtrl = GetDlgItem(hwndDlg, IDC_SHORTEX_RUN_DIFFERENT);
2721 if (LOWORD(wParam) == IDOK)
2722 {
2723 if (SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED)
2724 EndDialog(hwndDlg, 1);
2725 else
2726 EndDialog(hwndDlg, 0);
2727 }
2728 else if (LOWORD(wParam) == IDCANCEL)
2729 {
2730 EndDialog(hwndDlg, -1);
2731 }
2733 {
2734 if (SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED)
2735 SendMessage(hDlgCtrl, BM_SETCHECK, BST_UNCHECKED, 0);
2736 else
2737 SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0);
2738 }
2739 }
2740 }
2741 return FALSE;
2742}
2743
2744static void GetTypeDescriptionByPath(PCWSTR pszFullPath, DWORD fAttributes, PWSTR szBuf, UINT cchBuf)
2745{
2746 if (fAttributes == INVALID_FILE_ATTRIBUTES && !PathFileExistsAndAttributesW(pszFullPath, &fAttributes))
2747 fAttributes = 0;
2748
2749 SHFILEINFOW fi;
2750 if (!SHGetFileInfoW(pszFullPath, fAttributes, &fi, sizeof(fi), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES))
2751 {
2752 ERR("SHGetFileInfoW failed for %ls (%lu)\n", pszFullPath, GetLastError());
2753 fi.szTypeName[0] = UNICODE_NULL;
2754 }
2755
2756 BOOL fFolder = (fAttributes & FILE_ATTRIBUTE_DIRECTORY);
2757 LPCWSTR pwszExt = fFolder ? L"" : PathFindExtensionW(pszFullPath);
2758 if (pwszExt[0])
2759 {
2760 if (!fi.szTypeName[0])
2761 StringCchPrintfW(szBuf, cchBuf, L"%s", pwszExt + 1);
2762 else
2763 StringCchPrintfW(szBuf, cchBuf, L"%s (%s)", fi.szTypeName, pwszExt);
2764 }
2765 else
2766 {
2767 StringCchPrintfW(szBuf, cchBuf, L"%s", fi.szTypeName);
2768 }
2769}
2770
2772{
2773 TRACE("CShellLink::OnInitDialog(hwnd %p hwndFocus %p lParam %p)\n", hwndDlg, hwndFocus, lParam);
2774
2776
2777 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,
2779
2780 m_bInInit = TRUE;
2782
2783 /* Get file information */
2784 // FIXME! FIXME! Shouldn't we use m_sIcoPath, m_Header.nIconIndex instead???
2785 SHFILEINFOW fi;
2786 if (!SHGetFileInfoW(m_sLinkPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME | SHGFI_ICON))
2787 {
2788 ERR("SHGetFileInfoW failed for %ls (%lu)\n", m_sLinkPath, GetLastError());
2789 fi.szTypeName[0] = L'\0';
2790 fi.hIcon = NULL;
2791 }
2792
2793 if (fi.hIcon)
2794 {
2795 if (m_hIcon)
2797 m_hIcon = fi.hIcon;
2799 }
2800 else
2801 {
2802 ERR("ExtractIconW failed %ls %d\n", m_sIcoPath, m_Header.nIconIndex);
2803 }
2804
2805 if (!SHGetFileInfoW(m_sLinkPath, 0, &fi, sizeof(fi), SHGFI_DISPLAYNAME))
2808
2809 /* Target type */
2810 if (m_sPath)
2811 {
2815 }
2816
2817 /* Target location */
2818 if (m_sPath)
2819 {
2824 }
2825
2826 /* Target path */
2827 if (m_sPath)
2828 {
2829 WCHAR newpath[MAX_PATH * 2];
2830 newpath[0] = UNICODE_NULL;
2831 if (wcschr(m_sPath, ' '))
2832 StringCchPrintfExW(newpath, _countof(newpath), NULL, NULL, 0, L"\"%ls\"", m_sPath);
2833 else
2834 StringCchCopyExW(newpath, _countof(newpath), m_sPath, NULL, NULL, 0);
2835
2836 if (m_sArgs && m_sArgs[0])
2837 {
2838 StringCchCatW(newpath, _countof(newpath), L" ");
2839 StringCchCatW(newpath, _countof(newpath), m_sArgs);
2840 }
2841 SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, newpath);
2842 }
2843
2844 /* Working dir */
2845 if (m_sWorkDir)
2847
2848 /* Description */
2849 if (m_sDescription)
2851
2852 /* Hot key */
2854
2855 /* Run */
2857 const DWORD runshowcmd[] = { SW_SHOWNORMAL, SW_SHOWMINNOACTIVE, SW_SHOWMAXIMIZED };
2858 HWND hRunCombo = GetDlgItem(hwndDlg, IDC_SHORTCUT_RUN_COMBO);
2859 for (UINT i = 0; i < _countof(runstrings); ++i)
2860 {
2862 if (!LoadStringW(shell32_hInstance, runstrings[i], buf, _countof(buf)))
2863 break;
2864
2865 int index = SendMessageW(hRunCombo, CB_ADDSTRING, 0, (LPARAM)buf);
2866 if (index < 0)
2867 continue;
2868 SendMessageW(hRunCombo, CB_SETITEMDATA, index, runshowcmd[i]);
2869 if (!i || m_Header.nShowCommand == runshowcmd[i])
2870 SendMessageW(hRunCombo, CB_SETCURSEL, index, 0);
2871 }
2872
2873 BOOL disablecontrols = FALSE;
2874 if (darwin)
2875 {
2876 disablecontrols = TRUE;
2879 }
2880 else
2881 {
2882 WCHAR path[MAX_PATH * 2];
2883 path[0] = UNICODE_NULL;
2885 if (FAILED(hr))
2886 hr = GetPath(path, _countof(path), NULL, 0);
2887#if DBG
2888 if (GetKeyState(VK_CONTROL) < 0) // Allow inspection of PIDL parsing path
2889 {
2890 hr = S_OK;
2891 path[0] = UNICODE_NULL;
2892 }
2893#endif
2894 if (hr != S_OK)
2895 {
2896 disablecontrols = TRUE;
2897 LPITEMIDLIST pidl;
2898 if (GetIDList(&pidl) == S_OK)
2899 {
2900 path[0] = UNICODE_NULL;
2901 SHGetNameAndFlagsW(pidl, SHGDN_FORADDRESSBAR | SHGDN_FORPARSING, path, _countof(path), NULL);
2904 ILRemoveLastID(pidl);
2905 path[0] = UNICODE_NULL;
2907 SHGetNameAndFlagsW(pidl, SHGDN_NORMAL, path, _countof(path), NULL);
2909 ILFree(pidl);
2910 }
2913 }
2914 else
2915 {
2916 ASSERT(FAILED(hr) || !(path[0] == ':' && path[1] == ':' && path[2] == '{'));
2917 }
2918 }
2919
2920 HWND hWndTarget = GetDlgItem(hwndDlg, IDC_SHORTCUT_TARGET_TEXT);
2921 EnableWindow(hWndTarget, !disablecontrols);
2922 PostMessage(hWndTarget, EM_SETSEL, 0, -1); // Fix caret bug when first opening the tab [CORE-20016]
2923
2924 /* auto-completion */
2925 SHAutoComplete(hWndTarget, SHACF_DEFAULT);
2927
2928 m_bInInit = FALSE;
2929
2930 return TRUE;
2931}
2932
2933void CShellLink::OnCommand(HWND hwndDlg, int id, HWND hwndCtl, UINT codeNotify)
2934{
2935 switch (id)
2936 {
2937 case IDC_SHORTCUT_FIND:
2939 return;
2940
2942 {
2943 SHFILEINFOW fi;
2945 WCHAR wszPath[MAX_PATH];
2946 *wszPath = UNICODE_NULL;
2947
2948 if (!StrIsNullOrEmpty(m_sIcoPath))
2949 {
2950 PWSTR pszPath = m_sIcoPath;
2951 if (*m_sIcoPath == '.') // Extension-only icon location, we need a fake path
2952 {
2953 if (SUCCEEDED(StringCchPrintfW(wszPath, _countof(wszPath), L"x:\\x%s", m_sIcoPath)) &&
2954 SHGetFileInfoW(wszPath, 0, &fi, sizeof(fi), SHGFI_ICONLOCATION | SHGFI_USEFILEATTRIBUTES))
2955 {
2956 pszPath = fi.szDisplayName; // The path is now a generic icon based
2957 IconIndex = fi.iIcon; // on the registry info of the file extension.
2958 }
2959 }
2960
2961 if (FAILED(StringCchCopyW(wszPath, _countof(wszPath), pszPath)))
2962 *wszPath = UNICODE_NULL;
2963 }
2964 else if (!StrIsNullOrEmpty(m_sPath))
2965 {
2966 FindExecutableW(m_sPath, NULL, wszPath);
2967 }
2968
2969 if (!*wszPath && m_pPidl)
2970 {
2971 if (SHGetFileInfoW((PWSTR)m_pPidl, 0, &fi, sizeof(fi), SHGFI_ICONLOCATION | SHGFI_PIDL) &&
2972 SUCCEEDED(StringCchCopyW(wszPath, _countof(wszPath), fi.szDisplayName)))
2973 {
2974 IconIndex = fi.iIcon;
2975 }
2976 }
2977
2978 if (PickIconDlg(hwndDlg, wszPath, _countof(wszPath), &IconIndex))
2979 {
2980 SetIconLocation(wszPath, IconIndex);
2981 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
2982
2983 HICON hIconLarge = CreateShortcutIcon(wszPath, IconIndex);
2984 if (hIconLarge)
2985 {
2986 if (m_hIcon)
2988 m_hIcon = hIconLarge;
2990 }
2991 }
2992 return;
2993 }
2994
2996 {
2998 if (result == 1 || result == 0)
2999 {
3000 if (m_bRunAs != result)
3001 {
3002 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
3003 }
3004
3005 m_bRunAs = result;
3006 }
3007 return;
3008 }
3009 }
3010 if (codeNotify == EN_CHANGE || codeNotify == CBN_SELCHANGE)
3011 {
3012 if (!m_bInInit)
3013 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
3014 }
3015}
3016
3017LRESULT CShellLink::OnNotify(HWND hwndDlg, int idFrom, LPNMHDR pnmhdr)
3018{
3019 WCHAR wszBuf[MAX_PATH];
3020 LPPSHNOTIFY lppsn = (LPPSHNOTIFY)pnmhdr;
3021
3022 if (lppsn->hdr.code == PSN_APPLY)
3023 {
3024 /* set working directory */
3025 GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_START_IN_EDIT, wszBuf, _countof(wszBuf));
3026 SetWorkingDirectory(wszBuf);
3027
3028 /* set link destination */
3029 HWND hWndTarget = GetDlgItem(hwndDlg, IDC_SHORTCUT_TARGET_TEXT);
3030 GetWindowTextW(hWndTarget, wszBuf, _countof(wszBuf));
3031 // Only set the path and arguments for filesystem targets (we can't verify other targets)
3032 if (IsWindowEnabled(hWndTarget))
3033 {
3034 LPWSTR lpszArgs = NULL;
3035 LPWSTR unquoted = wszBuf;
3036 StrTrimW(unquoted, L" ");
3037
3038 if (!PathFileExistsW(unquoted))
3039 {
3040 lpszArgs = PathGetArgsW(unquoted);
3041 PathRemoveArgsW(unquoted);
3042 StrTrimW(lpszArgs, L" ");
3043 }
3044 if (unquoted[0] == '"' && unquoted[wcslen(unquoted) - 1] == '"')
3045 PathUnquoteSpacesW(unquoted);
3046
3047 WCHAR *pwszExt = PathFindExtensionW(unquoted);
3048 if (!_wcsicmp(pwszExt, L".lnk"))
3049 {
3050 // TODO: SLDF_ALLOW_LINK_TO_LINK (Win7+)
3051 // FIXME load localized error msg
3052 MessageBoxW(hwndDlg, L"You cannot create a link to a shortcut", NULL, MB_ICONERROR);
3054 return TRUE;
3055 }
3056
3057 if (!PathFileExistsW(unquoted))
3058 {
3059 // FIXME load localized error msg
3060 MessageBoxW(hwndDlg, L"The specified file name in the target box is invalid", NULL, MB_ICONERROR);
3062 return TRUE;
3063 }
3064
3065 SetPath(unquoted);
3066 SetArguments(lpszArgs ? lpszArgs : L"\0");
3067 }
3068
3070
3072 if (index != CB_ERR)
3073 {
3075 }
3076
3077 TRACE("This %p m_sLinkPath %S\n", this, m_sLinkPath);
3081 return TRUE;
3082 }
3083 return FALSE;
3084}
3085
3087{
3088 if (m_hIcon)
3089 {
3091 m_hIcon = NULL;
3092 }
3093}
3094
3095/**************************************************************************
3096 * SH_ShellLinkDlgProc
3097 *
3098 * dialog proc of the shortcut property dialog
3099 */
3100
3103{
3104 LPPROPSHEETPAGEW ppsp;
3105 CShellLink *pThis = reinterpret_cast<CShellLink *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
3106
3107 switch (uMsg)
3108 {
3109 case WM_INITDIALOG:
3110 ppsp = (LPPROPSHEETPAGEW)lParam;
3111 if (ppsp == NULL)
3112 break;
3113
3114 pThis = reinterpret_cast<CShellLink *>(ppsp->lParam);
3115 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pThis);
3116 return pThis->OnInitDialog(hwndDlg, (HWND)(wParam), lParam);
3117
3118 case WM_NOTIFY:
3119 return pThis->OnNotify(hwndDlg, (int)wParam, (NMHDR *)lParam);
3120
3121 case WM_COMMAND:
3122 pThis->OnCommand(hwndDlg, LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
3123 break;
3124
3125 case WM_DESTROY:
3126 pThis->OnDestroy(hwndDlg);
3127 break;
3128
3129 default:
3130 break;
3131 }
3132
3133 return FALSE;
3134}
3135
3136/**************************************************************************
3137 * ShellLink_IShellPropSheetExt interface
3138 */
3139
3141{
3143 (LPARAM)this, NULL, &PropSheetPageLifetimeCallback<CShellLink>);
3144 HRESULT hr = AddPropSheetPage(hPage, pfnAddPage, lParam);
3146 return hr;
3147 else
3148 AddRef(); // For PropSheetPageLifetimeCallback
3149 enum { CShellLink_PageIndex_Shortcut = 0 };
3150 return 1 + CShellLink_PageIndex_Shortcut; // Make this page the default (one-based)
3151}
3152
3154{
3155 TRACE("(%p) (uPageID %u, pfnReplacePage %p lParam %p\n", this, uPageID, pfnReplacePage, lParam);
3156 return E_NOTIMPL;
3157}
3158
3160{
3161 TRACE("%p %p\n", this, punk);
3162
3163 m_site = punk;
3164
3165 return S_OK;
3166}
3167
3169{
3170 TRACE("%p %s %p\n", this, debugstr_guid(&iid), ppvSite);
3171
3172 if (m_site == NULL)
3173 return E_FAIL;
3174
3175 return m_site->QueryInterface(iid, ppvSite);
3176}
3177
3179 DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
3180{
3181 TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
3182
3183 if (*pdwEffect == DROPEFFECT_NONE)
3184 return S_OK;
3185
3187 if (SUCCEEDED(hr))
3188 hr = m_DropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect);
3189 else
3190 *pdwEffect = DROPEFFECT_NONE;
3191
3192 return S_OK;
3193}
3194
3196 DWORD *pdwEffect)
3197{
3198 TRACE("(%p)\n", this);
3199 HRESULT hr = S_OK;
3200 if (m_DropTarget)
3201 hr = m_DropTarget->DragOver(dwKeyState, pt, pdwEffect);
3202 return hr;
3203}
3204
3206{
3207 TRACE("(%p)\n", this);
3208 HRESULT hr = S_OK;
3209 if (m_DropTarget)
3210 {
3211 hr = m_DropTarget->DragLeave();
3213 }
3214
3215 return hr;
3216}
3217
3219 DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
3220{
3221 TRACE("(%p)\n", this);
3222 HRESULT hr = S_OK;
3223 if (m_DropTarget)
3224 hr = m_DropTarget->Drop(pDataObject, dwKeyState, pt, pdwEffect);
3225
3226 return hr;
3227}
3228
3229/**************************************************************************
3230 * IShellLink_ConstructFromFile
3231 */
3233{
3235 HRESULT hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IPersistFile, &ppf));
3236 if (FAILED(hr))
3237 return hr;
3238
3239 hr = ppf->Load(path, 0);
3240 if (FAILED(hr))
3241 return hr;
3242
3243 return ppf->QueryInterface(riid, ppv);
3244}
3245
3247{
3249 if (!ILGetDisplayNameExW(psf, pidl, path, 0))
3250 return E_FAIL;
3251
3253}
3254
3256{
3258 const COLORREF crMask = GetSysColor(COLOR_3DFACE);
3259 WCHAR wszLnkIcon[MAX_PATH];
3260 int lnk_idx;
3261 HDC hDC;
3263 HICON hIcon = NULL, hNewIcon = NULL, hShortcut;
3264
3265 if (HLM_GetIconW(IDI_SHELL_SHORTCUT - 1, wszLnkIcon, _countof(wszLnkIcon), &lnk_idx))
3266 {
3267 ::ExtractIconExW(wszLnkIcon, lnk_idx, &hShortcut, NULL, 1);
3268 }
3269 else
3270 {
3272 IMAGE_ICON, cx, cy, 0);
3273 }
3274
3275 ::ExtractIconExW(wszIconPath, IconIndex, &hIcon, NULL, 1);
3276 if (!hIcon || !hShortcut || !himl)
3277 goto cleanup;
3278
3280 if (hDC)
3281 {
3282 // create 32bpp bitmap
3283 BITMAPINFO bi;
3284 ZeroMemory(&bi, sizeof(bi));
3285 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
3286 bi.bmiHeader.biWidth = cx;
3287 bi.bmiHeader.biHeight = cy;
3288 bi.bmiHeader.biPlanes = 1;
3289 bi.bmiHeader.biBitCount = 32;
3290 LPVOID pvBits;
3291 HBITMAP hbm = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0);
3292 if (hbm)
3293 {
3294 // draw the icon image
3295 HGDIOBJ hbmOld = SelectObject(hDC, hbm);
3296 {
3297 HBRUSH hbr = CreateSolidBrush(crMask);
3298 RECT rc = { 0, 0, cx, cy };
3299 FillRect(hDC, &rc, hbr);
3300 DeleteObject(hbr);
3301
3302 DrawIconEx(hDC, 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL);
3303 DrawIconEx(hDC, 0, 0, hShortcut, cx, cy, 0, NULL, DI_NORMAL);
3304 }
3305 SelectObject(hDC, hbmOld);
3306
3307 INT iAdded = ImageList_AddMasked(himl, hbm, crMask);
3308 hNewIcon = ImageList_GetIcon(himl, iAdded, ILD_NORMAL | ILD_TRANSPARENT);
3309
3311 }
3312 DeleteDC(hDC);
3313 }
3314
3315cleanup:
3316 if (hIcon)
3318 if (hShortcut)
3319 DestroyIcon(hShortcut);
3320 if (himl)
3322
3323 return hNewIcon;
3324}
static HDC hDC
Definition: 3dtext.c:33
#define PRF_TRYPROGRAMEXTENSIONS
Definition: PathResolve.cpp:40
#define shell32_hInstance
UINT cchMax
#define __inline
Definition: _wctype.cpp:15
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
#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
HRESULT hr
Definition: delayimp.cpp:573
#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
HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid)
Definition: combase.c:1470
BOOL WINAPI ImageList_Destroy(HIMAGELIST himl)
Definition: imagelist.c:941
HICON WINAPI ImageList_GetIcon(HIMAGELIST himl, INT i, UINT fStyle)
Definition: imagelist.c:1981
INT WINAPI ImageList_AddMasked(HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
Definition: imagelist.c:573
HIMAGELIST WINAPI ImageList_Create(INT cx, INT cy, UINT flags, INT cInitial, INT cGrow)
Definition: imagelist.c:814
#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
static void cleanup(void)
Definition: main.c:1335
DWORD WINAPI ExpandEnvironmentStringsW(IN LPCWSTR lpSrc, IN LPWSTR lpDst, IN DWORD nSize)
Definition: environ.c:520
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:636
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:1752
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:183
void WINAPI PathUnquoteSpacesW(WCHAR *path)
Definition: path.c:2006
WCHAR *WINAPI PathFindFileNameW(const WCHAR *path)
Definition: path.c:1701
BOOL WINAPI PathRemoveFileSpecW(WCHAR *path)
Definition: path.c:1145
LPWSTR WINAPI PathFindExtensionW(const WCHAR *path)
Definition: path.c:1274
BOOL WINAPI PathUnExpandEnvStringsW(const WCHAR *path, WCHAR *buffer, UINT buf_len)
Definition: path.c:2705
WCHAR *WINAPI PathGetArgsW(const WCHAR *path)
Definition: path.c:1740
BOOL WINAPI PathFileExistsW(const WCHAR *path)
Definition: path.c:2607
BOOL WINAPI PathIsFileSpecW(const WCHAR *path)
Definition: path.c:1842
BOOL WINAPI StrTrimW(WCHAR *str, const WCHAR *trim)
Definition: string.c:796
GUID guid
Definition: version.c:147
DWORD WINAPI GetVersion(void)
Definition: version.c:1458
#define assert(_expr)
Definition: assert.h:32
_ACRTIMP wchar_t *__cdecl wcspbrk(const wchar_t *, const wchar_t *)
Definition: wcs.c:2016
_ACRTIMP int __cdecl _wcsicmp(const wchar_t *, const wchar_t *)
Definition: wcs.c:159
_ACRTIMP size_t __cdecl wcslen(const wchar_t *)
Definition: wcs.c:2983
_ACRTIMP int __cdecl wcscmp(const wchar_t *, const wchar_t *)
Definition: wcs.c:1972
void WINAPI ReleaseStgMedium(STGMEDIUM *pmedium)
Definition: ole2.c:2014
static const WCHAR IconIndex[]
Definition: install.c:52
BOOL WINAPI PickIconDlg(HWND hWndOwner, LPWSTR lpstrFile, UINT nMaxFile, INT *lpdwIconIndex)
Definition: dialogs.cpp:352
HRESULT SHGetNameAndFlagsW(_In_ LPCITEMIDLIST pidl, _In_ DWORD dwFlags, _Out_opt_ LPWSTR pszText, _In_ UINT cchBuf, _Inout_opt_ DWORD *pdwAttributes)
Definition: utils.cpp:575
const GUID SHELL32_AdvtShortcutProduct
static HRESULT AddPropSheetPage(HPROPSHEETPAGE hPage, LPFNSVADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
Definition: precomp.h:155
EXTERN_C HRESULT SHELL_GetUIObjectOfAbsoluteItem(_In_opt_ HWND hWnd, _In_ PCIDLIST_ABSOLUTE pidl, _In_ REFIID riid, _Out_ void **ppvObj)
Definition: utils.cpp:452
const GUID SHELL32_AdvtShortcutComponent
void WINAPI SHFree(LPVOID pv)
Definition: shellole.c:370
UINT WINAPI DragQueryFileW(HDROP hDrop, UINT lFile, LPWSTR lpszwFile, UINT lLength)
Definition: shellole.c:666
LPVOID WINAPI SHAlloc(SIZE_T len)
Definition: shellole.c:348
BOOL WINAPI PathResolveW(_Inout_ LPWSTR path, _Inout_opt_ LPCWSTR *dirs, _In_ DWORD flags)
Definition: shellpath.c:1032
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:487
void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
Definition: path.c:782
BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr)
Definition: path.c:1879
DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
Definition: string.c:2803
#define FAILED_UNEXPECTEDLY
Definition: utils.cpp:30
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define MAKE_HRESULT(sev, fac, code)
Definition: dmerror.h:29
#define pt(x, y)
Definition: drawing.c:79
return ret
Definition: mutex.c:146
#define L(x)
Definition: resources.c:13
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
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
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:855
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 LOBYTE(W)
Definition: jmemdos.c:487
#define NTDDI_VERSION
Definition: k32.h:35
#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:1001
if(dx< 0)
Definition: linetemp.h:194
void *WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: malloc.c:381
#define ZeroMemory
Definition: minwinbase.h:31
#define LMEM_ZEROINIT
Definition: minwinbase.h:85
#define CopyMemory
Definition: minwinbase.h:29
LONG_PTR LPARAM
Definition: minwindef.h:175
LONG_PTR LRESULT
Definition: minwindef.h:176
UINT_PTR WPARAM
Definition: minwindef.h:174
#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:149
static const WCHAR szGuid[]
Definition: rtlstr.c:1928
static BSTR *static LPOLESTR
Definition: varformat.c:44
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:60
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
_In_ LPWSTR _In_ DWORD _In_ DWORD _In_ DWORD dwFlags
Definition: netsh.h:141
#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 MAKEINTRESOURCE(i)
Definition: ntverrsrc.c:25
#define STGM_CREATE
Definition: objbase.h:945
#define STGM_READWRITE
Definition: objbase.h:938
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:942
#define STGM_SHARE_DENY_WRITE
Definition: objbase.h:941
#define STGM_READ
Definition: objbase.h:936
#define PathAddBackslashW
Definition: pathcch.h:302
#define LOWORD(l)
Definition: pedump.c:82
short WCHAR
Definition: pedump.c:58
unsigned short USHORT
Definition: pedump.c:61
LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner, int nFolder, BOOL fCreate)
Definition: pidl.c:446
LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl)
Definition: pidl.c:238
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:1051
HRESULT WINAPI SHILCreateFromPathW(LPCWSTR path, LPITEMIDLIST *ppidl, DWORD *attributes)
Definition: pidl.c:404
LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:817
BOOL WINAPI ILRemoveLastID(LPITEMIDLIST pidl)
Definition: pidl.c:222
HRESULT WINAPI ILSaveToStream(IStream *pStream, LPCITEMIDLIST pPidl)
Definition: pidl.c:354
UINT WINAPI ILGetSize(LPCITEMIDLIST pidl)
Definition: pidl.c:941
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1496
HRESULT WINAPI ILLoadFromStream(IStream *pStream, LPITEMIDLIST *ppPidl)
Definition: pidl.c:294
LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath)
Definition: pidl.c:1245
BOOL ILGetDisplayNameExW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPWSTR path, DWORD type)
Definition: pidl.c:101
#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
_In_ HBITMAP hbm
Definition: ntgdi.h:2776
#define PathRemoveBackslash
Definition: shlwapi.h:501
_In_opt_ IUnknown * punk
Definition: shlwapi.h:158
#define SHACF_DEFAULT
Definition: shlwapi.h:45
_In_ UINT cchBuf
Definition: shlwapi.h:378
#define PathIsDirectory
Definition: shlwapi.h:477
#define WM_NOTIFY
Definition: richedit.h:61
const WCHAR * str
static calc_node_t temp
Definition: rpn_ieee.c:38
wcsncpy
wcscpy
#define LoadStringW
Definition: utils.h:64
#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:223
#define SEE_MASK_DOENVSUBST
Definition: shellapi.h:37
_In_ UINT _In_ UINT cch
Definition: shellapi.h:432
#define SHGFI_ICONLOCATION
Definition: shellapi.h:169
#define SHGFI_DISPLAYNAME
Definition: shellapi.h:166
#define SEE_MASK_HOTKEY
Definition: shellapi.h:32
#define SEE_MASK_UNICODE
Definition: shellapi.h:40
#define SHGFI_ICON
Definition: shellapi.h:164
#define SHGFI_TYPENAME
Definition: shellapi.h:167
#define SHGFI_USEFILEATTRIBUTES
Definition: shellapi.h:181
#define SEE_MASK_ASYNCOK
Definition: shellapi.h:43
#define SEE_MASK_NOASYNC
Definition: shellapi.h:35
_In_ LPCSTR pszDir
Definition: shellapi.h:601
#define SHGFI_PIDL
Definition: shellapi.h:180
#define SEE_MASK_INVOKEIDLIST
Definition: shellapi.h:28
#define SEE_MASK_FLAG_NO_UI
Definition: shellapi.h:38
HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
Definition: shlexec.cpp:1581
HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
Definition: shlexec.cpp:2778
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:2723
EXTERN_C HRESULT WINAPI SHOpenFolderAndSelectItems(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD dwFlags)
Definition: shlfolder.cpp:551
#define EXP_DARWIN_ID_SIG
Definition: shlobj.h:2063
#define SHCNE_UPDATEITEM
Definition: shlobj.h:1910
struct EXP_DARWIN_LINK * LPEXP_DARWIN_LINK
#define SHCNE_CREATE
Definition: shlobj.h:1898
#define EXP_SZ_LINK_SIG
Definition: shlobj.h:2059
@ SLDF_HAS_RELPATH
Definition: shlobj.h:1955
@ SLDF_HAS_EXP_SZ
Definition: shlobj.h:1961
@ SLDF_HAS_ID_LIST
Definition: shlobj.h:1952
@ SLDF_HAS_DARWINID
Definition: shlobj.h:1966
@ SLDF_RUN_IN_SEPARATE
Definition: shlobj.h:1962
@ SLDF_HAS_LINK_INFO
Definition: shlobj.h:1953
@ SLDF_HAS_WORKINGDIR
Definition: shlobj.h:1956
@ SLDF_HAS_ARGS
Definition: shlobj.h:1957
@ SLDF_FORCE_NO_LINKINFO
Definition: shlobj.h:1960
@ SLDF_HAS_EXP_ICON_SZ
Definition: shlobj.h:1968
@ SLDF_RUNAS_USER
Definition: shlobj.h:1967
@ SLDF_UNICODE
Definition: shlobj.h:1959
@ SLDF_RUN_WITH_SHIMLAYER
Definition: shlobj.h:1971
@ SLDF_HAS_ICONLOCATION
Definition: shlobj.h:1958
@ SLDF_HAS_NAME
Definition: shlobj.h:1954
#define EXP_SZ_ICON_SIG
Definition: shlobj.h:2067
#define EXP_SPECIAL_FOLDER_SIG
Definition: shlobj.h:2062
#define SHCNF_PATHW
Definition: shlobj.h:1933
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
DWORD WINAPI SHExpandEnvironmentStringsW(LPCWSTR, LPWSTR, DWORD)
#define IDC_SHORTCUT_FIND
Definition: shresdef.h:518
#define IDS_SHORTCUT_RUN_MAX
Definition: shresdef.h:263
#define IDC_SHORTCUT_ADVANCED
Definition: shresdef.h:520
#define IDS_OPEN_VERB
Definition: shresdef.h:212
#define IDC_SHORTCUT_RUN_COMBO
Definition: shresdef.h:515
#define IDS_OPENFILELOCATION
Definition: shresdef.h:246
#define IDS_SHORTCUT_RUN_MIN
Definition: shresdef.h:262
#define IDC_SHORTCUT_LOCATION_EDIT
Definition: shresdef.h:507
#define IDC_SHORTCUT_TEXT
Definition: shresdef.h:503
#define IDC_SHORTCUT_TARGET_TEXT
Definition: shresdef.h:509
#define IDC_SHORTCUT_ICON
Definition: shresdef.h:502
#define IDC_SHORTCUT_KEY_HOTKEY
Definition: shresdef.h:513
#define IDC_SHORTEX_RUN_DIFFERENT
Definition: shresdef.h:523
#define IDI_SHELL_SHORTCUT
Definition: shresdef.h:623
#define IDS_SHORTCUT_RUN_NORMAL
Definition: shresdef.h:261
#define IDD_SHORTCUT_PROPERTIES
Definition: shresdef.h:443
#define IDC_SHORTCUT_CHANGE_ICON
Definition: shresdef.h:519
#define IDD_SHORTCUT_EXTENDED_PROPERTIES
Definition: shresdef.h:449
#define IDC_SHORTCUT_TYPE_EDIT
Definition: shresdef.h:505
#define IDC_SHORTCUT_COMMENT_EDIT
Definition: shresdef.h:517
#define IDC_SHORTCUT_START_IN_EDIT
Definition: shresdef.h:511
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:2049
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:340
LPCWSTR lpParameters
Definition: shellapi.h:339
WCHAR szTypeName[80]
Definition: shellapi.h:388
WCHAR szDisplayName[MAX_PATH]
Definition: shellapi.h:387
HICON hIcon
Definition: shellapi.h:384
FILETIME ftLastWriteTime
Definition: minwinbase.h:286
_Field_z_ WCHAR cAlternateFileName[14]
Definition: minwinbase.h:292
_Field_z_ WCHAR cFileName[MAX_PATH]
Definition: minwinbase.h:291
DWORD dwFileAttributes
Definition: minwinbase.h:283
FILETIME ftLastAccessTime
Definition: minwinbase.h:285
FILETIME ftCreationTime
Definition: minwinbase.h:284
Definition: match.c:390
uint16_t size
Definition: btrfs_drv.h:563
Definition: fci.c:116
Definition: format.c:58
Definition: heap.c:86
USHORT biBitCount
Definition: precomp.h:34
BITMAPINFOHEADER bmiHeader
Definition: wingdi.h:1922
LPWSTR dwTypeData
Definition: winuser.h:3377
UINT code
Definition: winuser.h:3267
Definition: tools.h:99
WCHAR label[12]
Definition: CShellLink.cpp:184
#define max(a, b)
Definition: svc.c:63
#define GetWindowLongPtr
Definition: treelist.c:73
#define SetWindowLongPtr
Definition: treelist.c:70
uint16_t * PWSTR
Definition: typedefs.h:56
const char * LPCSTR
Definition: typedefs.h:52
int32_t INT_PTR
Definition: typedefs.h:64
char * PSTR
Definition: typedefs.h:51
const uint16_t * PCWSTR
Definition: typedefs.h:57
const uint16_t * LPCWSTR
Definition: typedefs.h:57
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
uint16_t * LPWSTR
Definition: typedefs.h:56
ULONG_PTR SIZE_T
Definition: typedefs.h:80
char * LPSTR
Definition: typedefs.h:51
int32_t INT
Definition: typedefs.h:58
const char * PCSTR
Definition: typedefs.h:52
#define MAXUSHORT
Definition: typedefs.h:83
uint32_t ULONG
Definition: typedefs.h:59
#define HIWORD(l)
Definition: typedefs.h:247
#define SEE_MASK_HASLINKNAME
Definition: undocshell.h:737
WORD WORD PSZ PSZ pszFileName
Definition: vdmdbg.h:44
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
HPROPSHEETPAGE SH_CreatePropertySheetPageEx(WORD wDialogId, DLGPROC pfnDlgProc, LPARAM lParam, LPCWSTR pwszTitle, LPFNPSPCALLBACK Callback)
Definition: propsheet.cpp:223
HBITMAP WINAPI CreateDIBSection(HDC hDC, CONST BITMAPINFO *BitmapInfo, UINT Usage, VOID **Bits, HANDLE hSection, DWORD dwOffset)
Definition: bitmap.c:245
UINT WINAPI GetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount)
Definition: dialog.c:2263
int WINAPI GetWindowTextW(HWND hWnd, LPWSTR lpString, int nMaxCount)
Definition: window.c:1382
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
DWORD COLORREF
Definition: windef.h:100
#define WINAPI
Definition: msvc.h:6
#define STG_E_INVALIDPOINTER
Definition: winerror.h:3666
#define S_FALSE
Definition: winerror.h:3451
#define SEVERITY_SUCCESS
Definition: winerror.h:177
#define NOERROR
Definition: winerror.h:3448
#define E_POINTER
Definition: winerror.h:3480
#define DIB_RGB_COLORS
Definition: wingdi.h:367
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1546
#define DI_NORMAL
Definition: wingdi.h:72
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
int WINAPI FillRect(HDC, LPCRECT, HBRUSH)
HBRUSH WINAPI CreateSolidBrush(_In_ COLORREF)
BOOL WINAPI DeleteDC(_In_ HDC)
#define DATE_SHORTDATE
Definition: winnls.h:209
#define SW_SHOWNORMAL
Definition: winuser.h:781
#define SW_SHOWMAXIMIZED
Definition: winuser.h:784
DWORD WINAPI GetSysColor(_In_ int)
#define CB_SETITEMDATA
Definition: winuser.h:1995
#define DWLP_USER
Definition: winuser.h:883
#define MIIM_ID
Definition: winuser.h:733
#define STM_SETICON
Definition: winuser.h:2128
#define IDCANCEL
Definition: winuser.h:842
#define BST_UNCHECKED
Definition: winuser.h:199
#define IMAGE_ICON
Definition: winuser.h:212
UINT WINAPI PrivateExtractIconsW(_In_reads_(MAX_PATH) LPCWSTR szFileName, _In_ int nIconIndex, _In_ int cxIcon, _In_ int cyIcon, _Out_writes_opt_(nIcons) HICON *phicon, _Out_writes_opt_(nIcons) UINT *piconid, _In_ UINT nIcons, _In_ UINT flags)
#define WM_COMMAND
Definition: winuser.h:1768
#define CB_ERR
Definition: winuser.h:2471
HANDLE WINAPI LoadImageW(_In_opt_ HINSTANCE hInst, _In_ LPCWSTR name, _In_ UINT type, _In_ int cx, _In_ int cy, _In_ UINT fuLoad)
Definition: cursoricon.c:2572
#define CB_SETCURSEL
Definition: winuser.h:1990
#define VK_CONTROL
Definition: winuser.h:2239
BOOL WINAPI SetDlgItemTextW(_In_ HWND, _In_ int, _In_ LPCWSTR)
#define WM_INITDIALOG
Definition: winuser.h:1767
int WINAPI MessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType)
HWND WINAPI GetDlgItem(_In_opt_ HWND, _In_ int)
#define IDOK
Definition: winuser.h:841
#define CBN_SELCHANGE
Definition: winuser.h:2008
#define BM_SETCHECK
Definition: winuser.h:1950
#define MIIM_STATE
Definition: winuser.h:732
LRESULT WINAPI SendDlgItemMessageW(_In_ HWND, _In_ int, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define MFS_DEFAULT
Definition: winuser.h:759
#define MB_ICONERROR
Definition: winuser.h:798
#define SM_CYICON
Definition: winuser.h:984
BOOL WINAPI DrawIconEx(_In_ HDC, _In_ int, _In_ int, _In_ HICON, _In_ int, _In_ int, _In_ UINT, _In_opt_ HBRUSH, _In_ UINT)
Definition: cursoricon.c:2397
#define CB_ADDSTRING
Definition: winuser.h:1965
#define CB_GETITEMDATA
Definition: winuser.h:1979
#define SendMessage
Definition: winuser.h:6009
BOOL WINAPI EnableWindow(_In_ HWND, _In_ BOOL)
#define EM_SETSEL
Definition: winuser.h:2047
#define MFS_ENABLED
Definition: winuser.h:761
BOOL WINAPI IsWindowEnabled(_In_ HWND)
#define PostMessage
Definition: winuser.h:5998
HWND WINAPI GetParent(_In_ HWND)
#define DWLP_MSGRESULT
Definition: winuser.h:881
#define MFT_STRING
Definition: winuser.h:757
#define SW_SHOW
Definition: winuser.h:786
#define WM_DESTROY
Definition: winuser.h:1637
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define CB_GETCURSEL
Definition: winuser.h:1972
#define SM_CXICON
Definition: winuser.h:983
int WINAPI GetSystemMetrics(_In_ int)
#define SW_SHOWMINNOACTIVE
Definition: winuser.h:788
#define MIIM_TYPE
Definition: winuser.h:736
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define BST_CHECKED
Definition: winuser.h:197
BOOL WINAPI InsertMenuItemW(_In_ HMENU, _In_ UINT, _In_ BOOL, _In_ LPCMENUITEMINFOW)
SHORT WINAPI GetKeyState(_In_ int)
INT_PTR WINAPI DialogBoxParamW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_opt_ HWND, _In_opt_ DLGPROC, _In_ LPARAM)
#define BM_GETCHECK
Definition: winuser.h:1947
BOOL WINAPI EndDialog(_In_ HWND, _In_ INT_PTR)
BOOL WINAPI DestroyIcon(_In_ HICON)
Definition: cursoricon.c:2422
#define EN_CHANGE
Definition: winuser.h:2051
#define COLOR_3DFACE
Definition: winuser.h:940
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
#define IID_PPV_ARG(Itype, ppType)