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 { 22 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 30 ~TOOL(void) 31 { } 32 33 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 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 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 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 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 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 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 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 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