[SYSDM]
[reactos.git] / reactos / 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
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 /* no directory given */
338 return FALSE;
339 }
340 ///
341 /// FIXME
342 /// check if path is valid
343 ///
344
345 wcscpy(pContext->szLinkName, szPath);
346 if (pContext->szLinkName[nLength-1] != L'\\')
347 {
348 pContext->szLinkName[nLength] = L'\\';
349 pContext->szLinkName[nLength+1] = L'\0';
350 }
351
352
353 /* Create the Welcome page */
354 psp.dwSize = sizeof(PROPSHEETPAGE);
355 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
356 psp.hInstance = hApplet;
357 psp.pfnDlgProc = WelcomeDlgProc;
358 psp.pszTemplate = MAKEINTRESOURCE(IDD_SHORTCUT_LOCATION);
359 psp.lParam = (LPARAM)pContext;
360 ahpsp[nPages++] = CreatePropertySheetPage(&psp);
361
362 /* Create the Finish page */
363 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
364 psp.pfnDlgProc = FinishDlgProc;
365 psp.pszTemplate = MAKEINTRESOURCE(IDD_SHORTCUT_FINISH);
366 ahpsp[nPages++] = CreatePropertySheetPage(&psp);
367
368
369 /* Create the property sheet */
370 psh.dwSize = sizeof(PROPSHEETHEADER);
371 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK;
372 psh.hInstance = hApplet;
373 psh.hwndParent = NULL;
374 psh.nPages = nPages;
375 psh.nStartPage = 0;
376 psh.phpage = ahpsp;
377 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
378
379 /* Display the wizard */
380 PropertySheet(&psh);
381 HeapFree(GetProcessHeap(), 0, pContext);
382 return TRUE;
383 }
384
385
386 LONG
387 CALLBACK
388 NewLinkHere(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
389 {
390 WCHAR szFile[MAX_PATH];
391
392 if (MultiByteToWideChar(CP_ACP, 0, (char*)lParam1, strlen((char*)lParam1)+1, szFile, MAX_PATH))
393 {
394 return ShowCreateShortcutWizard(hwndCPl, szFile);
395 }
396 return -1;
397 }
398
399
400 LONG
401 CALLBACK
402 NewLinkHereW(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
403 {
404 return ShowCreateShortcutWizard(hwndCPl, (LPWSTR)lParam1);
405 }
406
407 LONG
408 CALLBACK
409 NewLinkHereA(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
410 {
411 WCHAR szFile[MAX_PATH];
412
413 if (MultiByteToWideChar(CP_ACP, 0, (char*)lParam1, strlen((char*)lParam1)+1, szFile, MAX_PATH))
414 {
415 return ShowCreateShortcutWizard(hwndCPl, szFile);
416 }
417 return -1;
418 }