Synchronize with trunk.
[reactos.git] / dll / cpl / appwiz / createlink.c
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 * UPDATE HISTORY:
9 * 06-17-2004 Created
10 */
11
12 #include "appwiz.h"
13
14 BOOL
15 IsShortcut(HKEY hKey)
16 {
17 WCHAR Value[10];
18 DWORD Size;
19 DWORD Type;
20
21 Size = sizeof(Value);
22 if (RegQueryValueExW(hKey, L"IsShortcut", NULL, &Type, (LPBYTE)Value, &Size) != ERROR_SUCCESS)
23 return FALSE;
24
25 if (Type != REG_SZ)
26 return FALSE;
27
28 return (wcsicmp(Value, L"yes") == 0);
29 }
30
31 BOOL
32 IsExtensionAShortcut(LPWSTR lpExtension)
33 {
34 HKEY hKey;
35 WCHAR Buffer[100];
36 DWORD Size;
37 DWORD Type;
38
39 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, lpExtension, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
40 return FALSE;
41
42 if (IsShortcut(hKey))
43 {
44 RegCloseKey(hKey);
45 return TRUE;
46 }
47
48 Size = sizeof(Buffer);
49 if (RegQueryValueEx(hKey, NULL, NULL, &Type, (LPBYTE)Buffer, &Size) != ERROR_SUCCESS || Type != REG_SZ)
50 {
51 RegCloseKey(hKey);
52 return FALSE;
53 }
54
55 RegCloseKey(hKey);
56
57 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Buffer, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
58 return FALSE;
59
60 if (IsShortcut(hKey))
61 {
62 RegCloseKey(hKey);
63 return TRUE;
64 }
65
66 RegCloseKey(hKey);
67 return FALSE;
68 }
69
70 BOOL
71 CreateShortcut(PCREATE_LINK_CONTEXT pContext)
72 {
73 IShellLinkW *pShellLink, *pSourceShellLink;
74 IPersistFile *pPersistFile;
75 HRESULT hr;
76 WCHAR Path[MAX_PATH];
77 LPWSTR lpExtension;
78
79 /* get the extension */
80 lpExtension = wcsrchr(pContext->szTarget, '.');
81
82 if (IsExtensionAShortcut(lpExtension))
83 {
84 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_ALL, &IID_IShellLinkW, (void**)&pSourceShellLink);
85
86 if (hr != S_OK)
87 return FALSE;
88
89 hr = pSourceShellLink->lpVtbl->QueryInterface(pSourceShellLink, &IID_IPersistFile, (void**)&pPersistFile);
90 if (hr != S_OK)
91 {
92 pSourceShellLink->lpVtbl->Release(pSourceShellLink);
93 return FALSE;
94 }
95
96 hr = pPersistFile->lpVtbl->Load(pPersistFile, (LPCOLESTR)pContext->szTarget, STGM_READ);
97 pPersistFile->lpVtbl->Release(pPersistFile);
98
99 if (hr != S_OK)
100 {
101 pSourceShellLink->lpVtbl->Release(pSourceShellLink);
102 return FALSE;
103 }
104
105 hr = pSourceShellLink->lpVtbl->GetPath(pSourceShellLink, Path, sizeof(Path) / sizeof(WCHAR), NULL, 0);
106 pSourceShellLink->lpVtbl->Release(pSourceShellLink);
107
108 if (hr != S_OK)
109 {
110 return FALSE;
111 }
112 }
113 else
114 {
115 wcscpy(Path, pContext->szTarget);
116 }
117
118 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_ALL,
119 &IID_IShellLinkW, (void**)&pShellLink);
120
121 if (hr != S_OK)
122 return FALSE;
123
124
125 pShellLink->lpVtbl->SetPath(pShellLink, Path);
126 pShellLink->lpVtbl->SetDescription(pShellLink, pContext->szDescription);
127 pShellLink->lpVtbl->SetWorkingDirectory(pShellLink, pContext->szWorkingDirectory);
128
129 hr = pShellLink->lpVtbl->QueryInterface(pShellLink, &IID_IPersistFile, (void**)&pPersistFile);
130 if (hr != S_OK)
131 {
132 pShellLink->lpVtbl->Release(pShellLink);
133 return FALSE;
134 }
135
136 hr = pPersistFile->lpVtbl->Save(pPersistFile, pContext->szLinkName, TRUE);
137 pPersistFile->lpVtbl->Release(pPersistFile);
138 pShellLink->lpVtbl->Release(pShellLink);
139 return (hr == S_OK);
140 }
141
142
143
144
145 INT_PTR
146 CALLBACK
147 WelcomeDlgProc(HWND hwndDlg,
148 UINT uMsg,
149 WPARAM wParam,
150 LPARAM lParam)
151 {
152 LPPROPSHEETPAGEW ppsp;
153 PCREATE_LINK_CONTEXT pContext;
154 LPPSHNOTIFY lppsn;
155 WCHAR szPath[MAX_PATH];
156 WCHAR szDesc[100];
157 BROWSEINFOW brws;
158 LPITEMIDLIST pidllist;
159 IMalloc* malloc;
160
161 switch(uMsg)
162 {
163 case WM_INITDIALOG:
164 ppsp = (LPPROPSHEETPAGEW)lParam;
165 pContext = (PCREATE_LINK_CONTEXT) ppsp->lParam;
166 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
167 PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
168 break;
169 case WM_COMMAND:
170 switch(HIWORD(wParam))
171 {
172 case EN_CHANGE:
173 if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, WM_GETTEXTLENGTH, 0, 0))
174 {
175 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
176 }
177 else
178 {
179 PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
180 }
181 break;
182 }
183 switch(LOWORD(wParam))
184 {
185 case IDC_SHORTCUT_BROWSE:
186 ZeroMemory(&brws, sizeof(brws));
187 brws.hwndOwner = hwndDlg;
188 brws.pidlRoot = NULL;
189 brws.pszDisplayName = szPath;
190 brws.ulFlags = BIF_BROWSEINCLUDEFILES;
191 brws.lpfn = NULL;
192 pidllist = SHBrowseForFolderW(&brws);
193 if (!pidllist)
194 break;
195
196 if (SHGetPathFromIDListW(pidllist, szPath))
197 SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, WM_SETTEXT, 0, (LPARAM)szPath);
198
199 /* Free memory, if possible */
200 if (SUCCEEDED(SHGetMalloc(&malloc)))
201 {
202 IMalloc_Free(malloc, pidllist);
203 IMalloc_Release(malloc);
204 }
205
206 break;
207 }
208 break;
209 case WM_NOTIFY:
210 lppsn = (LPPSHNOTIFY) lParam;
211 if (lppsn->hdr.code == PSN_WIZNEXT)
212 {
213 pContext = (PCREATE_LINK_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER);
214 SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, WM_GETTEXT, MAX_PATH, (LPARAM)pContext->szTarget);
215 ///
216 /// FIXME
217 /// it should also be possible to create a link to folders, shellobjects etc....
218 ///
219 if (GetFileAttributesW(pContext->szTarget) == INVALID_FILE_ATTRIBUTES)
220 {
221 szDesc[0] = L'\0';
222 szPath[0] = L'\0';
223 if (LoadStringW(hApplet, IDS_CREATE_SHORTCUT, szDesc, 100) < 100 &&
224 LoadStringW(hApplet, IDS_ERROR_NOT_FOUND, szPath, MAX_PATH) < MAX_PATH)
225 {
226 WCHAR szError[MAX_PATH + 100];
227 #ifdef _MSC_VER
228 _swprintf(szError, szPath, pContext->szTarget);
229 #else
230 swprintf(szError, szPath, pContext->szTarget);
231 #endif
232 MessageBoxW(hwndDlg, szError, szDesc, MB_ICONERROR);
233 }
234 SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1);
235 SetFocus(GetDlgItem(hwndDlg, IDC_SHORTCUT_LOCATION));
236 SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
237 return -1;
238 }
239 else
240 {
241 WCHAR * first, *last;
242 wcscpy(pContext->szWorkingDirectory, pContext->szTarget);
243 first = wcschr(pContext->szWorkingDirectory, L'\\');
244 last = wcsrchr(pContext->szWorkingDirectory, L'\\');
245 wcscpy(pContext->szDescription, &last[1]);
246
247 if (first != last)
248 last[0] = L'\0';
249 else
250 first[1] = L'\0';
251
252 first = wcsrchr(pContext->szDescription, L'.');
253
254 if(first)
255 first[0] = L'\0';
256 }
257
258 }
259 break;
260 }
261 return FALSE;
262 }
263
264 INT_PTR
265 CALLBACK
266 FinishDlgProc(HWND hwndDlg,
267 UINT uMsg,
268 WPARAM wParam,
269 LPARAM lParam)
270 {
271 LPPROPSHEETPAGEW ppsp;
272 PCREATE_LINK_CONTEXT pContext;
273 LPPSHNOTIFY lppsn;
274
275 switch(uMsg)
276 {
277 case WM_INITDIALOG:
278 ppsp = (LPPROPSHEETPAGEW)lParam;
279 pContext = (PCREATE_LINK_CONTEXT) ppsp->lParam;
280 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
281 SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_NAME, WM_SETTEXT, 0, (LPARAM)pContext->szDescription);
282 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
283 break;
284 case WM_COMMAND:
285 switch(HIWORD(wParam))
286 {
287 case EN_CHANGE:
288 if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_NAME, WM_GETTEXTLENGTH, 0, 0))
289 {
290 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
291 }
292 else
293 {
294 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
295 }
296 break;
297 }
298 break;
299 case WM_NOTIFY:
300 lppsn = (LPPSHNOTIFY) lParam;
301 pContext = (PCREATE_LINK_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER);
302 if (lppsn->hdr.code == PSN_WIZFINISH)
303 {
304 SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_NAME, WM_GETTEXT, MAX_PATH, (LPARAM)pContext->szDescription);
305 wcscat(pContext->szLinkName, pContext->szDescription);
306 wcscat(pContext->szLinkName, L".lnk");
307 if (!CreateShortcut(pContext))
308 {
309 MessageBox(hwndDlg, _T("Failed to create shortcut"), _T("Error"), MB_ICONERROR);
310 }
311 }
312
313
314 }
315 return FALSE;
316 }
317
318 LONG CALLBACK
319 ShowCreateShortcutWizard(HWND hwndCPl, LPWSTR szPath)
320 {
321 PROPSHEETHEADERW psh;
322 HPROPSHEETPAGE ahpsp[2];
323 PROPSHEETPAGE psp;
324 UINT nPages = 0;
325 UINT nLength;
326 DWORD attrs;
327
328 PCREATE_LINK_CONTEXT pContext = (PCREATE_LINK_CONTEXT) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CREATE_LINK_CONTEXT));
329 if (!pContext)
330 {
331 /* no memory */
332 return FALSE;
333 }
334 nLength = wcslen(szPath);
335 if (!nLength)
336 {
337 HeapFree(GetProcessHeap(), 0, pContext);
338
339 /* no directory given */
340 return FALSE;
341 }
342
343 attrs = GetFileAttributesW(szPath);
344 if (attrs == INVALID_FILE_ATTRIBUTES)
345 {
346 HeapFree(GetProcessHeap(), 0, pContext);
347
348 /* invalid path */
349 return FALSE;
350 }
351
352 wcscpy(pContext->szLinkName, szPath);
353 if (pContext->szLinkName[nLength-1] != L'\\')
354 {
355 pContext->szLinkName[nLength] = L'\\';
356 pContext->szLinkName[nLength+1] = L'\0';
357 }
358
359
360 /* Create the Welcome page */
361 psp.dwSize = sizeof(PROPSHEETPAGE);
362 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
363 psp.hInstance = hApplet;
364 psp.pfnDlgProc = WelcomeDlgProc;
365 psp.pszTemplate = MAKEINTRESOURCE(IDD_SHORTCUT_LOCATION);
366 psp.lParam = (LPARAM)pContext;
367 ahpsp[nPages++] = CreatePropertySheetPage(&psp);
368
369 /* Create the Finish page */
370 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
371 psp.pfnDlgProc = FinishDlgProc;
372 psp.pszTemplate = MAKEINTRESOURCE(IDD_SHORTCUT_FINISH);
373 ahpsp[nPages++] = CreatePropertySheetPage(&psp);
374
375
376 /* Create the property sheet */
377 psh.dwSize = sizeof(PROPSHEETHEADER);
378 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK;
379 psh.hInstance = hApplet;
380 psh.hwndParent = NULL;
381 psh.nPages = nPages;
382 psh.nStartPage = 0;
383 psh.phpage = ahpsp;
384 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
385
386 /* Display the wizard */
387 PropertySheet(&psh);
388 HeapFree(GetProcessHeap(), 0, pContext);
389 return TRUE;
390 }
391
392
393 LONG
394 CALLBACK
395 NewLinkHere(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
396 {
397 WCHAR szFile[MAX_PATH];
398
399 if (MultiByteToWideChar(CP_ACP, 0, (LPSTR) lParam1, -1, szFile, MAX_PATH))
400 {
401 return ShowCreateShortcutWizard(hwndCPl, szFile);
402 }
403 return -1;
404 }
405
406
407 LONG
408 CALLBACK
409 NewLinkHereW(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
410 {
411 return ShowCreateShortcutWizard(hwndCPl, (LPWSTR) lParam1);
412 }
413
414 LONG
415 CALLBACK
416 NewLinkHereA(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
417 {
418 WCHAR szFile[MAX_PATH];
419
420 if (MultiByteToWideChar(CP_ACP, 0, (LPSTR) lParam1, -1, szFile, MAX_PATH))
421 {
422 return ShowCreateShortcutWizard(hwndCPl, szFile);
423 }
424 return -1;
425 }