- add check for NULL pointer, "first" is NULL for folders, files without extension...
[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
16 BOOL
17 CreateShortcut(PCREATE_LINK_CONTEXT pContext)
18 {
19 IShellLinkW *pShellLink;
20 IPersistFile *pPersistFile;
21 HRESULT hr;
22
23 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_ALL,
24 &IID_IShellLink, (void**)&pShellLink);
25
26 if (hr != S_OK)
27 return FALSE;
28
29
30 pShellLink->lpVtbl->SetPath(pShellLink, pContext->szTarget);
31 pShellLink->lpVtbl->SetDescription(pShellLink, pContext->szDescription);
32 pShellLink->lpVtbl->SetWorkingDirectory(pShellLink, pContext->szWorkingDirectory);
33
34 hr = pShellLink->lpVtbl->QueryInterface(pShellLink, &IID_IPersistFile, (void**)&pPersistFile);
35 if (hr != S_OK)
36 {
37 pShellLink->lpVtbl->Release(pShellLink);
38 return FALSE;
39 }
40
41 hr = pPersistFile->lpVtbl->Save(pPersistFile, pContext->szLinkName, TRUE);
42 pPersistFile->lpVtbl->Release(pPersistFile);
43 pShellLink->lpVtbl->Release(pShellLink);
44 return (hr == S_OK);
45 }
46
47
48
49
50 INT_PTR
51 CALLBACK
52 WelcomeDlgProc(HWND hwndDlg,
53 UINT uMsg,
54 WPARAM wParam,
55 LPARAM lParam)
56 {
57 LPPROPSHEETPAGEW ppsp;
58 PCREATE_LINK_CONTEXT pContext;
59 LPPSHNOTIFY lppsn;
60 WCHAR szPath[MAX_PATH];
61 WCHAR szDesc[100];
62 BROWSEINFOW brws;
63 LPITEMIDLIST pidllist;
64 IMalloc* malloc;
65
66 switch(uMsg)
67 {
68 case WM_INITDIALOG:
69 ppsp = (LPPROPSHEETPAGEW)lParam;
70 pContext = (PCREATE_LINK_CONTEXT) ppsp->lParam;
71 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
72 PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
73 break;
74 case WM_COMMAND:
75 switch(HIWORD(wParam))
76 {
77 case EN_CHANGE:
78 if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, WM_GETTEXTLENGTH, 0, 0))
79 {
80 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
81 }
82 else
83 {
84 PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
85 }
86 break;
87 }
88 switch(LOWORD(wParam))
89 {
90 case IDC_SHORTCUT_BROWSE:
91 ZeroMemory(&brws, sizeof(brws));
92 brws.hwndOwner = hwndDlg;
93 brws.pidlRoot = NULL;
94 brws.pszDisplayName = szPath;
95 brws.ulFlags = BIF_BROWSEINCLUDEFILES;
96 brws.lpfn = NULL;
97 pidllist = SHBrowseForFolder(&brws);
98 if (!pidllist)
99 break;
100
101 if (SHGetPathFromIDList(pidllist, szPath))
102 SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, WM_SETTEXT, 0, (LPARAM)szPath);
103
104 /* Free memory, if possible */
105 if (SUCCEEDED(SHGetMalloc(&malloc)))
106 {
107 IMalloc_Free(malloc, pidllist);
108 IMalloc_Release(malloc);
109 }
110
111 break;
112 }
113 break;
114 case WM_NOTIFY:
115 lppsn = (LPPSHNOTIFY) lParam;
116 if (lppsn->hdr.code == PSN_WIZNEXT)
117 {
118 pContext = (PCREATE_LINK_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER);
119 SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, WM_GETTEXT, MAX_PATH, (LPARAM)pContext->szTarget);
120 ///
121 /// FIXME
122 /// it should also be possible to create a link to folders, shellobjects etc....
123 ///
124 if (GetFileAttributesW(pContext->szTarget) == INVALID_FILE_ATTRIBUTES)
125 {
126 szDesc[0] = L'\0';
127 szPath[0] = L'\0';
128 if (LoadStringW(hApplet, IDS_CREATE_SHORTCUT, szDesc, 100) < 100 &&
129 LoadStringW(hApplet, IDS_ERROR_NOT_FOUND, szPath, MAX_PATH) < MAX_PATH)
130 {
131 WCHAR szError[MAX_PATH + 100];
132 #ifdef _MSC_VER
133 _swprintf(szError, szPath, pContext->szTarget);
134 #else
135 swprintf(szError, szPath, pContext->szTarget);
136 #endif
137 MessageBoxW(hwndDlg, szError, szDesc, MB_ICONERROR);
138 }
139 SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1);
140 SetFocus(GetDlgItem(hwndDlg, IDC_SHORTCUT_LOCATION));
141 SetWindowLong(hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
142 return -1;
143 }
144 else
145 {
146 WCHAR * first, *last;
147 wcscpy(pContext->szWorkingDirectory, pContext->szTarget);
148 first = wcschr(pContext->szWorkingDirectory, L'\\');
149 last = wcsrchr(pContext->szWorkingDirectory, L'\\');
150 wcscpy(pContext->szDescription, &last[1]);
151
152 if (first != last)
153 last[0] = L'\0';
154 else
155 first[1] = L'\0';
156
157 first = wcsrchr(pContext->szDescription, L'.');
158
159 if(first)
160 first[0] = L'\0';
161 }
162
163 }
164 break;
165 }
166 return FALSE;
167 }
168
169 INT_PTR
170 CALLBACK
171 FinishDlgProc(HWND hwndDlg,
172 UINT uMsg,
173 WPARAM wParam,
174 LPARAM lParam)
175 {
176 LPPROPSHEETPAGEW ppsp;
177 PCREATE_LINK_CONTEXT pContext;
178 LPPSHNOTIFY lppsn;
179
180 switch(uMsg)
181 {
182 case WM_INITDIALOG:
183 ppsp = (LPPROPSHEETPAGEW)lParam;
184 pContext = (PCREATE_LINK_CONTEXT) ppsp->lParam;
185 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
186 SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_NAME, WM_SETTEXT, 0, (LPARAM)pContext->szDescription);
187 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
188 break;
189 case WM_COMMAND:
190 switch(HIWORD(wParam))
191 {
192 case EN_CHANGE:
193 if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_NAME, WM_GETTEXTLENGTH, 0, 0))
194 {
195 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
196 }
197 else
198 {
199 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
200 }
201 break;
202 }
203 break;
204 case WM_NOTIFY:
205 lppsn = (LPPSHNOTIFY) lParam;
206 pContext = (PCREATE_LINK_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER);
207 if (lppsn->hdr.code == PSN_WIZFINISH)
208 {
209 SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_NAME, WM_GETTEXT, MAX_PATH, (LPARAM)pContext->szDescription);
210 wcscat(pContext->szLinkName, pContext->szDescription);
211 wcscat(pContext->szLinkName, L".lnk");
212 if (!CreateShortcut(pContext))
213 {
214 MessageBox(hwndDlg, _T("Failed to create shortcut"), _T("Error"), MB_ICONERROR);
215 }
216 }
217
218
219 }
220 return FALSE;
221 }
222
223 LONG CALLBACK
224 ShowCreateShortcutWizard(HWND hwndCPl, LPWSTR szPath)
225 {
226 PROPSHEETHEADERW psh;
227 HPROPSHEETPAGE ahpsp[2];
228 PROPSHEETPAGE psp;
229 UINT nPages = 0;
230 UINT nLength;
231
232 PCREATE_LINK_CONTEXT pContext = (PCREATE_LINK_CONTEXT) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CREATE_LINK_CONTEXT));
233 if (!pContext)
234 {
235 /* no memory */
236 return FALSE;
237 }
238 nLength = wcslen(szPath);
239 if (!nLength)
240 {
241 /* no directory given */
242 return FALSE;
243 }
244 ///
245 /// FIXME
246 /// check if path is valid
247 ///
248
249 wcscpy(pContext->szLinkName, szPath);
250 if (pContext->szLinkName[nLength-1] != L'\\')
251 {
252 pContext->szLinkName[nLength] = L'\\';
253 pContext->szLinkName[nLength+1] = L'\0';
254 }
255
256
257 /* Create the Welcome page */
258 psp.dwSize = sizeof(PROPSHEETPAGE);
259 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
260 psp.hInstance = hApplet;
261 psp.pfnDlgProc = WelcomeDlgProc;
262 psp.pszTemplate = MAKEINTRESOURCE(IDD_SHORTCUT_LOCATION);
263 psp.lParam = (LPARAM)pContext;
264 ahpsp[nPages++] = CreatePropertySheetPage(&psp);
265
266 /* Create the Finish page */
267 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
268 psp.pfnDlgProc = FinishDlgProc;
269 psp.pszTemplate = MAKEINTRESOURCE(IDD_SHORTCUT_FINISH);
270 ahpsp[nPages++] = CreatePropertySheetPage(&psp);
271
272
273 /* Create the property sheet */
274 psh.dwSize = sizeof(PROPSHEETHEADER);
275 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK;
276 psh.hInstance = hApplet;
277 psh.hwndParent = NULL;
278 psh.nPages = nPages;
279 psh.nStartPage = 0;
280 psh.phpage = ahpsp;
281 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
282
283 /* Display the wizard */
284 PropertySheet(&psh);
285 HeapFree(GetProcessHeap(), 0, pContext);
286 return TRUE;
287 }
288
289
290 LONG
291 CALLBACK
292 NewLinkHere(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
293 {
294 WCHAR szFile[MAX_PATH];
295
296 if (MultiByteToWideChar(CP_ACP, 0, (char*)lParam1, strlen((char*)lParam1)+1, szFile, MAX_PATH))
297 {
298 return ShowCreateShortcutWizard(hwndCPl, szFile);
299 }
300 return -1;
301 }
302
303
304 LONG
305 CALLBACK
306 NewLinkHereW(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
307 {
308 return ShowCreateShortcutWizard(hwndCPl, (LPWSTR)lParam1);
309 }
310
311 LONG
312 CALLBACK
313 NewLinkHereA(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
314 {
315 WCHAR szFile[MAX_PATH];
316
317 if (MultiByteToWideChar(CP_ACP, 0, (char*)lParam1, strlen((char*)lParam1)+1, szFile, MAX_PATH))
318 {
319 return ShowCreateShortcutWizard(hwndCPl, szFile);
320 }
321 return -1;
322 }