xref: /reactos/dll/cpl/appwiz/createlink.c (revision 1734f297)
1 /*
2  * PROJECT:         ReactOS Software Control Panel
3  * FILE:            dll/cpl/appwiz/createlink.c
4  * PURPOSE:         ReactOS Software Control Panel
5  * PROGRAMMER:      Gero Kuehn (reactos.filter@gkware.com)
6  *                  Dmitry Chapyshev (lentind@yandex.ru)
7  *                  Johannes Anderwald
8  *                  Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
9  * UPDATE HISTORY:
10  *      06-17-2004  Created
11  */
12 
13 #include "appwiz.h"
14 #include <commctrl.h>
15 #include <shellapi.h>
16 #include <strsafe.h>
17 
18 BOOL
19 IsShortcut(HKEY hKey)
20 {
21     WCHAR Value[10];
22     DWORD Size;
23     DWORD Type;
24 
25     Size = sizeof(Value);
26     if (RegQueryValueExW(hKey, L"IsShortcut", NULL, &Type, (LPBYTE)Value, &Size) != ERROR_SUCCESS)
27         return FALSE;
28 
29     if (Type != REG_SZ)
30         return FALSE;
31 
32     return (wcsicmp(Value, L"yes") == 0);
33 }
34 
35 BOOL
36 IsExtensionAShortcut(LPWSTR lpExtension)
37 {
38     HKEY hKey;
39     WCHAR Buffer[100];
40     DWORD Size;
41     DWORD Type;
42 
43     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, lpExtension, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
44         return FALSE;
45 
46     if (IsShortcut(hKey))
47     {
48         RegCloseKey(hKey);
49         return TRUE;
50     }
51 
52     Size = sizeof(Buffer);
53     if (RegQueryValueEx(hKey, NULL, NULL, &Type, (LPBYTE)Buffer, &Size) != ERROR_SUCCESS || Type != REG_SZ)
54     {
55         RegCloseKey(hKey);
56         return FALSE;
57     }
58 
59     RegCloseKey(hKey);
60 
61     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Buffer, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
62         return FALSE;
63 
64     if (IsShortcut(hKey))
65     {
66         RegCloseKey(hKey);
67         return TRUE;
68     }
69 
70     RegCloseKey(hKey);
71     return FALSE;
72 }
73 
74 BOOL
75 CreateShortcut(PCREATE_LINK_CONTEXT pContext)
76 {
77     IShellLinkW *pShellLink, *pSourceShellLink;
78     IPersistFile *pPersistFile;
79     HRESULT hr;
80     WCHAR Path[MAX_PATH];
81     LPWSTR lpExtension;
82 
83     /* get the extension */
84     lpExtension = PathFindExtensionW(pContext->szTarget);
85 
86     if (IsExtensionAShortcut(lpExtension))
87     {
88         hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_ALL, &IID_IShellLinkW, (void**)&pSourceShellLink);
89 
90         if (FAILED(hr))
91             return FALSE;
92 
93         hr = IUnknown_QueryInterface(pSourceShellLink, &IID_IPersistFile, (void**)&pPersistFile);
94         if (FAILED(hr))
95         {
96             IUnknown_Release(pSourceShellLink);
97             return FALSE;
98         }
99 
100         hr = pPersistFile->lpVtbl->Load(pPersistFile, (LPCOLESTR)pContext->szTarget, STGM_READ);
101         IUnknown_Release(pPersistFile);
102 
103         if (FAILED(hr))
104         {
105             IUnknown_Release(pSourceShellLink);
106             return FALSE;
107         }
108 
109         hr = IShellLinkW_GetPath(pSourceShellLink, Path, _countof(Path), NULL, 0);
110         IUnknown_Release(pSourceShellLink);
111 
112         if (FAILED(hr))
113         {
114             return FALSE;
115         }
116     }
117     else
118     {
119         StringCchCopyW(Path, _countof(Path), pContext->szTarget);
120     }
121 
122     hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_ALL,
123                           &IID_IShellLinkW, (void**)&pShellLink);
124 
125     if (hr != S_OK)
126         return FALSE;
127 
128     pShellLink->lpVtbl->SetPath(pShellLink, Path);
129     pShellLink->lpVtbl->SetDescription(pShellLink, pContext->szDescription);
130     pShellLink->lpVtbl->SetWorkingDirectory(pShellLink, pContext->szWorkingDirectory);
131 
132     hr = IUnknown_QueryInterface(pShellLink, &IID_IPersistFile, (void**)&pPersistFile);
133     if (hr != S_OK)
134     {
135         IUnknown_Release(pShellLink);
136         return FALSE;
137     }
138 
139     hr = pPersistFile->lpVtbl->Save(pPersistFile, pContext->szLinkName, TRUE);
140     IUnknown_Release(pPersistFile);
141     IUnknown_Release(pShellLink);
142     return (hr == S_OK);
143 }
144 
145 BOOL
146 CreateInternetShortcut(PCREATE_LINK_CONTEXT pContext)
147 {
148     IUniformResourceLocatorW *pURL = NULL;
149     IPersistFile *pPersistFile = NULL;
150     HRESULT hr;
151     WCHAR szPath[MAX_PATH];
152     GetFullPathNameW(pContext->szLinkName, _countof(szPath), szPath, NULL);
153 
154     hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL,
155                           &IID_IUniformResourceLocatorW, (void **)&pURL);
156     if (FAILED(hr))
157         return FALSE;
158 
159     hr = IUnknown_QueryInterface(pURL, &IID_IPersistFile, (void **)&pPersistFile);
160     if (FAILED(hr))
161     {
162         IUnknown_Release(pURL);
163         return FALSE;
164     }
165 
166     pURL->lpVtbl->SetURL(pURL, pContext->szTarget, 0);
167 
168     hr = pPersistFile->lpVtbl->Save(pPersistFile, szPath, TRUE);
169 
170     IUnknown_Release(pPersistFile);
171     IUnknown_Release(pURL);
172 
173     return SUCCEEDED(hr);
174 }
175 
176 BOOL IsInternetLocation(LPCWSTR pszLocation)
177 {
178     return (PathIsURLW(pszLocation) || wcsstr(pszLocation, L"www.") == pszLocation);
179 }
180 
181 /* Remove all invalid characters from the name */
182 void
183 DoConvertNameForFileSystem(LPWSTR szName)
184 {
185     LPWSTR pch1, pch2;
186     for (pch1 = pch2 = szName; *pch1; ++pch1)
187     {
188         if (wcschr(L"\\/:*?\"<>|", *pch1) != NULL)
189         {
190             /* *pch1 is an invalid character */
191             continue;
192         }
193         *pch2 = *pch1;
194         ++pch2;
195     }
196     *pch2 = 0;
197 }
198 
199 BOOL
200 DoValidateShortcutName(PCREATE_LINK_CONTEXT pContext)
201 {
202     SIZE_T cch;
203     LPCWSTR pch, pszName = pContext->szDescription;
204 
205     if (!pszName || !pszName[0])
206         return FALSE;
207 
208     cch = wcslen(pContext->szOrigin) + wcslen(pszName) + 1;
209     if (cch >= MAX_PATH)
210         return FALSE;
211 
212     pch = pszName;
213     for (pch = pszName; *pch; ++pch)
214     {
215         if (wcschr(L"\\/:*?\"<>|", *pch) != NULL)
216         {
217             /* *pch is an invalid character */
218             return FALSE;
219         }
220     }
221 
222     return TRUE;
223 }
224 
225 INT_PTR
226 CALLBACK
227 WelcomeDlgProc(HWND hwndDlg,
228                UINT uMsg,
229                WPARAM wParam,
230                LPARAM lParam)
231 {
232     LPPROPSHEETPAGEW ppsp;
233     PCREATE_LINK_CONTEXT pContext;
234     LPPSHNOTIFY lppsn;
235     WCHAR szPath[MAX_PATH * 2];
236     WCHAR szDesc[100];
237     BROWSEINFOW brws;
238     LPITEMIDLIST pidllist;
239     LPWSTR pch;
240     SHFILEINFOW FileInfo;
241 
242     switch(uMsg)
243     {
244         case WM_INITDIALOG:
245             ppsp = (LPPROPSHEETPAGEW)lParam;
246             pContext = (PCREATE_LINK_CONTEXT) ppsp->lParam;
247             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
248             PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
249             SHAutoComplete(GetDlgItem(hwndDlg, IDC_SHORTCUT_LOCATION), SHACF_DEFAULT);
250             break;
251         case WM_COMMAND:
252             switch(HIWORD(wParam))
253             {
254                 case EN_CHANGE:
255                     if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, WM_GETTEXTLENGTH, 0, 0))
256                     {
257                         PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
258                     }
259                     else
260                     {
261                         PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
262                     }
263                     break;
264             }
265             switch(LOWORD(wParam))
266             {
267                 case IDC_SHORTCUT_BROWSE:
268                     ZeroMemory(&brws, sizeof(brws));
269                     brws.hwndOwner = hwndDlg;
270                     brws.pidlRoot = NULL;
271                     brws.pszDisplayName = szPath;
272                     brws.ulFlags = BIF_BROWSEINCLUDEFILES;
273                     brws.lpfn = NULL;
274                     pidllist = SHBrowseForFolderW(&brws);
275                     if (!pidllist)
276                         break;
277 
278                     if (SHGetPathFromIDListW(pidllist, szPath))
279                     {
280                         SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, szPath);
281                         SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, WM_SETFOCUS, 0, 0);
282                         SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1);
283                     }
284                     /* Free memory, if possible */
285                     CoTaskMemFree(pidllist);
286                     break;
287             }
288             break;
289         case WM_NOTIFY:
290             lppsn  = (LPPSHNOTIFY) lParam;
291             pContext = (PCREATE_LINK_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
292             if (lppsn->hdr.code == PSN_SETACTIVE)
293             {
294                 SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, pContext->szTarget);
295             }
296             else if (lppsn->hdr.code == PSN_WIZNEXT)
297             {
298                 GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, pContext->szTarget, _countof(pContext->szTarget));
299                 StrTrimW(pContext->szTarget, L" \t");
300 
301                 ExpandEnvironmentStringsW(pContext->szTarget, szPath, _countof(szPath));
302                 StringCchCopyW(pContext->szTarget, _countof(pContext->szTarget), szPath);
303 
304                 if (IsInternetLocation(pContext->szTarget))
305                 {
306                     /* internet */
307                     WCHAR szName[128];
308                     LoadStringW(hApplet, IDS_NEW_INTERNET_SHORTCUT, szName, _countof(szName));
309                     StringCchCopyW(pContext->szDescription, _countof(pContext->szDescription), szName);
310 
311                     pContext->szWorkingDirectory[0] = 0;
312                 }
313                 else if (GetFileAttributesW(pContext->szTarget) != INVALID_FILE_ATTRIBUTES)
314                 {
315                     /* file */
316                     SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1);
317                     SetFocus(GetDlgItem(hwndDlg, IDC_SHORTCUT_LOCATION));
318                     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
319 
320                     /* get display name */
321                     FileInfo.szDisplayName[0] = 0;
322                     if (SHGetFileInfoW(pContext->szTarget, 0, &FileInfo, sizeof(FileInfo), SHGFI_DISPLAYNAME))
323                         StringCchCopyW(pContext->szDescription, _countof(pContext->szDescription), FileInfo.szDisplayName);
324 
325                     /* set working directory */
326                     StringCchCopyW(pContext->szWorkingDirectory, _countof(pContext->szWorkingDirectory),
327                                    pContext->szTarget);
328                     PathRemoveBackslashW(pContext->szWorkingDirectory);
329                     pch = PathFindFileNameW(pContext->szWorkingDirectory);
330                     if (pch && *pch)
331                         *pch = 0;
332                     PathRemoveBackslashW(pContext->szWorkingDirectory);
333                 }
334                 else
335                 {
336                     /* not found */
337                     WCHAR szError[MAX_PATH + 100];
338 
339                     SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1);
340 
341                     LoadStringW(hApplet, IDS_CREATE_SHORTCUT, szDesc, _countof(szDesc));
342                     LoadStringW(hApplet, IDS_ERROR_NOT_FOUND, szPath, _countof(szPath));
343                     StringCchPrintfW(szError, _countof(szError), szPath, pContext->szTarget);
344                     MessageBoxW(hwndDlg, szError, szDesc, MB_ICONERROR);
345 
346                     /* prevent the wizard to go next */
347                     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
348                     return TRUE;
349                 }
350             }
351             else if (lppsn->hdr.code == PSN_RESET && !lppsn->lParam)
352             {
353                 /* The user has clicked [Cancel] */
354                 DeleteFileW(pContext->szOldFile);
355                 SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, pContext->szOldFile, NULL);
356             }
357             break;
358     }
359     return FALSE;
360 }
361 
362 INT_PTR
363 CALLBACK
364 FinishDlgProc(HWND hwndDlg,
365                UINT uMsg,
366                WPARAM wParam,
367                LPARAM lParam)
368 {
369     LPPROPSHEETPAGEW ppsp;
370     PCREATE_LINK_CONTEXT pContext;
371     LPPSHNOTIFY lppsn;
372     LPWSTR pch;
373     WCHAR szText[MAX_PATH];
374     WCHAR szMessage[128];
375 
376     switch(uMsg)
377     {
378         case WM_INITDIALOG:
379             ppsp = (LPPROPSHEETPAGEW)lParam;
380             pContext = (PCREATE_LINK_CONTEXT) ppsp->lParam;
381             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
382             PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
383             break;
384         case WM_COMMAND:
385             switch(HIWORD(wParam))
386             {
387                 case EN_CHANGE:
388                     if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_NAME, WM_GETTEXTLENGTH, 0, 0))
389                     {
390                         GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_NAME, szText, _countof(szText));
391                         StrTrimW(szText, L" \t");
392                         if (szText[0])
393                             PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
394                         else
395                             PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
396                     }
397                     else
398                     {
399                         PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
400                     }
401                     break;
402             }
403             break;
404         case WM_NOTIFY:
405             lppsn  = (LPPSHNOTIFY) lParam;
406             pContext = (PCREATE_LINK_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER);
407             if (lppsn->hdr.code == PSN_SETACTIVE)
408             {
409                 /* TODO: Use shell32!PathCleanupSpec instead of DoConvertNameForFileSystem */
410                 DoConvertNameForFileSystem(pContext->szDescription);
411                 SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_NAME, pContext->szDescription);
412                 SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_NAME, EM_SETSEL, 0, -1);
413                 SetFocus(GetDlgItem(hwndDlg, IDC_SHORTCUT_NAME));
414             }
415             else if (lppsn->hdr.code == PSN_WIZFINISH)
416             {
417                 GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_NAME, pContext->szDescription, _countof(pContext->szDescription));
418                 StrTrimW(pContext->szDescription, L" \t");
419 
420                 if (!DoValidateShortcutName(pContext))
421                 {
422                     SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_NAME, EM_SETSEL, 0, -1);
423 
424                     LoadStringW(hApplet, IDS_INVALID_NAME, szMessage, _countof(szMessage));
425                     MessageBoxW(hwndDlg, szMessage, NULL, MB_ICONERROR);
426 
427                     /* prevent the wizard to go next */
428                     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
429                     return TRUE;
430                 }
431 
432                 /* if old shortcut file exists, then delete it now */
433                 DeleteFileW(pContext->szOldFile);
434                 SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, pContext->szOldFile, NULL);
435 
436                 if (IsInternetLocation(pContext->szTarget))
437                 {
438                     /* internet */
439                     StringCchCopyW(pContext->szLinkName, _countof(pContext->szLinkName),
440                                    pContext->szOrigin);
441                     PathAppendW(pContext->szLinkName, pContext->szDescription);
442 
443                     /* change extension if any */
444                     pch = PathFindExtensionW(pContext->szLinkName);
445                     if (pch && *pch)
446                         *pch = 0;
447                     StringCchCatW(pContext->szLinkName, _countof(pContext->szLinkName), L".url");
448 
449                     if (!CreateInternetShortcut(pContext))
450                     {
451                         LoadStringW(hApplet, IDS_CANTMAKEINETSHORTCUT, szMessage, _countof(szMessage));
452                         MessageBoxW(hwndDlg, szMessage, NULL, MB_ICONERROR);
453                     }
454                 }
455                 else
456                 {
457                     /* file */
458                     StringCchCopyW(pContext->szLinkName, _countof(pContext->szLinkName),
459                                    pContext->szOrigin);
460                     PathAppendW(pContext->szLinkName, pContext->szDescription);
461 
462                     /* change extension if any */
463                     pch = PathFindExtensionW(pContext->szLinkName);
464                     if (pch && *pch)
465                         *pch = 0;
466                     StringCchCatW(pContext->szLinkName, _countof(pContext->szLinkName), L".lnk");
467 
468                     if (!CreateShortcut(pContext))
469                     {
470                         WCHAR szMessage[128];
471                         LoadStringW(hApplet, IDS_CANTMAKESHORTCUT, szMessage, _countof(szMessage));
472                         MessageBoxW(hwndDlg, szMessage, NULL, MB_ICONERROR);
473                     }
474                 }
475             }
476             else if (lppsn->hdr.code == PSN_RESET && !lppsn->lParam)
477             {
478                 /* The user has clicked [Cancel] */
479                 DeleteFileW(pContext->szOldFile);
480                 SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, pContext->szOldFile, NULL);
481             }
482             break;
483     }
484     return FALSE;
485 }
486 
487 static int CALLBACK
488 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
489 {
490     // NOTE: This callback is needed to set large icon correctly.
491     HICON hIcon;
492     switch (uMsg)
493     {
494         case PSCB_INITIALIZED:
495         {
496             hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDI_APPINETICO));
497             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
498             break;
499         }
500     }
501     return 0;
502 }
503 
504 LONG CALLBACK
505 ShowCreateShortcutWizard(HWND hwndCPl, LPCWSTR szPath)
506 {
507     PROPSHEETHEADERW psh;
508     HPROPSHEETPAGE ahpsp[2];
509     PROPSHEETPAGE psp;
510     UINT nPages = 0;
511     UINT nLength;
512     PCREATE_LINK_CONTEXT pContext;
513     WCHAR szMessage[128];
514     LPWSTR pch;
515 
516     pContext = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pContext));
517     if (!pContext)
518     {
519         /* no memory */
520         LoadStringW(hApplet, IDS_NO_MEMORY, szMessage, _countof(szMessage));
521         MessageBoxW(hwndCPl, szMessage, NULL, MB_ICONERROR);
522         return FALSE;
523     }
524 
525     nLength = wcslen(szPath);
526     if (!nLength)
527     {
528         HeapFree(GetProcessHeap(), 0, pContext);
529 
530         /* no directory given */
531         LoadStringW(hApplet, IDS_NO_DIRECTORY, szMessage, _countof(szMessage));
532         MessageBoxW(hwndCPl, szMessage, NULL, MB_ICONERROR);
533         return FALSE;
534     }
535 
536     if (!PathFileExistsW(szPath))
537     {
538         HeapFree(GetProcessHeap(), 0, pContext);
539 
540         /* invalid path */
541         LoadStringW(hApplet, IDS_INVALID_PATH, szMessage, _countof(szMessage));
542         MessageBoxW(hwndCPl, szMessage, NULL, MB_ICONERROR);
543         return FALSE;
544     }
545 
546     /* build the pContext->szOrigin and pContext->szOldFile */
547     if (PathIsDirectoryW(szPath))
548     {
549         StringCchCopyW(pContext->szOrigin, _countof(pContext->szOrigin), szPath);
550         pContext->szOldFile[0] = 0;
551     }
552     else
553     {
554         StringCchCopyW(pContext->szOrigin, _countof(pContext->szOrigin), szPath);
555         pch = PathFindFileNameW(pContext->szOrigin);
556         if (pch && *pch)
557             *pch = 0;
558 
559         StringCchCopyW(pContext->szOldFile, _countof(pContext->szOldFile), szPath);
560 
561         pch = PathFindFileNameW(szPath);
562         if (pch && *pch)
563         {
564             /* build szDescription */
565             StringCchCopyW(pContext->szDescription, _countof(pContext->szDescription), pch);
566             *pch = 0;
567 
568             pch = PathFindExtensionW(pContext->szDescription);
569             *pch = 0;
570         }
571     }
572     PathAddBackslashW(pContext->szOrigin);
573 
574     /* Create the Welcome page */
575     psp.dwSize = sizeof(PROPSHEETPAGE);
576     psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
577     psp.hInstance = hApplet;
578     psp.pfnDlgProc = WelcomeDlgProc;
579     psp.pszTemplate = MAKEINTRESOURCEW(IDD_SHORTCUT_LOCATION);
580     psp.lParam = (LPARAM)pContext;
581     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
582 
583     /* Create the Finish page */
584     psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
585     psp.pfnDlgProc = FinishDlgProc;
586     psp.pszTemplate = MAKEINTRESOURCEW(IDD_SHORTCUT_FINISH);
587     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
588 
589     /* Create the property sheet */
590     psh.dwSize = sizeof(PROPSHEETHEADER);
591     psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_USEICONID | PSH_USECALLBACK;
592     psh.hInstance = hApplet;
593     psh.pszIcon = MAKEINTRESOURCEW(IDI_APPINETICO);
594     psh.hwndParent = NULL;
595     psh.nPages = nPages;
596     psh.nStartPage = 0;
597     psh.phpage = ahpsp;
598     psh.pszbmWatermark = MAKEINTRESOURCEW(IDB_SHORTCUT);
599     psh.pfnCallback = PropSheetProc;
600 
601     /* Display the wizard */
602     PropertySheet(&psh);
603     HeapFree(GetProcessHeap(), 0, pContext);
604     return TRUE;
605 }
606 
607 LONG
608 CALLBACK
609 NewLinkHereW(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
610 {
611     InitCommonControls();
612     return ShowCreateShortcutWizard(hwndCPl, (LPWSTR)lParam1);
613 }
614 
615 LONG
616 CALLBACK
617 NewLinkHereA(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
618 {
619     WCHAR szFile[MAX_PATH];
620 
621     if (MultiByteToWideChar(CP_ACP, 0, (LPSTR)lParam1, -1, szFile, _countof(szFile)))
622     {
623         InitCommonControls();
624         return ShowCreateShortcutWizard(hwndCPl, szFile);
625     }
626     return -1;
627 }
628