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