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 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 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 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 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 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 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 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 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 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 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 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 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 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