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