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