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