* Sync up to trunk HEAD (r62286).
[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 #include <tchar.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 = wcsrchr(pContext->szTarget, '.');
83
84 if (IsExtensionAShortcut(lpExtension))
85 {
86 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_ALL, &IID_IShellLinkW, (void**)&pSourceShellLink);
87
88 if (hr != S_OK)
89 return FALSE;
90
91 hr = pSourceShellLink->lpVtbl->QueryInterface(pSourceShellLink, &IID_IPersistFile, (void**)&pPersistFile);
92 if (hr != S_OK)
93 {
94 pSourceShellLink->lpVtbl->Release(pSourceShellLink);
95 return FALSE;
96 }
97
98 hr = pPersistFile->lpVtbl->Load(pPersistFile, (LPCOLESTR)pContext->szTarget, STGM_READ);
99 pPersistFile->lpVtbl->Release(pPersistFile);
100
101 if (hr != S_OK)
102 {
103 pSourceShellLink->lpVtbl->Release(pSourceShellLink);
104 return FALSE;
105 }
106
107 hr = pSourceShellLink->lpVtbl->GetPath(pSourceShellLink, Path, sizeof(Path) / sizeof(WCHAR), NULL, 0);
108 pSourceShellLink->lpVtbl->Release(pSourceShellLink);
109
110 if (hr != S_OK)
111 {
112 return FALSE;
113 }
114 }
115 else
116 {
117 wcscpy(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
127 pShellLink->lpVtbl->SetPath(pShellLink, Path);
128 pShellLink->lpVtbl->SetDescription(pShellLink, pContext->szDescription);
129 pShellLink->lpVtbl->SetWorkingDirectory(pShellLink, pContext->szWorkingDirectory);
130
131 hr = pShellLink->lpVtbl->QueryInterface(pShellLink, &IID_IPersistFile, (void**)&pPersistFile);
132 if (hr != S_OK)
133 {
134 pShellLink->lpVtbl->Release(pShellLink);
135 return FALSE;
136 }
137
138 hr = pPersistFile->lpVtbl->Save(pPersistFile, pContext->szLinkName, TRUE);
139 pPersistFile->lpVtbl->Release(pPersistFile);
140 pShellLink->lpVtbl->Release(pShellLink);
141 return (hr == S_OK);
142 }
143
144
145
146
147 INT_PTR
148 CALLBACK
149 WelcomeDlgProc(HWND hwndDlg,
150 UINT uMsg,
151 WPARAM wParam,
152 LPARAM lParam)
153 {
154 LPPROPSHEETPAGEW ppsp;
155 PCREATE_LINK_CONTEXT pContext;
156 LPPSHNOTIFY lppsn;
157 WCHAR szPath[MAX_PATH];
158 WCHAR szDesc[100];
159 BROWSEINFOW brws;
160 LPITEMIDLIST pidllist;
161 IMalloc* malloc;
162
163 switch(uMsg)
164 {
165 case WM_INITDIALOG:
166 ppsp = (LPPROPSHEETPAGEW)lParam;
167 pContext = (PCREATE_LINK_CONTEXT) ppsp->lParam;
168 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
169 PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
170 break;
171 case WM_COMMAND:
172 switch(HIWORD(wParam))
173 {
174 case EN_CHANGE:
175 if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, WM_GETTEXTLENGTH, 0, 0))
176 {
177 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
178 }
179 else
180 {
181 PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
182 }
183 break;
184 }
185 switch(LOWORD(wParam))
186 {
187 case IDC_SHORTCUT_BROWSE:
188 ZeroMemory(&brws, sizeof(brws));
189 brws.hwndOwner = hwndDlg;
190 brws.pidlRoot = NULL;
191 brws.pszDisplayName = szPath;
192 brws.ulFlags = BIF_BROWSEINCLUDEFILES;
193 brws.lpfn = NULL;
194 pidllist = SHBrowseForFolderW(&brws);
195 if (!pidllist)
196 break;
197
198 if (SHGetPathFromIDListW(pidllist, szPath))
199 SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, WM_SETTEXT, 0, (LPARAM)szPath);
200
201 /* Free memory, if possible */
202 if (SUCCEEDED(SHGetMalloc(&malloc)))
203 {
204 IMalloc_Free(malloc, pidllist);
205 IMalloc_Release(malloc);
206 }
207
208 break;
209 }
210 break;
211 case WM_NOTIFY:
212 lppsn = (LPPSHNOTIFY) lParam;
213 if (lppsn->hdr.code == PSN_WIZNEXT)
214 {
215 pContext = (PCREATE_LINK_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER);
216 SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, WM_GETTEXT, MAX_PATH, (LPARAM)pContext->szTarget);
217 ///
218 /// FIXME
219 /// it should also be possible to create a link to folders, shellobjects etc....
220 ///
221 if (GetFileAttributesW(pContext->szTarget) == INVALID_FILE_ATTRIBUTES)
222 {
223 szDesc[0] = L'\0';
224 szPath[0] = L'\0';
225 if (LoadStringW(hApplet, IDS_CREATE_SHORTCUT, szDesc, 100) < 100 &&
226 LoadStringW(hApplet, IDS_ERROR_NOT_FOUND, szPath, MAX_PATH) < MAX_PATH)
227 {
228 WCHAR szError[MAX_PATH + 100];
229 #ifdef _MSC_VER
230 _swprintf(szError, szPath, pContext->szTarget);
231 #else
232 swprintf(szError, szPath, pContext->szTarget);
233 #endif
234 MessageBoxW(hwndDlg, szError, szDesc, MB_ICONERROR);
235 }
236 SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1);
237 SetFocus(GetDlgItem(hwndDlg, IDC_SHORTCUT_LOCATION));
238 SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
239 return -1;
240 }
241 else
242 {
243 WCHAR * first, *last;
244 wcscpy(pContext->szWorkingDirectory, pContext->szTarget);
245 first = wcschr(pContext->szWorkingDirectory, L'\\');
246 last = wcsrchr(pContext->szWorkingDirectory, L'\\');
247 wcscpy(pContext->szDescription, &last[1]);
248
249 if (first != last)
250 last[0] = L'\0';
251 else
252 first[1] = L'\0';
253
254 first = wcsrchr(pContext->szDescription, L'.');
255
256 if(first)
257 first[0] = L'\0';
258 }
259
260 }
261 break;
262 }
263 return FALSE;
264 }
265
266 INT_PTR
267 CALLBACK
268 FinishDlgProc(HWND hwndDlg,
269 UINT uMsg,
270 WPARAM wParam,
271 LPARAM lParam)
272 {
273 LPPROPSHEETPAGEW ppsp;
274 PCREATE_LINK_CONTEXT pContext;
275 LPPSHNOTIFY lppsn;
276
277 switch(uMsg)
278 {
279 case WM_INITDIALOG:
280 ppsp = (LPPROPSHEETPAGEW)lParam;
281 pContext = (PCREATE_LINK_CONTEXT) ppsp->lParam;
282 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
283 SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_NAME, WM_SETTEXT, 0, (LPARAM)pContext->szDescription);
284 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
285 break;
286 case WM_COMMAND:
287 switch(HIWORD(wParam))
288 {
289 case EN_CHANGE:
290 if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_NAME, WM_GETTEXTLENGTH, 0, 0))
291 {
292 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
293 }
294 else
295 {
296 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
297 }
298 break;
299 }
300 break;
301 case WM_NOTIFY:
302 lppsn = (LPPSHNOTIFY) lParam;
303 pContext = (PCREATE_LINK_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER);
304 if (lppsn->hdr.code == PSN_WIZFINISH)
305 {
306 SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_NAME, WM_GETTEXT, MAX_PATH, (LPARAM)pContext->szDescription);
307 wcscat(pContext->szLinkName, pContext->szDescription);
308 wcscat(pContext->szLinkName, L".lnk");
309 if (!CreateShortcut(pContext))
310 {
311 MessageBox(hwndDlg, _T("Failed to create shortcut"), _T("Error"), MB_ICONERROR);
312 }
313 }
314
315
316 }
317 return FALSE;
318 }
319
320 LONG CALLBACK
321 ShowCreateShortcutWizard(HWND hwndCPl, LPWSTR szPath)
322 {
323 PROPSHEETHEADERW psh;
324 HPROPSHEETPAGE ahpsp[2];
325 PROPSHEETPAGE psp;
326 UINT nPages = 0;
327 UINT nLength;
328 DWORD attrs;
329
330 PCREATE_LINK_CONTEXT pContext = (PCREATE_LINK_CONTEXT) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CREATE_LINK_CONTEXT));
331 if (!pContext)
332 {
333 /* no memory */
334 return FALSE;
335 }
336 nLength = wcslen(szPath);
337 if (!nLength)
338 {
339 HeapFree(GetProcessHeap(), 0, pContext);
340
341 /* no directory given */
342 return FALSE;
343 }
344
345 attrs = GetFileAttributesW(szPath);
346 if (attrs == INVALID_FILE_ATTRIBUTES)
347 {
348 HeapFree(GetProcessHeap(), 0, pContext);
349
350 /* invalid path */
351 return FALSE;
352 }
353
354 wcscpy(pContext->szLinkName, szPath);
355 if (pContext->szLinkName[nLength-1] != L'\\')
356 {
357 pContext->szLinkName[nLength] = L'\\';
358 pContext->szLinkName[nLength+1] = L'\0';
359 }
360
361
362 /* Create the Welcome page */
363 psp.dwSize = sizeof(PROPSHEETPAGE);
364 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
365 psp.hInstance = hApplet;
366 psp.pfnDlgProc = WelcomeDlgProc;
367 psp.pszTemplate = MAKEINTRESOURCEW(IDD_SHORTCUT_LOCATION);
368 psp.lParam = (LPARAM)pContext;
369 ahpsp[nPages++] = CreatePropertySheetPage(&psp);
370
371 /* Create the Finish page */
372 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
373 psp.pfnDlgProc = FinishDlgProc;
374 psp.pszTemplate = MAKEINTRESOURCEW(IDD_SHORTCUT_FINISH);
375 ahpsp[nPages++] = CreatePropertySheetPage(&psp);
376
377
378 /* Create the property sheet */
379 psh.dwSize = sizeof(PROPSHEETHEADER);
380 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK;
381 psh.hInstance = hApplet;
382 psh.hwndParent = NULL;
383 psh.nPages = nPages;
384 psh.nStartPage = 0;
385 psh.phpage = ahpsp;
386 psh.pszbmWatermark = MAKEINTRESOURCEW(IDB_WATERMARK);
387
388 /* Display the wizard */
389 PropertySheet(&psh);
390 HeapFree(GetProcessHeap(), 0, pContext);
391 return TRUE;
392 }
393
394 LONG
395 CALLBACK
396 NewLinkHereW(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
397 {
398 return ShowCreateShortcutWizard(hwndCPl, (LPWSTR) lParam1);
399 }
400
401 LONG
402 CALLBACK
403 NewLinkHereA(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
404 {
405 WCHAR szFile[MAX_PATH];
406
407 if (MultiByteToWideChar(CP_ACP, 0, (LPSTR) lParam1, -1, szFile, MAX_PATH))
408 {
409 return ShowCreateShortcutWizard(hwndCPl, szFile);
410 }
411 return -1;
412 }