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 <strsafe.h> 15 16 BOOL 17 IsShortcut(HKEY hKey) 18 { 19 WCHAR Value[10]; 20 DWORD Size; 21 DWORD Type; 22 23 Size = sizeof(Value); 24 if (RegQueryValueExW(hKey, L"IsShortcut", NULL, &Type, (LPBYTE)Value, &Size) != ERROR_SUCCESS) 25 return FALSE; 26 27 if (Type != REG_SZ) 28 return FALSE; 29 30 return (wcsicmp(Value, L"yes") == 0); 31 } 32 33 BOOL 34 IsExtensionAShortcut(LPWSTR lpExtension) 35 { 36 HKEY hKey; 37 WCHAR Buffer[100]; 38 DWORD Size; 39 DWORD Type; 40 41 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, lpExtension, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 42 return FALSE; 43 44 if (IsShortcut(hKey)) 45 { 46 RegCloseKey(hKey); 47 return TRUE; 48 } 49 50 Size = sizeof(Buffer); 51 if (RegQueryValueEx(hKey, NULL, NULL, &Type, (LPBYTE)Buffer, &Size) != ERROR_SUCCESS || Type != REG_SZ) 52 { 53 RegCloseKey(hKey); 54 return FALSE; 55 } 56 57 RegCloseKey(hKey); 58 59 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Buffer, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 60 return FALSE; 61 62 if (IsShortcut(hKey)) 63 { 64 RegCloseKey(hKey); 65 return TRUE; 66 } 67 68 RegCloseKey(hKey); 69 return FALSE; 70 } 71 72 BOOL 73 CreateShortcut(PCREATE_LINK_CONTEXT pContext) 74 { 75 IShellLinkW *pShellLink, *pSourceShellLink; 76 IPersistFile *pPersistFile; 77 HRESULT hr; 78 WCHAR Path[MAX_PATH]; 79 LPWSTR lpExtension; 80 81 /* get the extension */ 82 lpExtension = PathFindExtensionW(pContext->szTarget); 83 84 if (IsExtensionAShortcut(lpExtension)) 85 { 86 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_ALL, &IID_IShellLinkW, (void**)&pSourceShellLink); 87 88 if (FAILED(hr)) 89 return FALSE; 90 91 hr = IUnknown_QueryInterface(pSourceShellLink, &IID_IPersistFile, (void**)&pPersistFile); 92 if (FAILED(hr)) 93 { 94 IUnknown_Release(pSourceShellLink); 95 return FALSE; 96 } 97 98 hr = pPersistFile->lpVtbl->Load(pPersistFile, (LPCOLESTR)pContext->szTarget, STGM_READ); 99 IUnknown_Release(pPersistFile); 100 101 if (FAILED(hr)) 102 { 103 IUnknown_Release(pSourceShellLink); 104 return FALSE; 105 } 106 107 hr = IShellLinkW_GetPath(pSourceShellLink, Path, _countof(Path), NULL, 0); 108 IUnknown_Release(pSourceShellLink); 109 110 if (FAILED(hr)) 111 { 112 return FALSE; 113 } 114 } 115 else 116 { 117 StringCchCopyW(Path, _countof(Path), pContext->szTarget); 118 } 119 120 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_ALL, 121 &IID_IShellLinkW, (void**)&pShellLink); 122 123 if (hr != S_OK) 124 return FALSE; 125 126 pShellLink->lpVtbl->SetPath(pShellLink, Path); 127 pShellLink->lpVtbl->SetDescription(pShellLink, pContext->szDescription); 128 pShellLink->lpVtbl->SetWorkingDirectory(pShellLink, pContext->szWorkingDirectory); 129 130 hr = IUnknown_QueryInterface(pShellLink, &IID_IPersistFile, (void**)&pPersistFile); 131 if (hr != S_OK) 132 { 133 IUnknown_Release(pShellLink); 134 return FALSE; 135 } 136 137 hr = pPersistFile->lpVtbl->Save(pPersistFile, pContext->szLinkName, TRUE); 138 IUnknown_Release(pPersistFile); 139 IUnknown_Release(pShellLink); 140 return (hr == S_OK); 141 } 142 143 BOOL 144 CreateInternetShortcut(PCREATE_LINK_CONTEXT pContext) 145 { 146 IUniformResourceLocatorW *pURL = NULL; 147 IPersistFile *pPersistFile = NULL; 148 HRESULT hr; 149 WCHAR szPath[MAX_PATH]; 150 GetFullPathNameW(pContext->szLinkName, _countof(szPath), szPath, NULL); 151 152 hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, 153 &IID_IUniformResourceLocatorW, (void **)&pURL); 154 if (FAILED(hr)) 155 return FALSE; 156 157 hr = IUnknown_QueryInterface(pURL, &IID_IPersistFile, (void **)&pPersistFile); 158 if (FAILED(hr)) 159 { 160 IUnknown_Release(pURL); 161 return FALSE; 162 } 163 164 pURL->lpVtbl->SetURL(pURL, pContext->szTarget, 0); 165 166 hr = pPersistFile->lpVtbl->Save(pPersistFile, szPath, TRUE); 167 168 IUnknown_Release(pPersistFile); 169 IUnknown_Release(pURL); 170 171 return SUCCEEDED(hr); 172 } 173 174 BOOL IsInternetLocation(LPCWSTR pszLocation) 175 { 176 return (PathIsURLW(pszLocation) || wcsstr(pszLocation, L"www.") == pszLocation); 177 } 178 179 INT_PTR 180 CALLBACK 181 WelcomeDlgProc(HWND hwndDlg, 182 UINT uMsg, 183 WPARAM wParam, 184 LPARAM lParam) 185 { 186 LPPROPSHEETPAGEW ppsp; 187 PCREATE_LINK_CONTEXT pContext; 188 LPPSHNOTIFY lppsn; 189 WCHAR szPath[MAX_PATH]; 190 WCHAR szDesc[100]; 191 BROWSEINFOW brws; 192 LPITEMIDLIST pidllist; 193 194 switch(uMsg) 195 { 196 case WM_INITDIALOG: 197 ppsp = (LPPROPSHEETPAGEW)lParam; 198 pContext = (PCREATE_LINK_CONTEXT) ppsp->lParam; 199 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext); 200 PropSheet_SetWizButtons(GetParent(hwndDlg), 0); 201 break; 202 case WM_COMMAND: 203 switch(HIWORD(wParam)) 204 { 205 case EN_CHANGE: 206 if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, WM_GETTEXTLENGTH, 0, 0)) 207 { 208 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); 209 } 210 else 211 { 212 PropSheet_SetWizButtons(GetParent(hwndDlg), 0); 213 } 214 break; 215 } 216 switch(LOWORD(wParam)) 217 { 218 case IDC_SHORTCUT_BROWSE: 219 ZeroMemory(&brws, sizeof(brws)); 220 brws.hwndOwner = hwndDlg; 221 brws.pidlRoot = NULL; 222 brws.pszDisplayName = szPath; 223 brws.ulFlags = BIF_BROWSEINCLUDEFILES; 224 brws.lpfn = NULL; 225 pidllist = SHBrowseForFolderW(&brws); 226 if (!pidllist) 227 break; 228 229 if (SHGetPathFromIDListW(pidllist, szPath)) 230 SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, szPath); 231 232 /* Free memory, if possible */ 233 CoTaskMemFree(pidllist); 234 break; 235 } 236 break; 237 case WM_NOTIFY: 238 lppsn = (LPPSHNOTIFY) lParam; 239 if (lppsn->hdr.code == PSN_WIZNEXT) 240 { 241 LPWSTR pch; 242 pContext = (PCREATE_LINK_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER); 243 GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, pContext->szTarget, _countof(pContext->szTarget)); 244 StrTrimW(pContext->szTarget, L" \t"); 245 246 if (IsInternetLocation(pContext->szTarget)) 247 { 248 /* internet */ 249 WCHAR szName[128]; 250 LoadStringW(hApplet, IDS_NEW_INTERNET_SHORTCUT, szName, _countof(szName)); 251 StringCchCopyW(pContext->szDescription, _countof(pContext->szDescription), szName); 252 253 pContext->szWorkingDirectory[0] = 0; 254 } 255 else if (GetFileAttributesW(pContext->szTarget) != INVALID_FILE_ATTRIBUTES) 256 { 257 /* file */ 258 SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1); 259 SetFocus(GetDlgItem(hwndDlg, IDC_SHORTCUT_LOCATION)); 260 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); 261 262 /* set working directory */ 263 StringCchCopyW(pContext->szWorkingDirectory, _countof(pContext->szWorkingDirectory), 264 pContext->szTarget); 265 PathRemoveBackslashW(pContext->szWorkingDirectory); 266 pch = PathFindFileNameW(pContext->szWorkingDirectory); 267 if (pch && *pch) 268 *pch = 0; 269 PathRemoveBackslashW(pContext->szWorkingDirectory); 270 } 271 else 272 { 273 /* not found */ 274 WCHAR szError[MAX_PATH + 100]; 275 LoadStringW(hApplet, IDS_CREATE_SHORTCUT, szDesc, _countof(szDesc)); 276 LoadStringW(hApplet, IDS_ERROR_NOT_FOUND, szPath, _countof(szPath)); 277 StringCchPrintfW(szError, _countof(szError), szPath, pContext->szTarget); 278 MessageBoxW(hwndDlg, szError, szDesc, MB_ICONERROR); 279 } 280 } 281 break; 282 } 283 return FALSE; 284 } 285 286 INT_PTR 287 CALLBACK 288 FinishDlgProc(HWND hwndDlg, 289 UINT uMsg, 290 WPARAM wParam, 291 LPARAM lParam) 292 { 293 LPPROPSHEETPAGEW ppsp; 294 PCREATE_LINK_CONTEXT pContext; 295 LPPSHNOTIFY lppsn; 296 297 switch(uMsg) 298 { 299 case WM_INITDIALOG: 300 ppsp = (LPPROPSHEETPAGEW)lParam; 301 pContext = (PCREATE_LINK_CONTEXT) ppsp->lParam; 302 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext); 303 SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_NAME, pContext->szDescription); 304 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH); 305 break; 306 case WM_COMMAND: 307 switch(HIWORD(wParam)) 308 { 309 case EN_CHANGE: 310 if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_NAME, WM_GETTEXTLENGTH, 0, 0)) 311 { 312 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH); 313 } 314 else 315 { 316 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK); 317 } 318 break; 319 } 320 break; 321 case WM_NOTIFY: 322 lppsn = (LPPSHNOTIFY) lParam; 323 pContext = (PCREATE_LINK_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER); 324 if (lppsn->hdr.code == PSN_WIZFINISH) 325 { 326 LPWSTR pch; 327 DWORD attrs; 328 GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_NAME, pContext->szDescription, MAX_PATH); 329 StrTrimW(pContext->szDescription, L" \t"); 330 331 /* if old shortcut file exists, then delete it now */ 332 attrs = GetFileAttributesW(pContext->szOldFile); 333 if (attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY)) 334 { 335 DeleteFileW(pContext->szOldFile); 336 } 337 338 if (IsInternetLocation(pContext->szTarget)) 339 { 340 /* internet */ 341 StringCchCopyW(pContext->szLinkName, _countof(pContext->szLinkName), 342 pContext->szOrigin); 343 PathAppendW(pContext->szLinkName, pContext->szDescription); 344 345 /* change extension if any */ 346 pch = PathFindExtensionW(pContext->szLinkName); 347 if (pch && *pch) 348 *pch = 0; 349 StringCchCatW(pContext->szLinkName, _countof(pContext->szLinkName), L".url"); 350 351 if (!CreateInternetShortcut(pContext)) 352 { 353 WCHAR szMessage[128]; 354 LoadStringW(hApplet, IDS_CANTMAKEINETSHORTCUT, szMessage, _countof(szMessage)); 355 MessageBoxW(hwndDlg, szMessage, NULL, MB_ICONERROR); 356 } 357 } 358 else 359 { 360 /* file */ 361 StringCchCopyW(pContext->szLinkName, _countof(pContext->szLinkName), 362 pContext->szOrigin); 363 PathAppendW(pContext->szLinkName, pContext->szDescription); 364 365 /* change extension if any */ 366 pch = PathFindExtensionW(pContext->szLinkName); 367 if (pch && *pch) 368 *pch = 0; 369 StringCchCatW(pContext->szLinkName, _countof(pContext->szLinkName), L".lnk"); 370 371 if (!CreateShortcut(pContext)) 372 { 373 WCHAR szMessage[128]; 374 LoadStringW(hApplet, IDS_CANTMAKESHORTCUT, szMessage, _countof(szMessage)); 375 MessageBoxW(hwndDlg, szMessage, NULL, MB_ICONERROR); 376 } 377 } 378 } 379 break; 380 } 381 return FALSE; 382 } 383 384 LONG CALLBACK 385 ShowCreateShortcutWizard(HWND hwndCPl, LPWSTR szPath) 386 { 387 PROPSHEETHEADERW psh; 388 HPROPSHEETPAGE ahpsp[2]; 389 PROPSHEETPAGE psp; 390 UINT nPages = 0; 391 UINT nLength; 392 DWORD attrs; 393 394 PCREATE_LINK_CONTEXT pContext = (PCREATE_LINK_CONTEXT) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CREATE_LINK_CONTEXT)); 395 if (!pContext) 396 { 397 /* no memory */ 398 return FALSE; 399 } 400 401 nLength = wcslen(szPath); 402 if (!nLength) 403 { 404 HeapFree(GetProcessHeap(), 0, pContext); 405 406 /* no directory given */ 407 return FALSE; 408 } 409 410 attrs = GetFileAttributesW(szPath); 411 if (attrs == INVALID_FILE_ATTRIBUTES) 412 { 413 HeapFree(GetProcessHeap(), 0, pContext); 414 415 /* invalid path */ 416 return FALSE; 417 } 418 419 /* build the pContext->szOrigin and pContext->szOldFile */ 420 StringCchCopyW(pContext->szOrigin, _countof(pContext->szOrigin), szPath); 421 pContext->szOldFile[0] = 0; 422 if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) 423 { 424 LPWSTR pch; 425 StringCchCopyW(pContext->szOldFile, _countof(pContext->szOldFile), szPath); 426 pch = PathFindFileNameW(pContext->szOrigin); 427 if (pch && *pch) 428 *pch = 0; 429 } 430 PathAddBackslashW(pContext->szOrigin); 431 432 /* Create the Welcome page */ 433 psp.dwSize = sizeof(PROPSHEETPAGE); 434 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER; 435 psp.hInstance = hApplet; 436 psp.pfnDlgProc = WelcomeDlgProc; 437 psp.pszTemplate = MAKEINTRESOURCEW(IDD_SHORTCUT_LOCATION); 438 psp.lParam = (LPARAM)pContext; 439 ahpsp[nPages++] = CreatePropertySheetPage(&psp); 440 441 /* Create the Finish page */ 442 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER; 443 psp.pfnDlgProc = FinishDlgProc; 444 psp.pszTemplate = MAKEINTRESOURCEW(IDD_SHORTCUT_FINISH); 445 ahpsp[nPages++] = CreatePropertySheetPage(&psp); 446 447 448 /* Create the property sheet */ 449 psh.dwSize = sizeof(PROPSHEETHEADER); 450 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK; 451 psh.hInstance = hApplet; 452 psh.hwndParent = NULL; 453 psh.nPages = nPages; 454 psh.nStartPage = 0; 455 psh.phpage = ahpsp; 456 psh.pszbmWatermark = MAKEINTRESOURCEW(IDB_SHORTCUT); 457 458 /* Display the wizard */ 459 PropertySheet(&psh); 460 HeapFree(GetProcessHeap(), 0, pContext); 461 return TRUE; 462 } 463 464 LONG 465 CALLBACK 466 NewLinkHereW(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2) 467 { 468 return ShowCreateShortcutWizard(hwndCPl, (LPWSTR) lParam1); 469 } 470 471 LONG 472 CALLBACK 473 NewLinkHereA(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2) 474 { 475 WCHAR szFile[MAX_PATH]; 476 477 if (MultiByteToWideChar(CP_ACP, 0, (LPSTR) lParam1, -1, szFile, MAX_PATH)) 478 { 479 return ShowCreateShortcutWizard(hwndCPl, szFile); 480 } 481 return -1; 482 } 483