1 /*
2 * PROJECT: ReactOS Applications
3 * LICENSE: LGPL - See COPYING in the top level directory
4 * FILE: base/applications/msconfig_new/toolspage.cpp
5 * PURPOSE: Tools page message handler
6 * COPYRIGHT: Copyright 2005-2006 Christoph von Wittich <Christoph@ApiViewer.de>
7 * Copyright 2011-2012 Hermes BELUSCA - MAITO <hermes.belusca@sfr.fr>
8 */
9
10 #include "precomp.h"
11 #include "xmldomparser.hpp"
12 #include "utils.h"
13 #include "listview.h"
14 #include "uxthemesupp.h"
15
16 static HWND hToolsPage = NULL;
17 static HWND hToolsListCtrl = NULL;
18 static int iToolsPageSortedColumn = 0;
19
20 struct TOOL
21 {
TOOLTOOL22 TOOL(const _bstr_t& Command,
23 const _bstr_t& DefParam,
24 const _bstr_t& AdvParam) :
25 m_Command(Command),
26 m_DefParam(DefParam),
27 m_AdvParam(AdvParam)
28 { }
29
~TOOLTOOL30 ~TOOL(void)
31 { }
32
RunTOOL33 DWORD Run(BOOL bUseAdvParams)
34 {
35 return RunCommand(m_Command, bUseAdvParams ? m_AdvParam : m_DefParam, SW_SHOW);
36 }
37
38 _bstr_t m_Command;
39 _bstr_t m_DefParam;
40 _bstr_t m_AdvParam;
41 };
42
43 static void AddTool(IXMLDOMElement*, BOOL);
44
45 static HRESULT
ParseToolsList(IXMLDOMDocument * pXMLDom,BOOL bIsStandard)46 ParseToolsList(IXMLDOMDocument* pXMLDom, BOOL bIsStandard)
47 {
48 static const _bstr_t XMLFileTag(L"MSCONFIGTOOLFILE");
49 static const _bstr_t XMLToolsTag(L"MSCONFIGTOOLS");
50
51 HRESULT hr = S_OK;
52
53 IXMLDOMNode *pIterator = NULL, *pTmp = NULL;
54 IXMLDOMElement* pEl = NULL;
55 DOMNodeType type;
56 _bstr_t tagName;
57
58 if (!pXMLDom)
59 return E_POINTER; // E_INVALIDARG
60
61 pXMLDom->get_documentElement(&pEl);
62
63 pEl->get_tagName(&tagName.GetBSTR());
64 _wcsupr(tagName);
65 if (tagName == XMLFileTag)
66 {
67 pEl->get_firstChild(&pIterator); SAFE_RELEASE(pEl);
68 while (pIterator)
69 {
70 pIterator->get_nodeType(&type);
71 if (type == NODE_ELEMENT)
72 {
73 pIterator->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pEl) /* IID_PPV_ARGS(&pEl) */);
74
75 pEl->get_tagName(&tagName.GetBSTR());
76 _wcsupr(tagName);
77 if (tagName == XMLToolsTag)
78 {
79 pEl->get_firstChild(&pIterator); SAFE_RELEASE(pEl);
80 while (pIterator)
81 {
82 pIterator->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pEl) /* IID_PPV_ARGS(&pEl) */);
83 AddTool(pEl, bIsStandard);
84 SAFE_RELEASE(pEl);
85
86 pIterator->get_nextSibling(&pTmp);
87 SAFE_RELEASE(pIterator); pIterator = pTmp;
88 }
89 // SAFE_RELEASE(pIterator);
90
91 break;
92 }
93
94 SAFE_RELEASE(pEl);
95 }
96
97 pIterator->get_nextSibling(&pTmp);
98 SAFE_RELEASE(pIterator); pIterator = pTmp;
99 }
100 // SAFE_RELEASE(pIterator);
101 }
102 else if (tagName == XMLToolsTag)
103 {
104 pEl->get_firstChild(&pIterator); SAFE_RELEASE(pEl);
105 while (pIterator)
106 {
107 pIterator->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pEl) /* IID_PPV_ARGS(&pEl) */);
108 AddTool(pEl, bIsStandard);
109 SAFE_RELEASE(pEl);
110
111 pIterator->get_nextSibling(&pTmp);
112 SAFE_RELEASE(pIterator); pIterator = pTmp;
113 }
114 // SAFE_RELEASE(pIterator);
115 }
116
117 SAFE_RELEASE(pEl);
118
119 return hr;
120 }
121
122 static void
AddItem(BOOL bIsStandard,const _bstr_t & name,const _bstr_t & descr,TOOL * tool)123 AddItem(BOOL bIsStandard, const _bstr_t& name, const _bstr_t& descr, TOOL* tool)
124 {
125 LPWSTR lpszStandard;
126 LVITEM item = {};
127
128 assert(tool);
129
130 item.mask = LVIF_TEXT | LVIF_PARAM;
131 item.lParam = (LPARAM)tool;
132
133 item.pszText = (LPWSTR)name;
134 item.iSubItem = 0;
135 // item.iItem = ListView_GetItemCount(hToolsListCtrl);
136
137 ListView_InsertItem(hToolsListCtrl, &item);
138
139 if (bIsStandard)
140 {
141 lpszStandard = LoadResourceString(hInst, IDS_YES);
142 ListView_SetItemText(hToolsListCtrl, item.iItem, 1, lpszStandard);
143 MemFree(lpszStandard);
144 }
145 else
146 {
147 lpszStandard = LoadResourceString(hInst, IDS_NO);
148 ListView_SetItemText(hToolsListCtrl, item.iItem, 1, lpszStandard);
149 MemFree(lpszStandard);
150 }
151
152 ListView_SetItemText(hToolsListCtrl, item.iItem, 2, (LPWSTR)descr);
153 }
154
155 static void
AddTool(IXMLDOMElement * pXMLTool,BOOL bIsStandard)156 AddTool(IXMLDOMElement* pXMLTool, BOOL bIsStandard)
157 {
158 TOOL* tool;
159 _variant_t varLocID, varName, varPath,
160 varDefOpt, varAdvOpt, varHelp;
161
162 assert(pXMLTool);
163
164 pXMLTool->getAttribute(_bstr_t(L"_locID") , &varLocID );
165 pXMLTool->getAttribute(_bstr_t(L"NAME") , &varName );
166 pXMLTool->getAttribute(_bstr_t(L"PATH") , &varPath );
167 pXMLTool->getAttribute(_bstr_t(L"DEFAULT_OPT"), &varDefOpt);
168 pXMLTool->getAttribute(_bstr_t(L"ADV_OPT") , &varAdvOpt);
169 pXMLTool->getAttribute(_bstr_t(L"HELP") , &varHelp );
170
171 // TODO: check if the tool really exists... ??
172
173 tool = new TOOL(_bstr_t(varPath), _bstr_t(varDefOpt), _bstr_t(varAdvOpt));
174 AddItem(bIsStandard, _bstr_t(varName), _bstr_t(varHelp), tool);
175 }
176
177 static void
FillListView(void)178 FillListView(void)
179 {
180 IXMLDOMDocument* pXMLDom = NULL;
181
182 if (!SUCCEEDED(InitXMLDOMParser()))
183 return;
184
185 if (SUCCEEDED(CreateAndInitXMLDOMDocument(&pXMLDom)))
186 {
187 // Load the internal tools list.
188 if (LoadXMLDocumentFromResource(pXMLDom, L"MSCFGTL.XML"))
189 ParseToolsList(pXMLDom, TRUE);
190
191 // Try to load the user-provided tools list. If it doesn't exist,
192 // then the second list-view's column "Standard" tool is removed.
193 if (LoadXMLDocumentFromFile(pXMLDom, L"MSCFGTLC.XML", TRUE))
194 ParseToolsList(pXMLDom, FALSE);
195 else
196 ListView_DeleteColumn(hToolsListCtrl, 1);
197 }
198
199 SAFE_RELEASE(pXMLDom);
200 UninitXMLDOMParser();
201 }
202
203 static size_t
BuildCommandLine(LPWSTR lpszDest,LPCWSTR lpszCmdLine,LPCWSTR lpszParam,size_t bufSize)204 BuildCommandLine(LPWSTR lpszDest, LPCWSTR lpszCmdLine, LPCWSTR lpszParam, size_t bufSize)
205 {
206 size_t numOfChars = 0; // The null character is counted in ExpandEnvironmentStrings(...).
207 // TODO: Take into account the "plus one" for numOfChars for ANSI version (see MSDN for more details).
208
209 if (lpszCmdLine && *lpszCmdLine)
210 {
211 numOfChars += ExpandEnvironmentStringsW(lpszCmdLine, NULL, 0);
212 if (lpszDest)
213 ExpandEnvironmentStringsW(lpszCmdLine, lpszDest, (DWORD)bufSize); // TODO: size_t to DWORD conversion !
214
215 if (lpszParam && *lpszParam)
216 {
217 ++numOfChars;
218 if (lpszDest)
219 wcscat(lpszDest, L" ");
220 }
221 }
222
223 if (lpszParam && *lpszParam)
224 {
225 numOfChars += wcslen(lpszParam);
226 if (lpszDest)
227 wcscat(lpszDest, lpszParam);
228 }
229
230 return numOfChars;
231 }
232
Update_States(int iSelectedItem)233 static void Update_States(int iSelectedItem)
234 {
235 TOOL* tool;
236 LVITEM item = {};
237
238 assert(hToolsPage);
239
240 item.mask = LVIF_PARAM;
241 item.iItem = iSelectedItem;
242
243 if (ListView_GetItem(hToolsListCtrl, &item)) // (item.iItem > -1) // TODO: corriger ailleurs ce genre de code...
244 {
245 LPWSTR lpszCmdLine = NULL;
246 size_t numOfChars = 0;
247 tool = reinterpret_cast<TOOL*>(item.lParam);
248
249 ListView_EnsureVisible(hToolsListCtrl, item.iItem, FALSE);
250
251 Button_Enable(GetDlgItem(hToolsPage, IDC_BTN_RUN), TRUE);
252
253 if (!*(wchar_t*)tool->m_AdvParam)
254 {
255 ShowWindow(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), SW_HIDE);
256 Button_Enable(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), FALSE);
257 }
258 else
259 {
260 Button_Enable(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), TRUE);
261 ShowWindow(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), SW_NORMAL);
262 }
263
264 if ( (Button_IsEnabled(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT))) &&
265 (Button_GetCheck(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT)) == BST_CHECKED) )
266 {
267 numOfChars = BuildCommandLine(NULL, tool->m_Command, tool->m_AdvParam, 0);
268 lpszCmdLine = (LPWSTR)MemAlloc(0, numOfChars * sizeof(WCHAR));
269 BuildCommandLine(lpszCmdLine, tool->m_Command, tool->m_AdvParam, numOfChars);
270 }
271 else
272 {
273 numOfChars = BuildCommandLine(NULL, tool->m_Command, tool->m_DefParam, 0);
274 lpszCmdLine = (LPWSTR)MemAlloc(0, numOfChars * sizeof(WCHAR));
275 BuildCommandLine(lpszCmdLine, tool->m_Command, tool->m_DefParam, numOfChars);
276 }
277
278 SendDlgItemMessage(hToolsPage, IDC_TOOLS_CMDLINE, WM_SETTEXT, 0, (LPARAM)lpszCmdLine);
279
280 MemFree(lpszCmdLine);
281 }
282 else
283 {
284 ShowWindow(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), SW_HIDE);
285 Button_Enable(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), FALSE);
286 Button_Enable(GetDlgItem(hToolsPage, IDC_BTN_RUN), FALSE);
287 }
288 }
289
RunSelectedTool(VOID)290 static BOOL RunSelectedTool(VOID)
291 {
292 BOOL Success = FALSE;
293 BOOL bUseAdvParams;
294
295 LVITEM item = {};
296 item.mask = LVIF_PARAM;
297 item.iItem = ListView_GetSelectionMark(hToolsListCtrl);
298 ListView_GetItem(hToolsListCtrl, &item);
299
300 if (ListView_GetItem(hToolsListCtrl, &item)) // (item.iItem > -1) // TODO: corriger ailleurs ce genre de code...
301 {
302 if ( (Button_IsEnabled(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT))) &&
303 (Button_GetCheck(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT)) == BST_CHECKED) )
304 bUseAdvParams = TRUE;
305 else
306 bUseAdvParams = FALSE;
307
308 // Values greater (strictly) than 32 indicate success (see MSDN documentation for ShellExecute(...) API).
309 Success = (reinterpret_cast<TOOL*>(item.lParam)->Run(bUseAdvParams) > 32);
310 }
311
312 return Success;
313 }
314
315 extern "C" {
316
317 INT_PTR CALLBACK
ToolsPageWndProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)318 ToolsPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
319 {
320 switch (message)
321 {
322 case WM_INITDIALOG:
323 {
324 hToolsPage = hDlg;
325 hToolsListCtrl = GetDlgItem(hToolsPage, IDC_TOOLS_LIST);
326
327 //
328 // Initialize the styles.
329 //
330 DWORD dwStyle = ListView_GetExtendedListViewStyle(hToolsListCtrl);
331 ListView_SetExtendedListViewStyle(hToolsListCtrl, dwStyle | LVS_EX_FULLROWSELECT);
332 SetWindowTheme(hToolsListCtrl, L"Explorer", NULL);
333
334 //
335 // Initialize the application page's controls.
336 //
337 LVCOLUMN column = {};
338
339 // First column : Tool's name.
340 column.mask = LVCF_TEXT | LVCF_WIDTH;
341 column.pszText = LoadResourceString(hInst, IDS_TOOLS_COLUMN_NAME);
342 column.cx = 150;
343 ListView_InsertColumn(hToolsListCtrl, 0, &column);
344 MemFree(column.pszText);
345
346 // Second column : Whether the tool is a standard one or not.
347 column.mask = LVCF_TEXT | LVCF_WIDTH;
348 column.pszText = LoadResourceString(hInst, IDS_TOOLS_COLUMN_STANDARD);
349 column.cx = 60;
350 ListView_InsertColumn(hToolsListCtrl, 1, &column);
351 MemFree(column.pszText);
352
353 // Third column : Description.
354 column.mask = LVCF_TEXT | LVCF_WIDTH;
355 column.pszText = LoadResourceString(hInst, IDS_TOOLS_COLUMN_DESCR);
356 column.cx = 500;
357 ListView_InsertColumn(hToolsListCtrl, 2, &column);
358 MemFree(column.pszText);
359
360 //
361 // Populate and sort the list.
362 //
363 FillListView();
364 ListView_Sort(hToolsListCtrl, 0);
365
366 // Force an update in case of an empty list (giving focus on it when empty won't emit a LVN_ITEMCHANGED message).
367 Update_States(-1 /* Wrong index to initialize all the controls with their default state (i.e. disabled) */);
368
369 PropSheet_UnChanged(GetParent(hToolsPage), hToolsPage);
370
371 return TRUE;
372 }
373
374 case WM_DESTROY:
375 {
376 LVITEM lvitem = {};
377 lvitem.mask = LVIF_PARAM;
378 lvitem.iItem = -1; // From the beginning.
379
380 while ((lvitem.iItem = ListView_GetNextItem(hToolsListCtrl, lvitem.iItem, LVNI_ALL)) != -1)
381 {
382 // ListView_Update(); // Updates a list-view item.
383 // ListView_FindItem(); // peut �tre int�ressant pour faire de la recherche it�rative � partir du nom (ou partie du...) de l'item.
384
385 ListView_GetItem(hToolsListCtrl, &lvitem);
386
387 delete reinterpret_cast<TOOL*>(lvitem.lParam);
388 lvitem.lParam = NULL;
389 }
390 ListView_DeleteAllItems(hToolsListCtrl);
391
392 return 0;
393 }
394
395 case WM_COMMAND:
396 {
397 switch (LOWORD(wParam))
398 {
399 case IDC_BTN_RUN:
400 {
401 RunSelectedTool();
402 return TRUE;
403 }
404
405 case IDC_CBX_TOOLS_ADVOPT:
406 {
407 Update_States(ListView_GetSelectionMark(hToolsListCtrl));
408 return TRUE;
409 }
410
411 default:
412 return FALSE;
413 }
414 return FALSE;
415 }
416
417 case WM_NOTIFY:
418 {
419 if (((LPNMHDR)lParam)->hwndFrom == hToolsListCtrl)
420 {
421 switch (((LPNMHDR)lParam)->code)
422 {
423 case LVN_ITEMCHANGED:
424 {
425 if ( (((LPNMLISTVIEW)lParam)->uChanged & LVIF_STATE) && /* The state has changed */
426 (((LPNMLISTVIEW)lParam)->uNewState & LVIS_SELECTED) /* The item has been (de)selected */ )
427 {
428 Update_States(((LPNMLISTVIEW)lParam)->iItem);
429 }
430
431 return TRUE;
432 }
433
434 case NM_DBLCLK:
435 case NM_RDBLCLK:
436 {
437 RunSelectedTool();
438 return TRUE;
439 }
440
441 case LVN_COLUMNCLICK:
442 {
443 int iSortingColumn = ((LPNMLISTVIEW)lParam)->iSubItem;
444
445 ListView_SortEx(hToolsListCtrl, iSortingColumn, iToolsPageSortedColumn);
446 iToolsPageSortedColumn = iSortingColumn;
447
448 return TRUE;
449 }
450
451 default:
452 break;
453 }
454 }
455 else
456 {
457 switch (((LPNMHDR)lParam)->code)
458 {
459 case PSN_APPLY:
460 {
461 // Since there are nothing to modify, applying modifications
462 // cannot return any error.
463 SetWindowLongPtr(hToolsPage, DWLP_MSGRESULT, PSNRET_NOERROR);
464 PropSheet_UnChanged(GetParent(hToolsPage), hToolsPage);
465 return TRUE;
466 }
467
468 case PSN_HELP:
469 {
470 MessageBoxW(hToolsPage, L"Help not implemented yet!", L"Help", MB_ICONINFORMATION | MB_OK);
471 return TRUE;
472 }
473
474 case PSN_KILLACTIVE: // Is going to lose activation.
475 {
476 // Changes are always valid of course.
477 SetWindowLongPtr(hToolsPage, DWLP_MSGRESULT, FALSE);
478 return TRUE;
479 }
480
481 case PSN_QUERYCANCEL:
482 {
483 // Allows cancellation since there are nothing to cancel...
484 SetWindowLongPtr(hToolsPage, DWLP_MSGRESULT, FALSE);
485 return TRUE;
486 }
487
488 case PSN_QUERYINITIALFOCUS:
489 {
490 // Give the focus on and select the first item.
491 ListView_SetItemState(hToolsListCtrl, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
492
493 SetWindowLongPtr(hToolsPage, DWLP_MSGRESULT, (LONG_PTR)hToolsListCtrl);
494 return TRUE;
495 }
496
497 //
498 // DO NOT TOUCH THESE NEXT MESSAGES, THEY ARE OK LIKE THIS...
499 //
500 case PSN_RESET: // Perform final cleaning, called before WM_DESTROY.
501 return TRUE;
502
503 case PSN_SETACTIVE: // Is going to gain activation.
504 {
505 SetWindowLongPtr(hToolsPage, DWLP_MSGRESULT, 0);
506 return TRUE;
507 }
508
509 default:
510 break;
511 }
512 }
513
514 return FALSE;
515 }
516
517 default:
518 return FALSE;
519 }
520
521 // return FALSE;
522 }
523
524 }
525
526 /* EOF */
527