Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6487 lines
191 KiB

  1. // ARP.cpp : Add Remove Programs
  2. //
  3. #include "priv.h"
  4. #define GADGET_ENABLE_TRANSITIONS
  5. // Related services
  6. #include <duser.h>
  7. #include <directui.h>
  8. #include "stdafx.h"
  9. #include "appwizid.h"
  10. #include "resource.h"
  11. #include <winable.h> // BlockInput
  12. #include <process.h> // Multi-threaded routines
  13. #include "setupenum.h"
  14. #include <tsappcmp.h> // for TermsrvAppInstallMod
  15. #include <comctrlp.h> // for DPA stuff
  16. #include "util.h"
  17. #include <shstyle.h>
  18. using namespace DirectUI;
  19. UsingDUIClass(Element);
  20. UsingDUIClass(Button);
  21. UsingDUIClass(RepeatButton); // used by ScrollBar
  22. UsingDUIClass(Thumb); // used by ScrollBar
  23. UsingDUIClass(ScrollBar); // used by ScrollViewer
  24. UsingDUIClass(Selector);
  25. UsingDUIClass(HWNDElement);
  26. UsingDUIClass(ScrollViewer);
  27. UsingDUIClass(Combobox);
  28. #include "shappmgrp.h"
  29. #include "arp.h"
  30. #define HRCHK(r) if (FAILED(r)) goto Cleanup;
  31. // Primary thread run flag
  32. bool g_fRun = true;
  33. // Appliction shutting down after run flag goes false
  34. bool g_fAppShuttingDown = false;
  35. void CALLBACK ARPParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine);
  36. inline void StrFree(LPWSTR psz)
  37. {
  38. CoTaskMemFree(psz); // CoTaskMemFree handles NULL parameter
  39. }
  40. // Need this weirdo helper function to avoid compiler complaining that
  41. // "bool is smaller than LPARAM, you're truncating!" Do this only if
  42. // you know that the LPARAM came from a bool originally.
  43. bool UNCASTLPARAMTOBOOL(LPARAM lParam)
  44. {
  45. return (bool&)lParam;
  46. }
  47. extern "C" void inline SetElementAccessability(Element* pe, bool bAccessible, int iRole, LPCWSTR pszAccName);
  48. // Client names are compared in English to avoid weirdness
  49. // with collation rules of certain languages.
  50. inline bool AreEnglishStringsEqual(LPCTSTR psz1, LPCTSTR psz2)
  51. {
  52. return CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, psz1, -1, psz2, -1) == CSTR_EQUAL;
  53. }
  54. //
  55. // Set the default action based on a resource ID in oleacc.
  56. //
  57. HRESULT SetDefAction(Element* pe, UINT oleacc)
  58. {
  59. WCHAR szBuf[80];
  60. if (!GetRoleTextW(oleacc, szBuf, DUIARRAYSIZE(szBuf)))
  61. {
  62. szBuf[0] = TEXT('\0');
  63. }
  64. return pe->SetAccDefAction(szBuf);
  65. }
  66. ////////////////////////////////////////////////////////
  67. // Tree traversal upwards
  68. //
  69. Element* _FindAncestorElement(Element* pe, IClassInfo* Class)
  70. {
  71. while (pe && !pe->GetClassInfo()->IsSubclassOf(Class))
  72. {
  73. pe = pe->GetParent();
  74. }
  75. return pe;
  76. }
  77. template<class T>
  78. T* FindAncestorElement(Element *pe)
  79. {
  80. return (T*)_FindAncestorElement(pe, T::Class);
  81. }
  82. ////////////////////////////////////////////////////////
  83. // Tree traversal downwards
  84. //
  85. typedef HRESULT (CALLBACK *_TRAVERSETREECB)(Element*, LPARAM);
  86. //
  87. // _TraverseTree is the worker function for TraverseTree<T>.
  88. HRESULT _TraverseTree(Element* pe, IClassInfo* Class, _TRAVERSETREECB lpfnCB, LPARAM lParam)
  89. {
  90. HRESULT hr = S_OK;
  91. Value* pv;
  92. if (pe->GetClassInfo()->IsSubclassOf(Class)) {
  93. hr = lpfnCB(pe, lParam);
  94. }
  95. if (SUCCEEDED(hr))
  96. {
  97. ElementList* peList = pe->GetChildren(&pv);
  98. if (peList)
  99. {
  100. Element* peChild;
  101. for (UINT i = 0; SUCCEEDED(hr) && i < peList->GetSize(); i++)
  102. {
  103. peChild = peList->GetItem(i);
  104. hr = _TraverseTree(peChild, Class, lpfnCB, lParam);
  105. }
  106. pv->Release();
  107. }
  108. }
  109. return hr;
  110. }
  111. // TraverseTree<T> walks the tree starting at pe and calls the callback
  112. // for each element of type T. T is inferred from the callback function,
  113. // but for readability, it is suggested that you state it explicitly.
  114. //
  115. // Callback should return S_OK to continue enumeration or a COM error
  116. // to stop enumeration, in which case the COM error code is returned as
  117. // the return value from TraverseTree.
  118. //
  119. template <class T>
  120. HRESULT TraverseTree(Element* pe,
  121. HRESULT (CALLBACK *lpfnCB)(T*, LPARAM), LPARAM lParam = 0)
  122. {
  123. return _TraverseTree(pe, T::Class, (_TRAVERSETREECB)lpfnCB, lParam);
  124. }
  125. ////////////////////////////////////////////////////////
  126. //
  127. // When chunks of the tree go UI-inactive, you must manually
  128. // enable and disable accessibility on them.
  129. HRESULT DisableElementAccessibilityCB(Element* pe, LPARAM)
  130. {
  131. pe->SetAccessible(false);
  132. return S_OK;
  133. }
  134. HRESULT CheckAndEnableElementAccessibilityCB(Element* pe, LPARAM)
  135. {
  136. if ( 0 != pe->GetAccRole())
  137. {
  138. pe->SetAccessible(true);
  139. }
  140. return S_OK;
  141. }
  142. void DisableElementTreeAccessibility(Element* pe)
  143. {
  144. TraverseTree(pe, DisableElementAccessibilityCB);
  145. }
  146. void EnableElementTreeAccessibility(Element* pe)
  147. {
  148. TraverseTree(pe, CheckAndEnableElementAccessibilityCB);
  149. }
  150. HRESULT DisableElementShortcutCB(Element* pe, LPARAM)
  151. {
  152. pe->SetShortcut(0);
  153. return S_OK;
  154. }
  155. // When a tree is hidden or removed from layout permanently (due to
  156. // restriction), we also have to remove all keyboard shortcuts so the
  157. // user doesn't have a backdoor.
  158. //
  159. void DisableElementTreeShortcut(Element* pe)
  160. {
  161. pe->SetVisible(false);
  162. TraverseTree(pe, DisableElementShortcutCB);
  163. }
  164. ////////////////////////////////////////////////////////
  165. // ARPFrame class
  166. ////////////////////////////////////////////////////////
  167. // ARPFrame IDs (for identifying targets of events)
  168. ATOM ARPFrame::_idChange = 0;
  169. ATOM ARPFrame::_idAddNew = 0;
  170. ATOM ARPFrame::_idAddRmWin = 0;
  171. ATOM ARPFrame::_idClose = 0;
  172. ATOM ARPFrame::_idAddFromDisk = 0;
  173. ATOM ARPFrame::_idAddFromMsft = 0;
  174. ATOM ARPFrame::_idComponents = 0;
  175. ATOM ARPFrame::_idSortCombo = 0;
  176. ATOM ARPFrame::_idCategoryCombo = 0;
  177. ATOM ARPFrame::_idAddFromCDPane = 0;
  178. ATOM ARPFrame::_idAddFromMSPane = 0;
  179. ATOM ARPFrame::_idAddFromNetworkPane = 0;
  180. ATOM ARPFrame::_idAddWinComponent = 0;
  181. ATOM ARPFrame::_idPickApps = 0;
  182. ATOM ARPFrame::_idOptionList = 0;
  183. HANDLE ARPFrame::htPopulateInstalledItemList = NULL;
  184. HANDLE ARPFrame::htPopulateAndRenderOCSetupItemList = NULL;
  185. HANDLE ARPFrame::htPopulateAndRenderPublishedItemList = NULL;
  186. ARPFrame::~ARPFrame()
  187. {
  188. UINT i;
  189. if (_psacl)
  190. {
  191. for (i = 0; i < _psacl->cCategories; i++)
  192. {
  193. if (_psacl->pCategory[i].pszCategory)
  194. {
  195. StrFree(_psacl->pCategory[i].pszCategory);
  196. }
  197. }
  198. delete _psacl;
  199. }
  200. if (_pParserStyle)
  201. _pParserStyle->Destroy();
  202. // Close theme handles (if applicable)
  203. for (i = FIRSTHTHEME; i <= LASTHTHEME; i++)
  204. {
  205. if (_arH[i])
  206. CloseThemeData(_arH[i]);
  207. }
  208. if (_arH[SHELLSTYLEHINSTANCE])
  209. {
  210. FreeLibrary((HMODULE)_arH[SHELLSTYLEHINSTANCE]);
  211. }
  212. EndProgressDialog();
  213. }
  214. HRESULT ARPFrame::Create(OUT Element** ppElement)
  215. {
  216. UNREFERENCED_PARAMETER(ppElement);
  217. DUIAssertForce("Cannot instantiate an HWND host derived Element via parser. Must use substitution.");
  218. return E_NOTIMPL;
  219. }
  220. HRESULT ARPFrame::Create(NativeHWNDHost* pnhh, bool fDblBuffer, OUT Element** ppElement)
  221. {
  222. *ppElement = NULL;
  223. ARPFrame* paf = HNewAndZero<ARPFrame>();
  224. if (!paf)
  225. return E_OUTOFMEMORY;
  226. HRESULT hr = paf->Initialize(pnhh, fDblBuffer);
  227. if (FAILED(hr))
  228. {
  229. paf->Destroy();
  230. return hr;
  231. }
  232. *ppElement = paf;
  233. return S_OK;
  234. }
  235. HRESULT ARPFrame::Initialize(NativeHWNDHost* pnhh, bool fDblBuffer)
  236. {
  237. // Initialize
  238. _pnhh = pnhh;
  239. _bDoubleBuffer = fDblBuffer;
  240. _pParserStyle = NULL;
  241. ZeroMemory(_arH, sizeof(_arH));
  242. _fThemedStyle = FALSE;
  243. _pParserStyle = NULL;
  244. _hdsaInstalledItems = NULL;
  245. _hdsaPublishedItems = NULL;
  246. _bAnimationEnabled = true;
  247. if (IsOS(OS_TERMINALSERVER))
  248. {
  249. _bTerminalServer = true;
  250. }
  251. else
  252. {
  253. _bTerminalServer = false;
  254. }
  255. // Do base class initialization
  256. HRESULT hr = HWNDElement::Initialize(pnhh->GetHWND(), fDblBuffer, 0);
  257. if (FAILED(hr))
  258. return hr;
  259. CurrentSortType = SORT_NAME;
  260. hr = CreateStyleParser(&_pParserStyle);
  261. if (FAILED(hr) || !_pParserStyle || _pParserStyle->WasParseError())
  262. return hr;
  263. ManageAnimations();
  264. return S_OK;
  265. }
  266. HRESULT ARPFrame::CreateStyleParser(Parser** ppParser)
  267. {
  268. HRESULT hr;
  269. // We always need these two
  270. _arH[THISDLLHINSTANCE] = g_hinst; // Default HINSTANCE
  271. _arH[XPSP1HINSTANCE] = g_hinst; // same HINSTANCE
  272. // And this one
  273. if (_arH[SHELLSTYLEHINSTANCE])
  274. {
  275. FreeLibrary((HMODULE)_arH[SHELLSTYLEHINSTANCE]);
  276. }
  277. _arH[SHELLSTYLEHINSTANCE] = SHGetShellStyleHInstance();
  278. // Store style and theme information
  279. // We cannot trust IsAppThemed() or IsThemeActive() because WindowBlinds
  280. // patches them to return hard-coded TRUE. If we trusted it, then
  281. // we would think that we're using a theme-enabled shellstyle.dll and
  282. // fail when we try to load resources out of it. Instead, sniff
  283. // the DLL to see if it has a control panel watermark bitmap.
  284. if (FindResource((HMODULE)_arH[SHELLSTYLEHINSTANCE],
  285. MAKEINTRESOURCE(IDB_CPANEL_WATERMARK), RT_BITMAP))
  286. {
  287. _fThemedStyle = TRUE;
  288. // Populate handle list for theme style parsing
  289. _arH[BUTTONHTHEME] = OpenThemeData(GetHWND(), L"Button");
  290. _arH[SCROLLBARHTHEME] = OpenThemeData(GetHWND(), L"Scrollbar");
  291. _arH[TOOLBARHTHEME] = OpenThemeData(GetHWND(), L"Toolbar");
  292. hr = Parser::Create(IDR_ARPSTYLETHEME, _arH, ARPParseError, ppParser);
  293. }
  294. else
  295. {
  296. _fThemedStyle = FALSE;
  297. hr = Parser::Create(IDR_ARPSTYLESTD, _arH, ARPParseError, ppParser);
  298. }
  299. return hr;
  300. }
  301. extern "C" DWORD _cdecl ARPIsRestricted(LPCWSTR pszPolicy);
  302. extern "C" bool _cdecl ARPIsOnDomain();
  303. // Handy helper functions.
  304. // Finds a descendent and asserts if not found.
  305. Element* FindDescendentByName(Element* peRoot, LPCWSTR pszName)
  306. {
  307. Element* pe = peRoot->FindDescendent(StrToID(pszName));
  308. DUIAssertNoMsg(pe);
  309. return pe;
  310. }
  311. // Finds a descendent but doesn't complain if not found.
  312. Element* MaybeFindDescendentByName(Element* peRoot, LPCWSTR pszName)
  313. {
  314. Element* pe = peRoot->FindDescendent(StrToID(pszName));
  315. return pe;
  316. }
  317. HRESULT _SendParseCompleted(ClientBlock* pcb, LPARAM lParam)
  318. {
  319. return pcb->ParseCompleted((ARPFrame*)lParam);
  320. }
  321. // Initialize IDs and hold parser, called after contents are filled
  322. bool ARPFrame::Setup(Parser* pParser, int uiStartPane)
  323. {
  324. WCHAR szTemp[1024];
  325. _pParser = pParser;
  326. if (uiStartPane >= 0 && uiStartPane <= 3)
  327. {
  328. _uiStartPane = uiStartPane;
  329. }
  330. // Initialize ID cache
  331. _idChange = StrToID(L"change");
  332. _idAddNew = StrToID(L"addnew");
  333. _idAddRmWin = StrToID(L"addrmwin");
  334. _idClose = StrToID(L"close");
  335. _idAddFromDisk = StrToID(L"addfromdisk");
  336. _idAddFromMsft = StrToID(L"addfrommsft");
  337. _idComponents = StrToID(L"components");
  338. _idSortCombo = StrToID(L"sortcombo");
  339. _idCategoryCombo = StrToID(L"categorycombo");
  340. _idAddFromCDPane = StrToID(L"addfromCDPane");
  341. _idAddFromMSPane = StrToID(L"addfromMSpane");
  342. _idAddFromNetworkPane = StrToID(L"addfromNetworkpane");
  343. _idAddWinComponent = StrToID(L"addwincomponent");
  344. _idPickApps = StrToID(L"pickapps");
  345. _idOptionList = StrToID(L"optionlist");
  346. // Find children
  347. _peOptionList = (ARPSelector*) FindDescendentByName(this, L"optionlist");
  348. _peInstalledItemList = (Selector*) FindDescendentByName(this, L"installeditemlist");
  349. _pePublishedItemList = (Selector*) FindDescendentByName(this, L"publisheditemlist");
  350. _peOCSetupItemList = (Selector*) FindDescendentByName(this, L"ocsetupitemlist");
  351. _peSortCombo = (Combobox*) FindDescendentByName(this, L"sortcombo");
  352. _pePublishedCategory = (Combobox*) FindDescendentByName(this, L"categorycombo");
  353. _pePublishedCategoryLabel = (Element*) FindDescendentByName(this, L"categorylabel");
  354. _peClientTypeList = (ARPSelector*) FindDescendentByName(this, L"clienttypelist");
  355. _peOEMClients = (Expando*) FindDescendentByName(_peClientTypeList, L"oemclients");
  356. _peMSClients = (Expando*) FindDescendentByName(_peClientTypeList, L"msclients");
  357. _peNonMSClients = (Expando*) FindDescendentByName(_peClientTypeList, L"nonmsclients");
  358. _peCustomClients = (Expando*) FindDescendentByName(_peClientTypeList, L"customclients");
  359. _peOK = FindDescendentByName(this, L"ok");
  360. _peCancel = FindDescendentByName(this, L"cancel");
  361. _peCurrentItemList = NULL;
  362. _peChangePane = FindDescendentByName(this, L"changepane");
  363. _peAddNewPane = FindDescendentByName(this, L"addnewpane");
  364. _peAddRmWinPane = FindDescendentByName(this, L"addrmwinpane");
  365. _pePickAppPane = FindDescendentByName(this, L"pickapppane");
  366. if (NULL != _peSortCombo)
  367. {
  368. LoadStringW(_pParser->GetHInstance(), IDS_APPNAME, szTemp, DUIARRAYSIZE(szTemp));
  369. _peSortCombo->AddString(szTemp);
  370. LoadStringW(_pParser->GetHInstance(), IDS_SIZE, szTemp, DUIARRAYSIZE(szTemp));
  371. _peSortCombo->AddString(szTemp);
  372. LoadStringW(_pParser->GetHInstance(), IDS_FREQUENCY, szTemp, DUIARRAYSIZE(szTemp));
  373. _peSortCombo->AddString(szTemp);
  374. LoadStringW(_pParser->GetHInstance(), IDS_DATELASTUSED, szTemp, DUIARRAYSIZE(szTemp));
  375. _peSortCombo->AddString(szTemp);
  376. _peSortCombo->SetSelection(0);
  377. }
  378. _bInDomain = ARPIsOnDomain();
  379. _bOCSetupNeeded = !!COCSetupEnum::s_OCSetupNeeded();
  380. // Apply polices as needed
  381. ApplyPolices();
  382. if(!_bOCSetupNeeded)
  383. {
  384. Element* pe = FindDescendentByName(this, L"addrmwinoc");
  385. DUIAssertNoMsg(pe);
  386. pe->SetLayoutPos(LP_None);
  387. }
  388. // Set initial selection of option list
  389. Element* peSel;
  390. switch(_uiStartPane)
  391. {
  392. case 3:
  393. peSel = FindDescendent(_idPickApps);
  394. break;
  395. case 2:
  396. peSel = FindDescendent(_idAddRmWin);
  397. break;
  398. case 1:
  399. peSel = FindDescendent(_idAddNew);
  400. break;
  401. case 0:
  402. default:
  403. peSel = FindDescendent(_idChange);
  404. break;
  405. }
  406. // Set initial selection of style list
  407. DUIAssertNoMsg(peSel);
  408. _peOptionList->SetSelection(peSel);
  409. // initialize focus-following floater window
  410. peLastFocused = NULL;
  411. Element::Create(0, &peFloater);
  412. peFloater->SetLayoutPos(LP_Absolute);
  413. Add(peFloater);
  414. peFloater->SetBackgroundColor(ARGB(64, 255, 255, 0));
  415. ///////////////////////////////////////////////////////////////
  416. // Initialize the Pick Apps pane
  417. // Tell the clientblock elements that it's safe to initialize now
  418. if (FAILED(TraverseTree<ClientBlock>(this, _SendParseCompleted, (LPARAM)this)))
  419. {
  420. return false;
  421. }
  422. // Fill the client type lists
  423. InitClientCombos(_peOEMClients, CLIENTFILTER_OEM);
  424. InitClientCombos(_peMSClients, CLIENTFILTER_MS);
  425. InitClientCombos(_peNonMSClients, CLIENTFILTER_NONMS);
  426. _peClientTypeList->SetSelection(_peCustomClients);
  427. _peCustomClients->SetExpanded(false);
  428. return true;
  429. }
  430. struct SETFILTERINFO {
  431. CLIENTFILTER _cf;
  432. BOOL _fHasApp;
  433. ARPFrame* _paf;
  434. };
  435. HRESULT SetFilterCB(ClientPicker *pe, LPARAM lParam)
  436. {
  437. SETFILTERINFO* pfi = (SETFILTERINFO*)lParam;
  438. HRESULT hr = pe->SetFilter(pfi->_cf, pfi->_paf);
  439. if (SUCCEEDED(hr) && !pe->IsEmpty())
  440. {
  441. pfi->_fHasApp = TRUE;
  442. }
  443. return hr;
  444. }
  445. HRESULT ARPFrame::InitClientCombos(Expando* pexParent, CLIENTFILTER cf)
  446. {
  447. HRESULT hr;
  448. Element* pe;
  449. hr = _pParser->CreateElement(L"clientcategoryblock", NULL, &pe);
  450. if (SUCCEEDED(hr))
  451. {
  452. //
  453. // The client combos appear as the last element in the
  454. // clipped block. The clipped block is the first (only)
  455. // child of the clipper.
  456. //
  457. GetNthChild(pexParent->GetClipper(), 0)->Add(pe);
  458. SETFILTERINFO sfi = { cf, FALSE, this };
  459. hr = TraverseTree<ClientPicker>(pe, SetFilterCB, (LPARAM)&sfi);
  460. if (sfi._cf == CLIENTFILTER_OEM && !sfi._fHasApp)
  461. {
  462. pexParent->SetLayoutPos(LP_None);
  463. }
  464. }
  465. pexParent->SetExpanded(false);
  466. return hr;
  467. }
  468. //
  469. // ARPFrame::FindClientBlock locates a ClientBlock by client type.
  470. //
  471. struct FINDCLIENTBLOCKINFO {
  472. LPCWSTR _pwszType;
  473. ClientBlock* _pcb;
  474. };
  475. HRESULT FindClientBlockCB(ClientBlock* pcb, LPARAM lParam)
  476. {
  477. FINDCLIENTBLOCKINFO* pfcbi = (FINDCLIENTBLOCKINFO*)lParam;
  478. Value* pv;
  479. LPWSTR pwszType = pcb->GetClientTypeString(&pv);
  480. // Use LOCALE_INVARIANT so we aren't bitten by locales that do not
  481. // collate the same way as English.
  482. if (pwszType &&
  483. AreEnglishStringsEqual(pwszType, pfcbi->_pwszType))
  484. {
  485. pfcbi->_pcb = pcb; // found it!
  486. }
  487. pv->Release();
  488. return S_OK;
  489. }
  490. ClientBlock* ARPFrame::FindClientBlock(LPCWSTR pwszType)
  491. {
  492. FINDCLIENTBLOCKINFO fcbi = { pwszType, NULL };
  493. TraverseTree<ClientBlock>(this, FindClientBlockCB, (LPARAM)&fcbi);
  494. return fcbi._pcb;
  495. }
  496. /*
  497. * You must be a member of the Administrators group in order to
  498. * configure programs. Being Power User isn't good enough because
  499. * Power Users can't write to %ALLUSERSPROFILE%.
  500. */
  501. BOOL CanConfigurePrograms()
  502. {
  503. return IsUserAnAdmin();
  504. }
  505. void ARPFrame::ApplyPolices()
  506. {
  507. Element* pe;
  508. if (ARPIsRestricted(L"NoSupportInfo"))
  509. {
  510. _bSupportInfoRestricted = true;
  511. }
  512. if (ARPIsRestricted(L"ShowPostSetup"))
  513. {
  514. _bOCSetupNeeded = true;
  515. }
  516. else if (ARPIsRestricted(L"NoServices"))
  517. {
  518. _bOCSetupNeeded = false;
  519. }
  520. pe = FindDescendent(_idChange);
  521. DUIAssertNoMsg(pe);
  522. if (ARPIsRestricted(L"NoRemovePage"))
  523. {
  524. pe->SetLayoutPos(LP_None);
  525. if (0 == _uiStartPane)
  526. {
  527. _uiStartPane++;
  528. }
  529. }
  530. pe = FindDescendent(_idAddNew);
  531. DUIAssertNoMsg(pe);
  532. if (ARPIsRestricted(L"NoAddPage"))
  533. {
  534. pe->SetLayoutPos(LP_None);
  535. if (1 == _uiStartPane)
  536. {
  537. _uiStartPane++;
  538. }
  539. }
  540. else
  541. {
  542. if (ARPIsRestricted(L"NoAddFromCDorFloppy"))
  543. {
  544. pe = FindDescendent(_idAddFromCDPane);
  545. DUIAssertNoMsg(pe);
  546. pe->SetVisible(false);
  547. DisableElementTreeShortcut(pe);
  548. }
  549. if (ARPIsRestricted(L"NoAddFromInternet"))
  550. {
  551. pe = FindDescendent(_idAddFromMSPane);
  552. DUIAssertNoMsg(pe);
  553. pe->SetVisible(false);
  554. DisableElementTreeShortcut(pe);
  555. }
  556. if (!_bInDomain || ARPIsRestricted(L"NoAddFromNetwork"))
  557. {
  558. pe = FindDescendent(_idAddFromNetworkPane);
  559. DUIAssertNoMsg(pe);
  560. pe->SetVisible(false);
  561. DisableElementTreeShortcut(pe);
  562. }
  563. }
  564. pe = FindDescendent(_idAddRmWin);
  565. DUIAssertNoMsg(pe);
  566. // Note that in real ARP, we will never end up here with all thre panes disabled since we check for that before doing anything elese.
  567. if (ARPIsRestricted(L"NoWindowsSetupPage"))
  568. {
  569. pe->SetLayoutPos(LP_None);
  570. DisableElementTreeShortcut(pe);
  571. if (2 == _uiStartPane)
  572. {
  573. _uiStartPane++;
  574. }
  575. }
  576. pe = FindDescendent(_idAddWinComponent);
  577. DUIAssertNoMsg(pe);
  578. if (ARPIsRestricted(L"NoComponents"))
  579. {
  580. pe->SetVisible(false);
  581. DisableElementTreeShortcut(pe);
  582. }
  583. // Remove the "pick apps" page entirely if we are on Server or embedded
  584. // ("Choose Programs" is a workstation-only feature)
  585. // or it is restricted
  586. // (
  587. pe = FindDescendent(_idPickApps);
  588. DUIAssertNoMsg(pe);
  589. if (IsOS(OS_ANYSERVER) ||
  590. IsOS(OS_EMBEDDED) ||
  591. ARPIsRestricted(L"NoChooseProgramsPage"))
  592. {
  593. pe->SetLayoutPos(LP_None);
  594. DisableElementTreeShortcut(pe);
  595. if (3 == _uiStartPane)
  596. {
  597. _uiStartPane++;
  598. }
  599. }
  600. else
  601. {
  602. // DUI doesn't support content=rcicon so we have to set it manually
  603. HICON hico = (HICON)LoadImage(g_hinst, MAKEINTRESOURCE(IDI_DEFPROGS), IMAGE_ICON, 32, 32, 0);
  604. if (hico)
  605. {
  606. Value *pv = Value::CreateGraphic(hico);
  607. if (pv)
  608. {
  609. GetNthChild(pe, 0)->SetValue(ContentProp, PI_Local, pv);
  610. pv->Release();
  611. }
  612. }
  613. // Neuter the "pick apps" page if the user can't configure apps
  614. if (!CanConfigurePrograms()) {
  615. pe = FindDescendentByName(_pePickAppPane, L"pickappadmin");
  616. pe->SetVisible(false);
  617. DisableElementTreeShortcut(pe);
  618. pe = FindDescendentByName(_pePickAppPane, L"pickappnonadmin");
  619. pe->SetVisible(true);
  620. }
  621. }
  622. }
  623. bool ARPFrame::IsChangeRestricted()
  624. {
  625. return ARPIsRestricted(L"NoRemovePage")? true : false;
  626. }
  627. void ARPFrame::RunOCManager()
  628. {
  629. // Invoke Add/Remove Windows components
  630. // Command to invoke and OCMgr: "sysocmgr /y /i:%systemroot%\system32\sysoc.inf"
  631. WCHAR szInf[MAX_PATH];
  632. WCHAR szPath[MAX_PATH];
  633. if ( GetSystemDirectoryW(szPath, MAX_PATH) && PathCombineW(szInf, szPath, L"sysoc.inf") &&
  634. PathCombineW(szPath, szPath, L"sysocmgr.exe") )
  635. {
  636. WCHAR szParam[MAX_PATH];
  637. StringCchPrintf(szParam, ARRAYSIZE(szParam), L"/y /i:%s", szInf);
  638. ShellExecuteW(NULL, NULL, szPath, szParam, NULL, SW_SHOWDEFAULT);
  639. }
  640. }
  641. DWORD WINAPI PopulateInstalledItemList(void* paf);
  642. void ARPFrame::UpdateInstalledItems()
  643. {
  644. if (!IsChangeRestricted())
  645. {
  646. _peInstalledItemList->RemoveAll();
  647. _bInstalledListFilled = false;
  648. // Start second thread for item population
  649. //_beginthread(PopulateInstalledItemList, 0, (void*)this);
  650. if (!htPopulateInstalledItemList && g_fRun)
  651. htPopulateInstalledItemList = CreateThread(NULL, 0, PopulateInstalledItemList, (void*)this, 0, NULL);
  652. }
  653. }
  654. ////////////////////////////////////////////////////////
  655. // Generic eventing
  656. // Helper
  657. inline void _SetElementSheet(Element* peTarget, ATOM atomID, Value* pvSheet, bool bSheetRelease = true)
  658. {
  659. if (pvSheet)
  660. {
  661. Element* pe = peTarget->FindDescendent(atomID);
  662. DUIAssertNoMsg(pe);
  663. pe->SetValue(Element::SheetProp, PI_Local, pvSheet);
  664. if (bSheetRelease)
  665. pvSheet->Release();
  666. }
  667. }
  668. BOOL IsValidFileTime(FILETIME ft)
  669. {
  670. return ft.dwHighDateTime || ft.dwLowDateTime;
  671. }
  672. BOOL IsValidSize(ULONGLONG ull)
  673. {
  674. return ull != (ULONGLONG)-1;
  675. }
  676. BOOL IsValidFrequency(int iTimesUsed)
  677. {
  678. return iTimesUsed >= 0;
  679. }
  680. void CALLBACK
  681. _UnblockInputCallback(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR idEvent, DWORD /*dwTime*/)
  682. {
  683. BlockInput(FALSE);
  684. KillTimer(NULL, idEvent);
  685. }
  686. void _BlockDoubleClickInput(void)
  687. {
  688. if (SetTimer(NULL, 0, GetDoubleClickTime(), _UnblockInputCallback))
  689. {
  690. BlockInput(TRUE);
  691. }
  692. }
  693. //#ifdef NEVER
  694. //
  695. // NTRAID#NTBUG9-314154-2001/3/12-brianau Handle Refresh
  696. //
  697. // Need to finish this for Whistler.
  698. //
  699. DWORD WINAPI PopulateAndRenderPublishedItemList(void* paf);
  700. DWORD WINAPI PopulateAndRenderOCSetupItemList(void* paf);
  701. void EnablePane(Element* pePane, bool fEnable);
  702. void ARPFrame::OnInput(InputEvent *pEvent)
  703. {
  704. if (GMF_BUBBLED == pEvent->nStage)
  705. {
  706. if (GINPUT_KEYBOARD == pEvent->nCode)
  707. {
  708. KeyboardEvent *pke = (KeyboardEvent *)pEvent;
  709. if (VK_F5 == pke->ch)
  710. {
  711. if (_peCurrentItemList)
  712. {
  713. if (_peCurrentItemList == _peInstalledItemList)
  714. {
  715. UpdateInstalledItems();
  716. }
  717. else if (_peCurrentItemList == _pePublishedItemList)
  718. {
  719. RePopulatePublishedItemList();
  720. }
  721. else if (_peCurrentItemList == _peOCSetupItemList)
  722. {
  723. RePopulateOCSetupItemList();
  724. }
  725. }
  726. }
  727. }
  728. }
  729. HWNDElement::OnInput(pEvent);
  730. }
  731. //#endif
  732. HRESULT SetVisibleClientCB(ClientPicker *pe, LPARAM lParam)
  733. {
  734. pe->SetVisible(UNCASTLPARAMTOBOOL(lParam));
  735. return TRUE;
  736. }
  737. //
  738. // This hides the controls that belong to the old pane and shows the
  739. // controls that belong to the new pane.
  740. //
  741. void ARPFrame::ChangePane(Element *pePane)
  742. {
  743. bool fEnable;
  744. // Show/hide elements that belong to _peChangePane...
  745. fEnable = pePane == _peChangePane;
  746. // TODO: Zero size ancestors need to cause adaptors (HWNDHosts) to hide
  747. _peSortCombo->SetVisible(fEnable);
  748. EnablePane(_peChangePane, fEnable);
  749. // Show/hide elements that belong to _peAddNewPane
  750. fEnable = pePane == _peAddNewPane;
  751. _pePublishedCategory->SetVisible(fEnable);
  752. _pePublishedCategoryLabel->SetVisible(fEnable);
  753. EnablePane(_peAddNewPane, fEnable);
  754. // Show/hide elements that belong to _peAddRmWinPane
  755. fEnable = pePane == _peAddRmWinPane;
  756. EnablePane(_peAddRmWinPane, fEnable);
  757. // Show/hide elements that belong to _pePickAppPane
  758. fEnable = pePane == _pePickAppPane;
  759. TraverseTree<ClientPicker>(_pePickAppPane, SetVisibleClientCB, fEnable);
  760. EnablePane(_pePickAppPane, fEnable);
  761. }
  762. // If we can't put focus on the list, it will go to the fallback location
  763. void ARPFrame::PutFocusOnList(Selector* peList)
  764. {
  765. Element* pe;
  766. if (pe = peList->GetSelection())
  767. {
  768. pe->SetKeyFocus();
  769. }
  770. else
  771. {
  772. pe = FallbackFocus();
  773. if (pe)
  774. {
  775. pe->SetKeyFocus();
  776. }
  777. }
  778. }
  779. void ARPFrame::OnEvent(Event* pEvent)
  780. {
  781. // Handle only bubbled generic events
  782. if (pEvent->nStage == GMF_BUBBLED)
  783. {
  784. if (pEvent->uidType == Button::Click)
  785. {
  786. ButtonClickEvent* pbce = (ButtonClickEvent*)pEvent;
  787. if (pbce->peTarget->GetID() == _idClose ||
  788. pbce->peTarget == _peOK)
  789. {
  790. // Close button
  791. if (OnClose())
  792. {
  793. _pnhh->DestroyWindow();
  794. }
  795. pEvent->fHandled = true;
  796. return;
  797. }
  798. else if (pbce->peTarget == _peCancel)
  799. {
  800. // Do not call OnClose; nothing will be applied
  801. _pnhh->DestroyWindow();
  802. pEvent->fHandled = true;
  803. return;
  804. }
  805. else if (pbce->peTarget->GetID() == _idAddFromDisk)
  806. {
  807. // Add from disk button
  808. HRESULT hr;
  809. IShellAppManager* pisam = NULL;
  810. hr = CoCreateInstance(__uuidof(ShellAppManager), NULL, CLSCTX_INPROC_SERVER, __uuidof(IShellAppManager), (void**)&pisam);
  811. if (SUCCEEDED(hr))
  812. {
  813. pisam->InstallFromFloppyOrCDROM(GetHWND());
  814. }
  815. if (pisam)
  816. {
  817. pisam->Release();
  818. }
  819. pEvent->fHandled = true;
  820. return;
  821. }
  822. else if (pbce->peTarget->GetID() == _idAddFromMsft)
  823. {
  824. // Windows update button
  825. WCHAR szPath[MAX_PATH];
  826. if ( GetSystemDirectory(szPath, MAX_PATH) && PathCombineW(szPath, szPath, L"wupdmgr.exe") )
  827. {
  828. ShellExecuteW(NULL, NULL, szPath, NULL, NULL, SW_SHOWDEFAULT);
  829. pEvent->fHandled = true;
  830. }
  831. return;
  832. }
  833. else if (pbce->peTarget->GetID() == _idComponents)
  834. {
  835. RunOCManager();
  836. }
  837. else if (pbce->peTarget->GetID() == ARPItem::_idSize ||
  838. pbce->peTarget->GetID() == ARPItem::_idFreq ||
  839. pbce->peTarget->GetID() == ARPItem::_idSupInfo)
  840. {
  841. // Help requests
  842. ARPHelp* peHelp;
  843. NativeHWNDHost* pnhh = NULL;
  844. Element* pe = NULL;
  845. WCHAR szTitle[1024];
  846. if (pbce->peTarget->GetID() == ARPItem::_idSize)
  847. {
  848. LoadStringW(_pParser->GetHInstance(), IDS_SIZETITLE, szTitle, DUIARRAYSIZE(szTitle));
  849. if (SUCCEEDED(NativeHWNDHost::Create(szTitle, GetHWND(), NULL, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 0, WS_POPUPWINDOW | WS_OVERLAPPED | WS_DLGFRAME, NHHO_NoSendQuitMessage | NHHO_HostControlsSize | NHHO_ScreenCenter, &pnhh)))
  850. {
  851. ARPHelp::Create(pnhh, this, _bDoubleBuffer, (Element**)&peHelp);
  852. _pParser->CreateElement(L"sizehelp", peHelp, &pe);
  853. }
  854. else
  855. {
  856. DUITrace(">> Failed to create NativeHWNDHost for size info window.\n");
  857. }
  858. }
  859. else if (pbce->peTarget->GetID() == ARPItem::_idFreq)
  860. {
  861. LoadStringW(_pParser->GetHInstance(), IDS_FREQUENCYTITLE, szTitle, DUIARRAYSIZE(szTitle));
  862. if (SUCCEEDED(NativeHWNDHost::Create(szTitle, GetHWND(), NULL, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 0, WS_POPUPWINDOW | WS_OVERLAPPED | WS_DLGFRAME, NHHO_NoSendQuitMessage | NHHO_HostControlsSize | NHHO_ScreenCenter, &pnhh)))
  863. {
  864. ARPHelp::Create(pnhh, this, _bDoubleBuffer, (Element**)&peHelp);
  865. _pParser->CreateElement(L"freqhelp", peHelp, &pe);
  866. }
  867. else
  868. {
  869. DUITrace(">> Failed to create NativeHWNDHost for frequency info window.\n");
  870. }
  871. }
  872. else
  873. {
  874. // Support information, add additional fields
  875. LoadStringW(_pParser->GetHInstance(), IDS_SUPPORTTITLE, szTitle, DUIARRAYSIZE(szTitle));
  876. if (SUCCEEDED(NativeHWNDHost::Create(szTitle, GetHWND(), NULL, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 0, WS_POPUPWINDOW | WS_OVERLAPPED | WS_DLGFRAME, NHHO_NoSendQuitMessage | NHHO_HostControlsSize | NHHO_ScreenCenter, &pnhh)))
  877. {
  878. ARPHelp::Create(pnhh, this, _bDoubleBuffer, (Element**)&peHelp);
  879. _pParser->CreateElement(L"suphelp", peHelp, &pe);
  880. // Get application info
  881. APPINFODATA aid = {0};
  882. // Query
  883. aid.cbSize = sizeof(APPINFODATA);
  884. aid.dwMask = AIM_DISPLAYNAME | AIM_VERSION | AIM_PUBLISHER | AIM_PRODUCTID |
  885. AIM_REGISTEREDOWNER | AIM_REGISTEREDCOMPANY | AIM_SUPPORTURL |
  886. AIM_SUPPORTTELEPHONE | AIM_HELPLINK | AIM_INSTALLLOCATION | AIM_INSTALLDATE |
  887. AIM_COMMENTS | AIM_IMAGE | AIM_READMEURL | AIM_CONTACT | AIM_UPDATEINFOURL;
  888. // There must be a selection
  889. ARPItem* peSel = (ARPItem*)_peInstalledItemList->GetSelection();
  890. peSel->_piia->GetAppInfo(&aid);
  891. ((ARPHelp*)peHelp)->_piia = peSel->_piia;
  892. PrepareSupportInfo(peHelp, &aid);
  893. // Clean up
  894. ClearAppInfoData(&aid);
  895. }
  896. else
  897. {
  898. DUITrace(">> Failed to create NativeHWNDHost for support info window.\n");
  899. }
  900. }
  901. if (pe && pnhh) // Fill contents using substitution
  902. {
  903. // Set visible and host
  904. _pah = peHelp;
  905. _bInModalMode = true;
  906. EnableWindow(GetHWND(), FALSE);
  907. pnhh->Host(peHelp);
  908. peHelp->SetVisible(true);
  909. peHelp->SetDefaultFocus();
  910. // Do initial show
  911. pnhh->ShowWindow();
  912. }
  913. pEvent->fHandled = true;
  914. return;
  915. }
  916. }
  917. else if (pEvent->uidType == Selector::SelectionChange)
  918. {
  919. SelectionChangeEvent* sce = (SelectionChangeEvent*)pEvent;
  920. //
  921. // NTRAID#NTBUG9-294015-2001/02/08-jeffreys
  922. //
  923. // If the user double-clicks, weird things can happen.
  924. //
  925. //
  926. // NTRAID#NTBUG9-313888-2001/2/14-brianau
  927. //
  928. // This fix for 294015 caused more strange things to happen. The most notable
  929. // is that sometimes you click a button and it remains depressed
  930. // but nothing happens. Disabling this call to block double
  931. // click input fixes this problem. We need to devise a better way
  932. // of handling double-click input in DUI.
  933. //
  934. // _BlockDoubleClickInput();
  935. if (sce->peTarget == _peOptionList)
  936. {
  937. // ARP options
  938. StartDefer();
  939. Element* peAddContentHeader = FindDescendentByName(this, L"addcontentheader");
  940. ASSERT(peAddContentHeader != NULL);
  941. if (sce->peNew->GetID() == _idChange)
  942. {
  943. if (!_bInstalledListFilled)
  944. {
  945. UpdateInstalledItems();
  946. }
  947. ChangePane(_peChangePane);
  948. _peCurrentItemList = _peInstalledItemList;
  949. _peInstalledItemList->SetContentString(L"");
  950. PutFocusOnList(_peInstalledItemList);
  951. }
  952. else if (sce->peNew->GetID() == _idAddNew)
  953. {
  954. if (!_bPublishedListFilled)
  955. {
  956. WCHAR szTemp[1024];
  957. LoadStringW(_pParser->GetHInstance(), IDS_WAITFEEDBACK, szTemp, DUIARRAYSIZE(szTemp));
  958. _pePublishedItemList->SetContentString(szTemp);
  959. SetElementAccessability(_pePublishedItemList, true, ROLE_SYSTEM_STATICTEXT, szTemp);
  960. RePopulatePublishedItemList();
  961. }
  962. ChangePane(_peAddNewPane);
  963. _peCurrentItemList = _pePublishedItemList;
  964. PutFocusOnList(_pePublishedItemList);
  965. }
  966. else if (sce->peNew->GetID() == _idAddRmWin)
  967. {
  968. ChangePane(_peAddRmWinPane);
  969. _peCurrentItemList = _peOCSetupItemList;
  970. if (!_bOCSetupNeeded)
  971. {
  972. RunOCManager();
  973. if (sce->peOld) {
  974. _peOptionList->SetSelection(sce->peOld);
  975. }
  976. }
  977. else
  978. {
  979. if (!_bOCSetupListFilled)
  980. {
  981. //_beginthread(PopulateAndRenderOCSetupItemList, 0, (void*)this);
  982. if (!htPopulateAndRenderOCSetupItemList && g_fRun)
  983. htPopulateAndRenderOCSetupItemList = CreateThread(NULL, 0, PopulateAndRenderOCSetupItemList, (void*)this, 0, NULL);
  984. _bOCSetupListFilled = true;
  985. }
  986. PutFocusOnList(_peOCSetupItemList);
  987. }
  988. }
  989. else if (sce->peNew->GetID() == _idPickApps)
  990. {
  991. ChangePane(_pePickAppPane);
  992. _peCurrentItemList = _peClientTypeList;
  993. PutFocusOnList(_peClientTypeList);
  994. }
  995. EndDefer();
  996. }
  997. else if (sce->peTarget == _peInstalledItemList)
  998. {
  999. if (sce->peOld)
  1000. {
  1001. sce->peOld->FindDescendent(ARPItem::_idRow[0])->SetEnabled(false);
  1002. }
  1003. if (sce->peNew)
  1004. {
  1005. sce->peNew->FindDescendent(ARPItem::_idRow[0])->RemoveLocalValue(EnabledProp);
  1006. }
  1007. }
  1008. pEvent->fHandled = true;
  1009. return;
  1010. }
  1011. else if (pEvent->uidType == Combobox::SelectionChange)
  1012. {
  1013. SelectionIndexChangeEvent* psice = (SelectionIndexChangeEvent*)pEvent;
  1014. if (psice->peTarget->GetID() == _idSortCombo)
  1015. {
  1016. SortList(psice->iNew, psice->iOld);
  1017. }
  1018. else if (psice->peTarget->GetID() == _idCategoryCombo)
  1019. {
  1020. _curCategory = psice->iNew;
  1021. if (_bPublishedComboFilled)
  1022. {
  1023. if (_bPublishedListFilled)
  1024. {
  1025. RePopulatePublishedItemList();
  1026. }
  1027. }
  1028. }
  1029. }
  1030. }
  1031. HWNDElement::OnEvent(pEvent);
  1032. }
  1033. void ARPFrame::OnKeyFocusMoved(Element* peFrom, Element* peTo)
  1034. {
  1035. if(peTo && IsDescendent(peTo))
  1036. {
  1037. peLastFocused = peTo;
  1038. }
  1039. Element::OnKeyFocusMoved(peFrom, peTo);
  1040. /* uncomment when JStall's message fixing is done
  1041. if (peTo != peLastFocused)
  1042. {
  1043. // transition focus-following floater element from old to new
  1044. if (!peTo)
  1045. peFloater->SetVisible(false);
  1046. else
  1047. {
  1048. Value* pvSize;
  1049. const SIZE* psize = peTo->GetExtent(&pvSize);
  1050. peFloater->SetWidth(psize->cx);
  1051. peFloater->SetHeight(psize->cy);
  1052. pvSize->Release();
  1053. POINT pt = { 0, 0 };
  1054. MapElementPoint(peTo, &pt, &pt);
  1055. peFloater->SetX(pt.x);
  1056. peFloater->SetY(pt.y);
  1057. if (!peLastFocused)
  1058. peFloater->SetVisible(true);
  1059. }
  1060. peLastFocused = peTo;
  1061. }
  1062. */
  1063. }
  1064. void ARPFrame::OnPublishedListComplete()
  1065. {
  1066. Invoke(ARP_PUBLISHEDLISTCOMPLETE, NULL);
  1067. }
  1068. void ARPFrame::RePopulatePublishedItemList()
  1069. {
  1070. //_beginthread(::PopulateAndRenderPublishedItemList, 0, (void*)this);
  1071. if (!htPopulateAndRenderPublishedItemList && g_fRun)
  1072. {
  1073. // Disable the category combo until we are done populating the list
  1074. _pePublishedCategory->SetEnabled(false);
  1075. _bPublishedListFilled = false;
  1076. _pePublishedItemList->DestroyAll();
  1077. htPopulateAndRenderPublishedItemList = CreateThread(NULL, 0, PopulateAndRenderPublishedItemList, (void*)this, 0, NULL);
  1078. }
  1079. }
  1080. void ARPFrame::RePopulateOCSetupItemList()
  1081. {
  1082. if (!htPopulateAndRenderOCSetupItemList && g_fRun)
  1083. {
  1084. _peOCSetupItemList->DestroyAll();
  1085. _bOCSetupListFilled = false;
  1086. htPopulateAndRenderOCSetupItemList = CreateThread(NULL, 0, PopulateAndRenderOCSetupItemList, (void*)this, 0, NULL);
  1087. _bOCSetupListFilled = true;
  1088. }
  1089. }
  1090. bool ARPFrame::CanSetFocus()
  1091. {
  1092. if (_bInModalMode)
  1093. {
  1094. HWND hWnd = _pah->GetHost()->GetHWND();
  1095. FLASHWINFO fwi = {
  1096. sizeof(FLASHWINFO), // cbSize
  1097. hWnd, // hwnd
  1098. FLASHW_CAPTION, // flags
  1099. 5, // uCount
  1100. 75 // dwTimeout
  1101. };
  1102. FlashWindowEx(&fwi);
  1103. SetFocus(hWnd);
  1104. return false;
  1105. }
  1106. return true;
  1107. }
  1108. HRESULT TransferToCustomCB(ClientPicker *pe, LPARAM)
  1109. {
  1110. return pe->TransferToCustom();
  1111. }
  1112. HRESULT ApplyClientBlockCB(ClientBlock* pcb, LPARAM lParam)
  1113. {
  1114. return pcb->Apply((ARPFrame*)lParam);
  1115. }
  1116. bool ARPFrame::OnClose()
  1117. {
  1118. if (_peClientTypeList)
  1119. {
  1120. Element *peSelected = _peClientTypeList->GetSelection();
  1121. if (peSelected)
  1122. {
  1123. // Get all the client pickers in the user's selection
  1124. // to transfer their settings to the Custom pane.
  1125. // (This is a NOP if the current selection is itself the custom pane.)
  1126. TraverseTree<ClientPicker>(peSelected, TransferToCustomCB);
  1127. InitProgressDialog();
  1128. // To get the progress bar right, we apply in two passes.
  1129. // The first pass is "fake mode" where all we do is count up
  1130. // how much work we are going to do.
  1131. SetProgressFakeMode(true);
  1132. TraverseTree<ClientBlock>(this, ApplyClientBlockCB, (LPARAM)this);
  1133. // Okay now we know what the progress bar limit should be.
  1134. _dwProgressTotal = _dwProgressSoFar;
  1135. _dwProgressSoFar = 0;
  1136. // The second pass is "real mode" where we do the actualy work.
  1137. SetProgressFakeMode(false);
  1138. TraverseTree<ClientBlock>(this, ApplyClientBlockCB, (LPARAM)this);
  1139. EndProgressDialog();
  1140. }
  1141. }
  1142. return true;
  1143. }
  1144. void ARPFrame::InitProgressDialog()
  1145. {
  1146. TCHAR szBuf[MAX_PATH];
  1147. EndProgressDialog();
  1148. _dwProgressTotal = _dwProgressSoFar = 0;
  1149. if (SUCCEEDED(CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IProgressDialog, &_ppd))))
  1150. {
  1151. _ppd->SetAnimation(GetModuleHandle(TEXT("SHELL32")), 165);
  1152. LoadString(g_hinst, IDS_APPLYINGCLIENT, szBuf, SIZECHARS(szBuf));
  1153. _ppd->SetTitle(szBuf);
  1154. _ppd->StartProgressDialog(GetHostWindow(), NULL, PROGDLG_MODAL | PROGDLG_NOTIME | PROGDLG_NOMINIMIZE, NULL);
  1155. }
  1156. }
  1157. void ARPFrame::SetProgressDialogText(UINT ids, LPCTSTR pszName)
  1158. {
  1159. TCHAR szBuf[MAX_PATH];
  1160. TCHAR szFormat[MAX_PATH];
  1161. if (_ppd)
  1162. {
  1163. LoadString(g_hinst, ids, szFormat, SIZECHARS(szFormat));
  1164. wnsprintf(szBuf, SIZECHARS(szBuf), szFormat, pszName);
  1165. _ppd->SetLine(1, szBuf, FALSE, NULL);
  1166. _ppd->SetProgress(_dwProgressSoFar, _dwProgressTotal);
  1167. }
  1168. }
  1169. void ARPFrame::EndProgressDialog()
  1170. {
  1171. if (_ppd)
  1172. {
  1173. _ppd->StopProgressDialog();
  1174. _ppd->Release();
  1175. _ppd = NULL;
  1176. }
  1177. }
  1178. HRESULT ARPFrame::LaunchClientCommandAndWait(UINT ids, LPCTSTR pszName, LPTSTR pszCommand)
  1179. {
  1180. HRESULT hr = S_OK;
  1181. if (!_bFakeProgress)
  1182. {
  1183. if (_ppd && _ppd->HasUserCancelled())
  1184. {
  1185. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  1186. }
  1187. else
  1188. {
  1189. SetProgressDialogText(ids, pszName);
  1190. PROCESS_INFORMATION pi;
  1191. STARTUPINFO si = { 0 };
  1192. si.cb = sizeof(si);
  1193. si.dwFlags = STARTF_USESHOWWINDOW;
  1194. si.wShowWindow = SW_SHOWNORMAL;
  1195. if (CreateProcess(NULL, pszCommand, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
  1196. {
  1197. while (SHWaitForSendMessageThread(pi.hProcess, 1000) == WAIT_TIMEOUT)
  1198. {
  1199. if (_ppd && _ppd->HasUserCancelled())
  1200. {
  1201. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  1202. break;
  1203. }
  1204. }
  1205. CloseHandle(pi.hProcess);
  1206. CloseHandle(pi.hThread);
  1207. }
  1208. }
  1209. }
  1210. _dwProgressSoFar++;
  1211. return hr;
  1212. }
  1213. ////////////////////////////////////////////////////////
  1214. // Caller thread-safe APIs (do any additional work on callers thread and then marshal)
  1215. // Sets the range for the total number of installed items
  1216. void ARPFrame::SetInstalledItemCount(UINT cItems)
  1217. {
  1218. Invoke(ARP_SETINSTALLEDITEMCOUNT, (void*)(UINT_PTR)cItems);
  1219. }
  1220. void ARPFrame::DecrementInstalledItemCount()
  1221. {
  1222. Invoke(ARP_DECREMENTINSTALLEDITEMCOUNT, NULL);
  1223. }
  1224. // Sets the range for the total number of installed items
  1225. void ARPFrame::SetPublishedItemCount(UINT cItems)
  1226. {
  1227. Invoke(ARP_SETPUBLISHEDITEMCOUNT, (void*)(UINT_PTR)cItems);
  1228. }
  1229. void ARPFrame::DecrementPublishedItemCount()
  1230. {
  1231. Invoke(ARP_DECREMENTPUBLISHEDITEMCOUNT, NULL);
  1232. }
  1233. // Inserts in items, sorted into the ARP list
  1234. void ARPFrame::InsertInstalledItem(IInstalledApp* piia)
  1235. {
  1236. if (piia == NULL)
  1237. {
  1238. Invoke(ARP_DONEINSERTINSTALLEDITEM, NULL);
  1239. }
  1240. else
  1241. {
  1242. // Setup marshalled call, do as much work as possible on caller thread
  1243. InsertItemData iid;
  1244. APPINFODATA aid = {0};
  1245. SLOWAPPINFO sai = {0};
  1246. // Query only for display name and support URL
  1247. aid.cbSize = sizeof(APPINFODATA);
  1248. aid.dwMask = AIM_DISPLAYNAME | AIM_VERSION | AIM_PUBLISHER | AIM_PRODUCTID |
  1249. AIM_REGISTEREDOWNER | AIM_REGISTEREDCOMPANY | AIM_SUPPORTURL |
  1250. AIM_SUPPORTTELEPHONE | AIM_HELPLINK | AIM_INSTALLLOCATION | AIM_INSTALLDATE |
  1251. AIM_COMMENTS | AIM_IMAGE | AIM_READMEURL | AIM_CONTACT | AIM_UPDATEINFOURL;
  1252. piia->GetAppInfo(&aid);
  1253. if(FAILED(piia->GetCachedSlowAppInfo(&sai)))
  1254. {
  1255. piia->GetSlowAppInfo(&sai);
  1256. }
  1257. // Set data
  1258. iid.piia = piia;
  1259. if (aid.pszDisplayName && aid.pszDisplayName[0])
  1260. {
  1261. // Title
  1262. CopyMemory(iid.pszTitle, aid.pszDisplayName, min(sizeof(iid.pszTitle), (wcslen(aid.pszDisplayName) + 1) * sizeof(WCHAR)));
  1263. // Image
  1264. if (aid.pszImage && aid.pszImage[0])
  1265. {
  1266. iid.iIconIndex = PathParseIconLocationW(aid.pszImage);
  1267. CopyMemory(iid.pszImage, aid.pszImage, min(sizeof(iid.pszImage), (wcslen(aid.pszImage) + 1) * sizeof(WCHAR)));
  1268. }
  1269. else if (sai.pszImage && sai.pszImage[0])
  1270. {
  1271. iid.iIconIndex = PathParseIconLocationW(sai.pszImage);
  1272. CopyMemory(iid.pszImage, sai.pszImage, min(sizeof(iid.pszImage), (wcslen(sai.pszImage) + 1) * sizeof(WCHAR)));
  1273. }
  1274. else
  1275. {
  1276. *iid.pszImage = NULL;
  1277. }
  1278. // Size, Frequency, and Last Used On
  1279. iid.ullSize = sai.ullSize;
  1280. iid.iTimesUsed = sai.iTimesUsed;
  1281. iid.ftLastUsed = sai.ftLastUsed;
  1282. // Possible actions (change, remove, etc.)
  1283. piia->GetPossibleActions(&iid.dwActions);
  1284. // Flag if support information is available
  1285. iid.bSupportInfo = ShowSupportInfo(&aid);
  1286. Invoke(ARP_INSERTINSTALLEDITEM, &iid);
  1287. }
  1288. else
  1289. // Adjust Status bar size.
  1290. {
  1291. DecrementInstalledItemCount();
  1292. }
  1293. // Free query memory
  1294. ClearAppInfoData(&aid);
  1295. }
  1296. }
  1297. void ARPFrame::InsertPublishedItem(IPublishedApp* pipa, bool bDuplicateName)
  1298. {
  1299. PUBAPPINFO* ppai;
  1300. APPINFODATA aid = {0};
  1301. InsertItemData iid= {0};
  1302. ppai = new PUBAPPINFO;
  1303. if (ppai == NULL)
  1304. {
  1305. return;
  1306. }
  1307. ppai->cbSize = sizeof(PUBAPPINFO);
  1308. ppai->dwMask = PAI_SOURCE | PAI_ASSIGNEDTIME | PAI_PUBLISHEDTIME | PAI_EXPIRETIME | PAI_SCHEDULEDTIME;
  1309. aid.cbSize = sizeof(APPINFODATA);
  1310. aid.dwMask = AIM_DISPLAYNAME | AIM_VERSION | AIM_PUBLISHER | AIM_PRODUCTID |
  1311. AIM_REGISTEREDOWNER | AIM_REGISTEREDCOMPANY | AIM_SUPPORTURL |
  1312. AIM_SUPPORTTELEPHONE | AIM_HELPLINK | AIM_INSTALLLOCATION | AIM_INSTALLDATE |
  1313. AIM_COMMENTS | AIM_IMAGE | AIM_READMEURL | AIM_CONTACT | AIM_UPDATEINFOURL;
  1314. pipa->GetAppInfo(&aid);
  1315. pipa->GetPublishedAppInfo(ppai);
  1316. // Title
  1317. if (bDuplicateName)
  1318. {
  1319. //
  1320. // Duplicate entries have their publisher name appended
  1321. // to the application name so that they can be differentiated
  1322. // from one another in the UI.
  1323. //
  1324. StringCchPrintf(iid.pszTitle,
  1325. ARRAYSIZE(iid.pszTitle),
  1326. L"%ls: %ls",
  1327. aid.pszDisplayName,
  1328. ppai->pszSource);
  1329. }
  1330. else
  1331. {
  1332. //
  1333. // iid.pszTitle, despite the name is a character buffer, not a pointer.
  1334. //
  1335. lstrcpyn(iid.pszTitle, aid.pszDisplayName, ARRAYSIZE(iid.pszTitle));
  1336. }
  1337. iid.pipa = pipa;
  1338. iid.ppai = ppai;
  1339. Invoke(ARP_INSERTPUBLISHEDITEM, &iid);
  1340. // Free query memory
  1341. ClearAppInfoData(&aid);
  1342. }
  1343. void ARPFrame::InsertOCSetupItem(COCSetupApp* pocsa)
  1344. {
  1345. APPINFODATA aid = {0};
  1346. InsertItemData iid= {0};
  1347. aid.cbSize = sizeof(APPINFODATA);
  1348. aid.dwMask = AIM_DISPLAYNAME;
  1349. pocsa->GetAppInfo(&aid);
  1350. iid.pocsa = pocsa;
  1351. // Title
  1352. CopyMemory(iid.pszTitle, aid.pszDisplayName, min(sizeof(iid.pszTitle), (wcslen(aid.pszDisplayName) + 1) * sizeof(WCHAR)));
  1353. Invoke(ARP_INSERTOCSETUPITEM, &iid);
  1354. // Free query memory
  1355. ClearAppInfoData(&aid);
  1356. }
  1357. void ARPFrame::FeedbackEmptyPublishedList()
  1358. {
  1359. Invoke(ARP_SETPUBLISHEDFEEDBACKEMPTY, 0);
  1360. }
  1361. void ARPFrame::DirtyInstalledListFlag()
  1362. {
  1363. _bInstalledListFilled=false;
  1364. // Refresh if we are on the published list
  1365. if (_peCurrentItemList == _peInstalledItemList)
  1366. {
  1367. UpdateInstalledItems();
  1368. }
  1369. }
  1370. void ARPFrame::DirtyPublishedListFlag()
  1371. {
  1372. _bPublishedListFilled=false;
  1373. // Refresh if we are on the published list
  1374. if (_peCurrentItemList == _pePublishedItemList)
  1375. {
  1376. RePopulatePublishedItemList();
  1377. }
  1378. }
  1379. void ARPFrame::PopulateCategoryCombobox()
  1380. {
  1381. Invoke(ARP_POPULATECATEGORYCOMBO, NULL);
  1382. }
  1383. LPCWSTR ARPFrame::GetCurrentPublishedCategory()
  1384. {
  1385. int iCurrentCategory = _curCategory;
  1386. if (iCurrentCategory == 0 || iCurrentCategory == CB_ERR || _psacl == NULL)
  1387. {
  1388. return NULL;
  1389. }
  1390. return _psacl->pCategory[iCurrentCategory - 1].pszCategory;
  1391. }
  1392. inline bool ARPFrame::ShowSupportInfo(APPINFODATA *paid)
  1393. {
  1394. if (_bSupportInfoRestricted)
  1395. {
  1396. return false;
  1397. }
  1398. if (paid->pszVersion && paid->pszVersion ||
  1399. paid->pszPublisher && paid->pszPublisher ||
  1400. paid->pszProductID && paid->pszProductID ||
  1401. paid->pszRegisteredOwner && paid->pszRegisteredOwner ||
  1402. paid->pszRegisteredCompany && paid->pszRegisteredCompany ||
  1403. paid->pszSupportUrl && paid->pszSupportUrl ||
  1404. paid->pszHelpLink && paid->pszHelpLink ||
  1405. paid->pszContact && paid->pszContact ||
  1406. paid->pszReadmeUrl && paid->pszReadmeUrl ||
  1407. paid->pszComments && paid->pszComments)
  1408. {
  1409. return TRUE;
  1410. }
  1411. return FALSE;
  1412. }
  1413. void ARPFrame::PrepareSupportInfo(Element* peHelp, APPINFODATA *paid)
  1414. {
  1415. DWORD dwAction = 0;
  1416. Element* pe;
  1417. pe = FindDescendentByName(peHelp, L"title");
  1418. pe->SetContentString(paid->pszDisplayName);
  1419. SetElementAccessability(pe, true, ROLE_SYSTEM_STATICTEXT, paid->pszDisplayName);
  1420. pe = FindDescendentByName(peHelp, L"prodname");
  1421. pe->SetContentString(paid->pszDisplayName);
  1422. SetElementAccessability(pe, true, ROLE_SYSTEM_STATICTEXT, paid->pszDisplayName);
  1423. ARPSupportItem* pasi;
  1424. pasi = (ARPSupportItem*) FindDescendentByName(peHelp, L"publisher");
  1425. pasi->SetAccValue(paid->pszPublisher);
  1426. pasi->SetURL(paid->pszSupportUrl);
  1427. FindDescendentByName(peHelp, L"version")->SetAccValue(paid->pszVersion);
  1428. FindDescendentByName(peHelp, L"contact")->SetAccValue(paid->pszContact);
  1429. pasi = (ARPSupportItem*) FindDescendentByName(peHelp, L"support");
  1430. pasi->SetAccValue(paid->pszHelpLink);
  1431. pasi->SetURL(paid->pszHelpLink);
  1432. FindDescendentByName(peHelp, L"telephone")->SetAccValue(paid->pszSupportTelephone);
  1433. pasi = (ARPSupportItem*) FindDescendentByName(peHelp, L"readme");
  1434. pasi->SetAccValue(paid->pszReadmeUrl);
  1435. pasi->SetURL(paid->pszReadmeUrl);
  1436. pasi = (ARPSupportItem*) FindDescendentByName(peHelp, L"update");
  1437. pasi->SetAccValue(paid->pszUpdateInfoUrl);
  1438. pasi->SetURL(paid->pszUpdateInfoUrl);
  1439. FindDescendentByName(peHelp, L"productID")->SetAccValue(paid->pszProductID);
  1440. FindDescendentByName(peHelp, L"regCompany")->SetAccValue(paid->pszRegisteredCompany);
  1441. FindDescendentByName(peHelp, L"regOwner")->SetAccValue(paid->pszRegisteredOwner);
  1442. FindDescendentByName(peHelp, L"comments")->SetAccValue(paid->pszComments);
  1443. ((ARPHelp*)peHelp)->_piia->GetPossibleActions(&dwAction);
  1444. if (!(dwAction & APPACTION_REPAIR))
  1445. FindDescendentByName(peHelp, L"repairblock")->SetLayoutPos(LP_None);
  1446. }
  1447. extern "C" int __cdecl CompareElementDataName(const void* pA, const void* pB);
  1448. extern "C" int __cdecl CompareElementDataSize(const void* pA, const void* pB);
  1449. extern "C" int __cdecl CompareElementDataFreq(const void* pA, const void* pB);
  1450. extern "C" int __cdecl CompareElementDataLast(const void* pA, const void* pB);
  1451. CompareCallback ARPFrame::GetCompareFunction()
  1452. {
  1453. switch(CurrentSortType)
  1454. {
  1455. case SORT_SIZE: return CompareElementDataSize;
  1456. case SORT_TIMESUSED: return CompareElementDataFreq;
  1457. case SORT_LASTUSED: return CompareElementDataLast;
  1458. default: return CompareElementDataName;
  1459. }
  1460. }
  1461. void ARPFrame::SortList(int iNew, int iOld)
  1462. {
  1463. if ((iNew >= 0) && (iNew != CurrentSortType))
  1464. {
  1465. CurrentSortType = (SortType) iNew;
  1466. StartDefer();
  1467. if (((iNew != SORT_NAME) || (iOld != SORT_SIZE)) &&
  1468. ((iNew != SORT_SIZE) || (iOld != SORT_NAME)))
  1469. {
  1470. Value* pvChildren;
  1471. ElementList* pel = _peInstalledItemList->GetChildren(&pvChildren);
  1472. if (NULL == pel)
  1473. {
  1474. EndDefer();
  1475. return;
  1476. }
  1477. for (UINT i = 0; i < pel->GetSize(); i++)
  1478. ((ARPItem*) pel->GetItem(i))->SortBy(iNew, iOld);
  1479. pvChildren->Release();
  1480. }
  1481. _peInstalledItemList->SortChildren(GetCompareFunction());
  1482. if (!_peInstalledItemList->GetSelection())
  1483. {
  1484. Value* pv;
  1485. ElementList* peList = _peInstalledItemList->GetChildren(&pv);
  1486. if (NULL == peList)
  1487. {
  1488. EndDefer();
  1489. return;
  1490. }
  1491. _peInstalledItemList->SetSelection(peList->GetItem(0));
  1492. pv->Release();
  1493. }
  1494. EndDefer();
  1495. }
  1496. }
  1497. void ARPFrame::SelectInstalledApp(IInstalledApp* piia)
  1498. {
  1499. Value* pv;
  1500. ElementList* peList = _peInstalledItemList->GetChildren(&pv);
  1501. for (UINT i = 0; i < peList->GetSize(); i++)
  1502. {
  1503. ARPItem* pai = (ARPItem*) peList->GetItem(i);
  1504. if (pai->_piia == piia)
  1505. {
  1506. pai->SetKeyFocus();
  1507. break;
  1508. }
  1509. }
  1510. pv->Release();
  1511. }
  1512. // Selects an app adjacent in the list to piia if possible, or to the fallback otherwise.
  1513. // First preference is for the app immediately following piia, if available.
  1514. void ARPFrame::SelectClosestApp(IInstalledApp* piia)
  1515. {
  1516. Value* pv;
  1517. ElementList* peList = _peInstalledItemList->GetChildren(&pv);
  1518. for (UINT i = 0; i < peList->GetSize(); i++)
  1519. {
  1520. ARPItem* pai = (ARPItem*) peList->GetItem(i);
  1521. if (pai->_piia == piia)
  1522. {
  1523. Element* peFocus = FallbackFocus();
  1524. // If there is an app after piia, select it.
  1525. if ((i + 1) < peList->GetSize())
  1526. {
  1527. peFocus = (Element*) peList->GetItem(i + 1);
  1528. }
  1529. // else if there is an app before piia, select it
  1530. else if (i != 0)
  1531. {
  1532. peFocus = (Element*) peList->GetItem(i - 1);
  1533. }
  1534. peFocus->SetKeyFocus();
  1535. break;
  1536. }
  1537. }
  1538. pv->Release();
  1539. }
  1540. ////////////////////////////////////////////////////////
  1541. // Callee thread-safe invoke (override)
  1542. void ARPFrame::OnInvoke(UINT nType, void* pData)
  1543. {
  1544. // We are shutting down, ignore any requests from other threads
  1545. if (!g_fRun)
  1546. return;
  1547. // Initialize ID cache if first pass
  1548. if (!ARPItem::_idTitle)
  1549. {
  1550. ARPItem::_idTitle = StrToID(L"title");
  1551. ARPItem::_idIcon = StrToID(L"icon");
  1552. ARPItem::_idSize = StrToID(L"size");
  1553. ARPItem::_idFreq = StrToID(L"freq");
  1554. ARPItem::_idLastUsed = StrToID(L"lastused");
  1555. ARPItem::_idInstalled = StrToID(L"installed");
  1556. ARPItem::_idExInfo = StrToID(L"exinfo");
  1557. ARPItem::_idSupInfo = StrToID(L"supinfo");
  1558. ARPItem::_idItemAction = StrToID(L"itemaction");
  1559. ARPItem::_idRow[0] = StrToID(L"row1");
  1560. ARPItem::_idRow[1] = StrToID(L"row2");
  1561. ARPItem::_idRow[2] = StrToID(L"row3");
  1562. }
  1563. switch (nType)
  1564. {
  1565. case ARP_SETINSTALLEDITEMCOUNT:
  1566. // pData is item count
  1567. _cMaxInstalledItems = (int)(INT_PTR)pData;
  1568. break;
  1569. case ARP_DECREMENTINSTALLEDITEMCOUNT:
  1570. _cMaxInstalledItems--;
  1571. break;
  1572. case ARP_SETPUBLISHEDITEMCOUNT:
  1573. // pData is item count
  1574. _cMaxPublishedItems = (int)(INT_PTR)pData;
  1575. break;
  1576. case ARP_DECREMENTPUBLISHEDITEMCOUNT:
  1577. _cMaxPublishedItems--;
  1578. break;
  1579. case ARP_SETPUBLISHEDFEEDBACKEMPTY:
  1580. {
  1581. WCHAR szTemp[1024];
  1582. if (_bTerminalServer)
  1583. {
  1584. // We are running terminal server
  1585. // This means no applications are displayed by design (not because there aren't any available)
  1586. LoadStringW(_pParser->GetHInstance(), IDS_TERMSERVFEEDBACK, szTemp, DUIARRAYSIZE(szTemp));
  1587. }
  1588. else
  1589. {
  1590. LoadStringW(_pParser->GetHInstance(), IDS_EMPTYFEEDBACK, szTemp, DUIARRAYSIZE(szTemp));
  1591. }
  1592. _pePublishedItemList->SetContentString(szTemp);
  1593. SetElementAccessability(_pePublishedItemList, true, ROLE_SYSTEM_STATICTEXT, szTemp);
  1594. }
  1595. break;
  1596. case ARP_INSERTINSTALLEDITEM:
  1597. {
  1598. WCHAR szTemp[1024] = {0};
  1599. // pData is InsertItemData struct
  1600. InsertItemData* piid = (InsertItemData*)pData;
  1601. StartDefer();
  1602. // Create ARP item
  1603. DUIAssertNoMsg(_pParser);
  1604. ARPItem* peItem;
  1605. Element* pe;
  1606. if (_hdsaInstalledItems == NULL)
  1607. {
  1608. LoadStringW(_pParser->GetHInstance(), IDS_PLEASEWAIT, szTemp, DUIARRAYSIZE(szTemp));
  1609. _hdsaInstalledItems = DSA_Create(sizeof(ARPItem*), _cMaxInstalledItems);
  1610. _peInstalledItemList->SetContentString(szTemp);
  1611. }
  1612. _pParser->CreateElement(L"installeditem", NULL, (Element**)&peItem);
  1613. peItem->_paf = this;
  1614. // Add appropriate change, remove buttons
  1615. Element* peAction = NULL;
  1616. if (!(piid->dwActions & APPACTION_MODIFYREMOVE))
  1617. {
  1618. // It isn't marked with modify/remove (the default)
  1619. // Somebody gave us some special instructions from the registry
  1620. if (!(piid->dwActions & APPACTION_UNINSTALL))
  1621. {
  1622. // NoRemove is set to 1
  1623. if (piid->dwActions & APPACTION_MODIFY)
  1624. {
  1625. // NoModify is not set so we can show the change button
  1626. _pParser->CreateElement(L"installeditemchangeonlyaction", NULL, &peAction);
  1627. if (!ARPItem::_idChg)
  1628. {
  1629. ARPItem::_idChg = StrToID(L"chg");
  1630. }
  1631. LoadStringW(_pParser->GetHInstance(), IDS_HELPCHANGE, szTemp, DUIARRAYSIZE(szTemp));
  1632. }
  1633. }
  1634. else if (!(piid->dwActions & APPACTION_MODIFY))
  1635. {
  1636. // NoModify is set to 1
  1637. // The only way we get here is if NoRemove is not set
  1638. // so we don't have to check it again
  1639. _pParser->CreateElement(L"installeditemremoveonlyaction", NULL, &peAction);
  1640. if (!ARPItem::_idRm)
  1641. {
  1642. ARPItem::_idRm = StrToID(L"rm");
  1643. }
  1644. LoadStringW(_pParser->GetHInstance(), IDS_HELPREMOVE, szTemp, DUIARRAYSIZE(szTemp));
  1645. }
  1646. else
  1647. {
  1648. // Just display both Change and Remove buttons
  1649. _pParser->CreateElement(L"installeditemdoubleaction", NULL, &peAction);
  1650. if (!ARPItem::_idChg)
  1651. {
  1652. ARPItem::_idChg = StrToID(L"chg");
  1653. ARPItem::_idRm = StrToID(L"rm");
  1654. }
  1655. LoadStringW(_pParser->GetHInstance(), IDS_HELPCHANGEORREMOVE, szTemp, DUIARRAYSIZE(szTemp));
  1656. }
  1657. }
  1658. else
  1659. {
  1660. // Display the default "Change/Remove" button
  1661. _pParser->CreateElement(L"installeditemsingleaction", NULL, &peAction);
  1662. if (!ARPItem::_idChgRm)
  1663. ARPItem::_idChgRm = StrToID(L"chgrm");
  1664. LoadStringW(_pParser->GetHInstance(), IDS_HELPCHANGEREMOVE, szTemp, DUIARRAYSIZE(szTemp));
  1665. }
  1666. // Common steps for all cases above
  1667. if (peAction)
  1668. {
  1669. // If peAction is not set, we are not displaying any buttons...
  1670. pe = FindDescendentByName(peItem, L"instruct");
  1671. pe->SetContentString(szTemp);
  1672. SetElementAccessability(pe, true, ROLE_SYSTEM_STATICTEXT, szTemp);
  1673. peItem->FindDescendent(ARPItem::_idItemAction)->Add(peAction);
  1674. }
  1675. // Support information
  1676. if (!piid->bSupportInfo)
  1677. peItem->FindDescendent(ARPItem::_idSupInfo)->SetLayoutPos(LP_None);
  1678. // Set fields
  1679. // Installed app interface pointer
  1680. peItem->_piia = piid->piia;
  1681. peItem->_piia->AddRef();
  1682. // should just be call into the peItem: peItem->SetTimesUsed(piid->iTimesUsed); etc.
  1683. peItem->_iTimesUsed = piid->iTimesUsed;
  1684. peItem->_ftLastUsed = piid->ftLastUsed;
  1685. peItem->_ullSize = piid->ullSize;
  1686. // Title
  1687. Element* peField = peItem->FindDescendent(ARPItem::_idTitle);
  1688. DUIAssertNoMsg(peField);
  1689. peField->SetContentString(piid->pszTitle);
  1690. SetElementAccessability(peField, true, ROLE_SYSTEM_STATICTEXT, piid->pszTitle);
  1691. SetElementAccessability(peItem, true, ROLE_SYSTEM_LISTITEM, piid->pszTitle);
  1692. // Icon
  1693. if (piid->pszImage)
  1694. {
  1695. HICON hIcon;
  1696. ExtractIconExW(piid->pszImage, piid->iIconIndex, NULL, &hIcon, 1);
  1697. if (hIcon)
  1698. {
  1699. peField = peItem->FindDescendent(ARPItem::_idIcon);
  1700. DUIAssertNoMsg(peField);
  1701. Value* pvIcon = Value::CreateGraphic(hIcon);
  1702. if (NULL != pvIcon)
  1703. {
  1704. peField->SetValue(Element::ContentProp, PI_Local, pvIcon); // Element takes ownership (will destroy)
  1705. pvIcon->Release();
  1706. }
  1707. }
  1708. }
  1709. *szTemp = NULL;
  1710. // Size
  1711. peField = peItem->FindDescendent(ARPItem::_idSize);
  1712. DUIAssertNoMsg(peField);
  1713. if (IsValidSize(piid->ullSize))
  1714. {
  1715. WCHAR szMBLabel[5] = L"MB";
  1716. WCHAR szSize[15] = {0};
  1717. double fSize = (double)(__int64)piid->ullSize;
  1718. fSize /= 1048576.; // 1MB
  1719. LoadStringW(_pParser->GetHInstance(), IDS_SIZEUNIT, szMBLabel, DUIARRAYSIZE(szMBLabel));
  1720. if (fSize > 100.)
  1721. {
  1722. StringCchPrintfW(szTemp, ARRAYSIZE(szTemp), L"%d", (__int64)fSize); // Clip
  1723. }
  1724. else
  1725. {
  1726. StringCchPrintfW(szTemp, ARRAYSIZE(szTemp), L"%.2f", fSize);
  1727. }
  1728. // Format the number for the current user's locale
  1729. if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, NULL, szSize, DUIARRAYSIZE(szSize)) == 0)
  1730. {
  1731. lstrcpyn(szSize, szTemp, DUIARRAYSIZE(szSize));
  1732. }
  1733. if (SUCCEEDED(StringCchCat(szSize, ARRAYSIZE(szSize), szMBLabel)))
  1734. {
  1735. peField->SetContentString(szSize);
  1736. SetElementAccessability(peField, true, ROLE_SYSTEM_STATICTEXT, szTemp);
  1737. }
  1738. }
  1739. else
  1740. {
  1741. peField->SetVisible(false);
  1742. FindDescendentByName(peItem, L"sizelabel")->SetVisible(false);
  1743. }
  1744. // Frequency
  1745. peField = peItem->FindDescendent(ARPItem::_idFreq);
  1746. DUIAssertNoMsg(peField);
  1747. if (IsValidFrequency(piid->iTimesUsed))
  1748. {
  1749. if (piid->iTimesUsed <= 2)
  1750. LoadStringW(_pParser->GetHInstance(), IDS_USEDREARELY, szTemp, DUIARRAYSIZE(szTemp));
  1751. else if (piid->iTimesUsed <= 10)
  1752. LoadStringW(_pParser->GetHInstance(), IDS_USEDOCCASIONALLY, szTemp, DUIARRAYSIZE(szTemp));
  1753. else
  1754. LoadStringW(_pParser->GetHInstance(), IDS_USEDFREQUENTLY, szTemp, DUIARRAYSIZE(szTemp));
  1755. peField->SetContentString(szTemp);
  1756. SetElementAccessability(peField, true, ROLE_SYSTEM_STATICTEXT, szTemp);
  1757. }
  1758. else
  1759. {
  1760. peField->SetVisible(false);
  1761. FindDescendentByName(peItem, L"freqlabel")->SetVisible(false);
  1762. }
  1763. // Last used on
  1764. peField = peItem->FindDescendent(ARPItem::_idLastUsed);
  1765. DUIAssertNoMsg(peField);
  1766. if (IsValidFileTime(piid->ftLastUsed))
  1767. {
  1768. LPWSTR szDate;
  1769. SYSTEMTIME stLastUsed;
  1770. DWORD dwDateSize = 0;
  1771. BOOL bFailed=FALSE;
  1772. // Get the date it was last used on
  1773. FileTimeToSystemTime(&piid->ftLastUsed, &stLastUsed);
  1774. dwDateSize = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &stLastUsed, NULL, NULL, dwDateSize);
  1775. if (dwDateSize)
  1776. {
  1777. szDate = new WCHAR[dwDateSize];
  1778. if (szDate)
  1779. {
  1780. dwDateSize = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &stLastUsed, NULL, szDate, dwDateSize);
  1781. if (dwDateSize)
  1782. {
  1783. peField->SetContentString(szDate);
  1784. SetElementAccessability(peField, true, ROLE_SYSTEM_STATICTEXT, szDate);
  1785. }
  1786. else
  1787. {
  1788. bFailed=TRUE;
  1789. }
  1790. delete szDate;
  1791. }
  1792. else
  1793. {
  1794. bFailed=TRUE;
  1795. }
  1796. }
  1797. else
  1798. {
  1799. bFailed=TRUE;
  1800. }
  1801. if (bFailed)
  1802. {
  1803. peField->SetVisible(false);
  1804. FindDescendentByName(peItem, L"lastlabel")->SetVisible(false);
  1805. }
  1806. }
  1807. else
  1808. {
  1809. peField->SetVisible(false);
  1810. FindDescendentByName(peItem, L"lastlabel")->SetVisible(false);
  1811. }
  1812. // Insert item into DSA
  1813. int cNum = DSA_InsertItem(_hdsaInstalledItems, INT_MAX, &peItem);
  1814. // Insert failed
  1815. if (cNum < 0)
  1816. {
  1817. _cMaxInstalledItems--;
  1818. // We're out of items to insert so remove the wait string
  1819. if (!_cMaxInstalledItems)
  1820. {
  1821. _peInstalledItemList->SetContentString(L"");
  1822. }
  1823. }
  1824. EndDefer();
  1825. }
  1826. break;
  1827. case ARP_DONEINSERTINSTALLEDITEM:
  1828. {
  1829. DUITrace(">> ARP_DONEINSERTINSTALLEDITEM STARTED.\n");
  1830. StartDefer();
  1831. if (_hdsaInstalledItems != NULL)
  1832. {
  1833. int iMax = DSA_GetItemCount(_hdsaInstalledItems);
  1834. // Just to be safe so if all items get removed we won't be
  1835. // stuck with the please wait string.
  1836. _peInstalledItemList->SetContentString(L"");
  1837. for (int i=0; i < iMax; i++)
  1838. {
  1839. ARPItem* aItem;
  1840. if (DSA_GetItem(_hdsaInstalledItems, i, &aItem))
  1841. {
  1842. _peInstalledItemList->Add(aItem, GetCompareFunction());
  1843. }
  1844. }
  1845. DSA_Destroy(_hdsaInstalledItems);
  1846. _hdsaInstalledItems = NULL;
  1847. // Set focus to first item
  1848. // once list is populated, move focus to list
  1849. GetNthChild(_peInstalledItemList, 0)->SetKeyFocus();
  1850. _bInstalledListFilled = true;
  1851. }
  1852. EndDefer();
  1853. DUITrace(">> ARP_DONEINSERTINSTALLEDITEM DONE.\n");
  1854. }
  1855. break;
  1856. case ARP_INSERTPUBLISHEDITEM:
  1857. {
  1858. WCHAR szTemp[MAX_PATH] = {0};
  1859. InsertItemData* piid = (InsertItemData*)pData;
  1860. StartDefer();
  1861. // Need a DSA so we can add them all to the list at one time to avoid
  1862. // having lots of redrawing of the layout. This method is much much faster.
  1863. if (_hdsaPublishedItems == NULL)
  1864. {
  1865. LoadStringW(_pParser->GetHInstance(), IDS_PLEASEWAIT, szTemp, DUIARRAYSIZE(szTemp));
  1866. _hdsaPublishedItems = DSA_Create(sizeof(ARPItem*), _cMaxPublishedItems);
  1867. _pePublishedItemList->SetContentString(szTemp);
  1868. }
  1869. // Create ARP item
  1870. DUIAssertNoMsg(_pParser);
  1871. ARPItem* peItem;
  1872. Element* pe;
  1873. _pParser->CreateElement(L"publisheditem", NULL, (Element**)&peItem);
  1874. peItem->_paf = this;
  1875. // Add appropriate change, remove buttons
  1876. Element* peAction = NULL;
  1877. _pParser->CreateElement(L"publisheditemsingleaction", NULL, &peAction);
  1878. if (!ARPItem::_idAdd)
  1879. ARPItem::_idAdd = StrToID(L"add");
  1880. peItem->FindDescendent(ARPItem::_idItemAction)->Add(peAction);
  1881. if (S_OK == piid->pipa->IsInstalled())
  1882. {
  1883. peItem->ShowInstalledString(TRUE);
  1884. }
  1885. // Published app interface pointer
  1886. peItem->_pipa = piid->pipa;
  1887. peItem->_pipa->AddRef();
  1888. peItem->_ppai = piid->ppai;
  1889. // Title
  1890. Element* peField = peItem->FindDescendent(ARPItem::_idTitle);
  1891. DUIAssertNoMsg(peField);
  1892. peField->SetContentString(piid->pszTitle);
  1893. SetElementAccessability(peField, true, ROLE_SYSTEM_STATICTEXT, piid->pszTitle);
  1894. SetElementAccessability(peItem, true, ROLE_SYSTEM_LISTITEM, piid->pszTitle);
  1895. // Icon
  1896. if (piid->pszImage)
  1897. {
  1898. HICON hIcon;
  1899. ExtractIconExW(piid->pszImage, NULL, NULL, &hIcon, 1);
  1900. if (hIcon)
  1901. {
  1902. peField = peItem->FindDescendent(ARPItem::_idIcon);
  1903. DUIAssertNoMsg(peField);
  1904. Value* pvIcon = Value::CreateGraphic(hIcon);
  1905. peField->SetValue(Element::ContentProp, PI_Local, pvIcon); // Element takes ownership (will destroy)
  1906. pvIcon->Release();
  1907. }
  1908. }
  1909. // Insert into DSA, alphabetically
  1910. if (_hdsaPublishedItems != NULL)
  1911. {
  1912. int iInsert;
  1913. int cNum = DSA_GetItemCount(_hdsaPublishedItems);
  1914. // Search for place to insert
  1915. for (iInsert = 0; iInsert < cNum; iInsert++)
  1916. {
  1917. ARPItem* fItem;
  1918. if (DSA_GetItem(_hdsaPublishedItems, iInsert, &fItem))
  1919. {
  1920. Value* pvTitle;
  1921. pe = fItem->FindDescendent(ARPItem::_idTitle);
  1922. DUIAssertNoMsg(pe);
  1923. if (wcscmp(pe->GetContentString(&pvTitle), piid->pszTitle) > 0)
  1924. {
  1925. pvTitle->Release();
  1926. break;
  1927. }
  1928. pvTitle->Release();
  1929. }
  1930. }
  1931. // Insert item into DSA
  1932. if (DSA_InsertItem(_hdsaPublishedItems, iInsert, &peItem) < 0)
  1933. {
  1934. // Failed to insert the item
  1935. // Bring the total down by 1
  1936. _cMaxPublishedItems--;
  1937. }
  1938. }
  1939. // We only want to start actually adding the items to the list
  1940. // when we reach our last item. If we insert each item into the list
  1941. // as we process these messages, it can take upwards of 4 minutes to populate
  1942. // if there are a lot of items.
  1943. if (_hdsaPublishedItems != NULL &&
  1944. DSA_GetItemCount(_hdsaPublishedItems) == _cMaxPublishedItems)
  1945. {
  1946. for (int i=0; i < _cMaxPublishedItems; i++)
  1947. {
  1948. ARPItem* aItem;
  1949. if (DSA_GetItem(_hdsaPublishedItems, i, &aItem))
  1950. {
  1951. _pePublishedItemList->Insert(aItem, i);
  1952. }
  1953. }
  1954. DSA_Destroy(_hdsaPublishedItems);
  1955. _hdsaPublishedItems = NULL;
  1956. _pePublishedItemList->SetSelection(GetNthChild(_pePublishedItemList, 0));
  1957. }
  1958. EndDefer();
  1959. }
  1960. break;
  1961. case ARP_INSERTOCSETUPITEM:
  1962. {
  1963. WCHAR szTemp[MAX_PATH] = {0};
  1964. InsertItemData* piid = (InsertItemData*)pData;
  1965. StartDefer();
  1966. // Create ARP item
  1967. DUIAssertNoMsg(_pParser);
  1968. ARPItem* peItem;
  1969. if (SUCCEEDED(_pParser->CreateElement(L"ocsetupitem", NULL, (Element**)&peItem)))
  1970. {
  1971. peItem->_paf = this;
  1972. if (!ARPItem::_idConfigure)
  1973. ARPItem::_idConfigure = StrToID(L"configure");
  1974. // Add appropriate change, remove buttons
  1975. Element* peAction = NULL;
  1976. if (SUCCEEDED(_pParser->CreateElement(L"ocsetupitemsingleaction", NULL, &peAction)))
  1977. {
  1978. Element *peItemAction = peItem->FindDescendent(ARPItem::_idItemAction);
  1979. if (NULL != peItemAction && SUCCEEDED(peItemAction->Add(peAction)))
  1980. {
  1981. peAction = NULL; // Action successfully added.
  1982. // OCSetup pointer
  1983. peItem->_pocsa = piid->pocsa;
  1984. // Title
  1985. Element* peField = peItem->FindDescendent(ARPItem::_idTitle);
  1986. DUIAssertNoMsg(peField);
  1987. peField->SetContentString(piid->pszTitle);
  1988. SetElementAccessability(peField, true, ROLE_SYSTEM_STATICTEXT, piid->pszTitle);
  1989. SetElementAccessability(peItem, true, ROLE_SYSTEM_LISTITEM, piid->pszTitle);
  1990. // Insert into list, alphabetically
  1991. Value* pvElList;
  1992. ElementList* peElList = _peOCSetupItemList->GetChildren(&pvElList);
  1993. Value* pvTitle;
  1994. Element* pe;
  1995. UINT iInsert = 0;
  1996. if (peElList)
  1997. {
  1998. for (; iInsert < peElList->GetSize(); iInsert++)
  1999. {
  2000. pe = peElList->GetItem(iInsert)->FindDescendent(ARPItem::_idTitle);
  2001. DUIAssertNoMsg(pe);
  2002. if (wcscmp(pe->GetContentString(&pvTitle), piid->pszTitle) > 0)
  2003. {
  2004. pvTitle->Release();
  2005. break;
  2006. }
  2007. pvTitle->Release();
  2008. }
  2009. }
  2010. pvElList->Release();
  2011. // Insert item into list
  2012. if (FAILED(_peOCSetupItemList->Insert(peItem, iInsert)))
  2013. {
  2014. //
  2015. // Failed to insert item into list. Need to delete
  2016. // the OCSetupApp object.
  2017. //
  2018. delete peItem->_pocsa;
  2019. peItem->_pocsa = NULL;
  2020. }
  2021. else
  2022. {
  2023. peItem = NULL; // Successfully added to list.
  2024. _peOCSetupItemList->SetSelection(GetNthChild(_peOCSetupItemList, 0));
  2025. }
  2026. }
  2027. if (NULL != peAction)
  2028. {
  2029. peAction->Destroy();
  2030. peAction = NULL;
  2031. }
  2032. }
  2033. if (NULL != peItem)
  2034. {
  2035. peItem->Destroy();
  2036. peItem = NULL;
  2037. }
  2038. }
  2039. EndDefer();
  2040. }
  2041. break;
  2042. case ARP_POPULATECATEGORYCOMBO:
  2043. {
  2044. UINT i;
  2045. WCHAR szTemp[1024];
  2046. UINT iSelection = 0; // Default to "All Categories"
  2047. SHELLAPPCATEGORY *psac = _psacl->pCategory;
  2048. LoadStringW(_pParser->GetHInstance(), IDS_ALLCATEGORIES, szTemp, DUIARRAYSIZE(szTemp));
  2049. _pePublishedCategory->AddString(szTemp);
  2050. szTemp[0] = 0;
  2051. ARPGetPolicyString(L"DefaultCategory", szTemp, ARRAYSIZE(szTemp));
  2052. StartDefer();
  2053. for (i = 0; i < _psacl->cCategories; i++, psac++)
  2054. {
  2055. if (psac->pszCategory)
  2056. {
  2057. _pePublishedCategory->AddString(psac->pszCategory);
  2058. if (0 == lstrcmpi(psac->pszCategory, szTemp))
  2059. {
  2060. //
  2061. // Policy says default to this category.
  2062. // i + 1 is required since element 0 is "All Categories"
  2063. // and is ALWAYS present at element 0.
  2064. //
  2065. iSelection = i + 1;
  2066. }
  2067. }
  2068. }
  2069. _pePublishedCategory->SetSelection(iSelection);
  2070. EndDefer();
  2071. }
  2072. break;
  2073. case ARP_PUBLISHEDLISTCOMPLETE:
  2074. {
  2075. _pePublishedCategory->SetEnabled(true);
  2076. break;
  2077. }
  2078. }
  2079. }
  2080. void ARPFrame::ManageAnimations()
  2081. {
  2082. BOOL fAnimate = TRUE;
  2083. SystemParametersInfo(SPI_GETMENUANIMATION, 0, &fAnimate, 0);
  2084. if (fAnimate)
  2085. {
  2086. if (!IsFrameAnimationEnabled())
  2087. {
  2088. _bAnimationEnabled = true;
  2089. EnableAnimations();
  2090. }
  2091. }
  2092. else
  2093. {
  2094. if (IsFrameAnimationEnabled())
  2095. {
  2096. _bAnimationEnabled = false;
  2097. DisableAnimations();
  2098. }
  2099. }
  2100. DUIAssertNoMsg((fAnimate != FALSE) == IsFrameAnimationEnabled());
  2101. }
  2102. HRESULT CalculateWidthCB(ClientPicker* pcp, LPARAM)
  2103. {
  2104. pcp->CalculateWidth();
  2105. return S_OK;
  2106. }
  2107. LRESULT ARPFrame::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2108. {
  2109. switch (uMsg)
  2110. {
  2111. case WM_THEMECHANGED:
  2112. case WM_SETTINGCHANGE:
  2113. {
  2114. LockWindowUpdate(_pnhh->GetHWND());
  2115. Parser* pOldStyle = _pParserStyle;
  2116. Parser* pNewStyle = NULL;
  2117. if (!pOldStyle)
  2118. break;
  2119. // System parameter changing, reload style sheets so to sync
  2120. // up with changes
  2121. if (_fThemedStyle)
  2122. {
  2123. for (int i = FIRSTHTHEME; i <= LASTHTHEME; i++)
  2124. {
  2125. if (_arH[i])
  2126. {
  2127. CloseThemeData(_arH[i]);
  2128. _arH[i] = NULL;
  2129. }
  2130. }
  2131. }
  2132. CreateStyleParser(&pNewStyle);
  2133. // Replace all style sheets
  2134. if (pNewStyle)
  2135. {
  2136. Parser::ReplaceSheets(this, pOldStyle, pNewStyle);
  2137. }
  2138. // New style parser
  2139. _pParserStyle = pNewStyle;
  2140. // Destroy old
  2141. pOldStyle->Destroy();
  2142. // Animation setting may have changed
  2143. ManageAnimations();
  2144. TraverseTree<ClientPicker>(this, CalculateWidthCB);
  2145. LockWindowUpdate(NULL);
  2146. }
  2147. break;
  2148. }
  2149. return HWNDElement::WndProc(hWnd, uMsg, wParam, lParam);
  2150. }
  2151. ////////////////////////////////////////////////////////
  2152. // ClassInfo (must appear after property definitions)
  2153. // Define class info with type and base type, set static class pointer
  2154. IClassInfo* ARPFrame::Class = NULL;
  2155. HRESULT ARPFrame::Register()
  2156. {
  2157. return ClassInfo<ARPFrame,HWNDElement>::Register(L"ARPFrame", NULL, 0);
  2158. }
  2159. ////////////////////////////////////////////////////////
  2160. // ARPItem class
  2161. ////////////////////////////////////////////////////////
  2162. // ARP item IDs
  2163. ATOM ARPItem::_idTitle = 0;
  2164. ATOM ARPItem::_idIcon = 0;
  2165. ATOM ARPItem::_idSize = 0;
  2166. ATOM ARPItem::_idFreq = 0;
  2167. ATOM ARPItem::_idLastUsed = 0;
  2168. ATOM ARPItem::_idExInfo = 0;
  2169. ATOM ARPItem::_idInstalled = 0;
  2170. ATOM ARPItem::_idChgRm = 0;
  2171. ATOM ARPItem::_idChg = 0;
  2172. ATOM ARPItem::_idRm = 0;
  2173. ATOM ARPItem::_idAdd = 0;
  2174. ATOM ARPItem::_idConfigure = 0;
  2175. ATOM ARPItem::_idSupInfo = 0;
  2176. ATOM ARPItem::_idItemAction = 0;
  2177. ATOM ARPItem::_idRow[3] = { 0, 0, 0 };
  2178. ////////////////////////////////////////////////////////
  2179. // ARPItem
  2180. HRESULT ARPItem::Create(OUT Element** ppElement)
  2181. {
  2182. *ppElement = NULL;
  2183. ARPItem* pai = HNew<ARPItem>();
  2184. if (!pai)
  2185. return E_OUTOFMEMORY;
  2186. HRESULT hr = pai->Initialize();
  2187. if (FAILED(hr))
  2188. {
  2189. pai->Destroy();
  2190. return hr;
  2191. }
  2192. *ppElement = pai;
  2193. return S_OK;
  2194. }
  2195. HRESULT ARPItem::Initialize()
  2196. {
  2197. _piia = NULL; // Init before base in event of failure (invokes desstructor)
  2198. _pipa = NULL; // Init before base in event of failure (invokes desstructor)
  2199. // Do base class initialization
  2200. HRESULT hr = Button::Initialize(AE_MouseAndKeyboard);
  2201. if (FAILED(hr))
  2202. return hr;
  2203. return S_OK;
  2204. }
  2205. ARPItem::~ARPItem()
  2206. {
  2207. if (_piia)
  2208. _piia->Release();
  2209. if (_pipa)
  2210. _pipa->Release();
  2211. if (_pocsa)
  2212. delete _pocsa;
  2213. if (_ppai)
  2214. {
  2215. ClearPubAppInfo(_ppai);
  2216. delete _ppai;
  2217. }
  2218. }
  2219. void ARPItem::ShowInstalledString(BOOL bInstalled)
  2220. {
  2221. WCHAR szTemp[MAX_PATH] = L"";
  2222. Element* pe = FindDescendent(ARPItem::_idInstalled);
  2223. if (pe != NULL)
  2224. {
  2225. if (bInstalled)
  2226. {
  2227. LoadStringW(g_hinst, IDS_INSTALLED, szTemp, DUIARRAYSIZE(szTemp));
  2228. }
  2229. pe->SetContentString(szTemp);
  2230. SetElementAccessability(pe, true, ROLE_SYSTEM_STATICTEXT, szTemp);
  2231. }
  2232. }
  2233. HWND _CreateTransparentStubWindow(HWND hwndParent);
  2234. ////////////////////////////////////////////////////////
  2235. // Generic eventing
  2236. void ARPItem::OnEvent(Event* pEvent)
  2237. {
  2238. // Handle only bubbled generic events
  2239. if (pEvent->uidType == Element::KeyboardNavigate)
  2240. {
  2241. KeyboardNavigateEvent* pkne = (KeyboardNavigateEvent*)pEvent;
  2242. if (pkne->iNavDir & NAV_LOGICAL)
  2243. {
  2244. if (pEvent->nStage == GMF_DIRECT)
  2245. {
  2246. }
  2247. }
  2248. else
  2249. {
  2250. if (pEvent->nStage == GMF_ROUTED)
  2251. {
  2252. pEvent->fHandled = true;
  2253. KeyboardNavigateEvent kne;
  2254. kne.uidType = Element::KeyboardNavigate;
  2255. kne.peTarget = this;
  2256. kne.iNavDir = pkne->iNavDir;
  2257. FireEvent(&kne); // Will route and bubble
  2258. }
  2259. return;
  2260. }
  2261. }
  2262. if (pEvent->nStage == GMF_BUBBLED)
  2263. {
  2264. if (pEvent->uidType == Button::Click)
  2265. {
  2266. ButtonClickEvent* pbce = (ButtonClickEvent*)pEvent;
  2267. ATOM id = pbce->peTarget->GetID();
  2268. if (id == _idChgRm || id == _idRm || id == _idChg || id == _idAdd || id == _idConfigure)
  2269. {
  2270. HWND hwndStub = NULL;
  2271. HWND hwndHost = NULL;
  2272. DUIAssertNoMsg(_paf);
  2273. if (_paf)
  2274. {
  2275. hwndHost = _paf->GetHostWindow();
  2276. }
  2277. if (hwndHost)
  2278. {
  2279. hwndStub = _CreateTransparentStubWindow(hwndHost);
  2280. EnableWindow(hwndHost, FALSE);
  2281. SetActiveWindow(hwndStub);
  2282. }
  2283. if (id == _idAdd)
  2284. {
  2285. HRESULT hres = S_OK;
  2286. // Does the app have an expired publishing time?
  2287. if (_ppai->dwMask & PAI_EXPIRETIME)
  2288. {
  2289. // Yes, it does. Let's compare the expired time with our current time
  2290. SYSTEMTIME stCur = {0};
  2291. GetLocalTime(&stCur);
  2292. // Is "now" later than the expired time?
  2293. if (CompareSystemTime(&stCur, &_ppai->stExpire) > 0)
  2294. {
  2295. // Yes, warn the user and return failure
  2296. ShellMessageBox(g_hinst, hwndHost, MAKEINTRESOURCE(IDS_EXPIRED),
  2297. MAKEINTRESOURCE(IDS_ARPTITLE), MB_OK | MB_ICONEXCLAMATION);
  2298. hres = E_FAIL;
  2299. }
  2300. }
  2301. // if hres is not set by the above code, preceed with installation
  2302. if (hres == S_OK)
  2303. {
  2304. HCURSOR hcur = ::SetCursor(LoadCursor(NULL, IDC_WAIT));
  2305. // On NT, let Terminal Services know that we are about to install an application.
  2306. // NOTE: This function should be called no matter the Terminal Services
  2307. // is running or not.
  2308. BOOL bPrevMode = TermsrvAppInstallMode();
  2309. SetTermsrvAppInstallMode(TRUE);
  2310. if (SUCCEEDED(_pipa->Install(NULL)))
  2311. {
  2312. // Show this item as installed
  2313. ShowInstalledString(TRUE);
  2314. // update installed items list
  2315. _paf->DirtyInstalledListFlag();
  2316. }
  2317. SetTermsrvAppInstallMode(bPrevMode);
  2318. ::SetCursor(hcur);
  2319. }
  2320. }
  2321. else
  2322. {
  2323. HRESULT hr = E_FAIL;
  2324. if ((id == _idChgRm) || (id == _idRm))
  2325. hr = _piia->Uninstall(hwndHost);
  2326. else if (id == _idChg)
  2327. hr = _piia->Modify(hwndHost);
  2328. if (SUCCEEDED(hr))
  2329. {
  2330. if (S_FALSE == _piia->IsInstalled())
  2331. {
  2332. _paf->DirtyPublishedListFlag();
  2333. }
  2334. }
  2335. }
  2336. if (id == _idConfigure)
  2337. {
  2338. _pocsa->Run();
  2339. _paf->RePopulateOCSetupItemList();
  2340. }
  2341. if (hwndHost)
  2342. {
  2343. if (!_piia)
  2344. {
  2345. EnableWindow(hwndHost, TRUE);
  2346. SetForegroundWindow(hwndHost);
  2347. }
  2348. if (hwndStub)
  2349. {
  2350. DestroyWindow(hwndStub);
  2351. }
  2352. EnableWindow(hwndHost, TRUE);
  2353. }
  2354. if (_piia)
  2355. {
  2356. if (S_OK == _piia->IsInstalled())
  2357. {
  2358. SetKeyFocus();
  2359. }
  2360. else
  2361. {
  2362. // remove from installed items list
  2363. _paf->SelectClosestApp(_piia);
  2364. Destroy();
  2365. }
  2366. }
  2367. pEvent->fHandled = true;
  2368. return;
  2369. }
  2370. }
  2371. }
  2372. Button::OnEvent(pEvent);
  2373. }
  2374. ////////////////////////////////////////////////////////
  2375. // System events
  2376. void ARPItem::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  2377. {
  2378. if (IsProp(Selected))
  2379. {
  2380. // Display of extended information
  2381. Element* peExInfo = FindDescendent(_idExInfo);
  2382. DUIAssertNoMsg(peExInfo);
  2383. peExInfo->SetLayoutPos(pvNew->GetBool() ? BLP_Top : LP_None);
  2384. // Do default processing in this case
  2385. }
  2386. Button::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  2387. }
  2388. void GetOrder(int iSortBy, int* iOrder)
  2389. {
  2390. switch (iSortBy)
  2391. {
  2392. case SORT_NAME:
  2393. case SORT_SIZE: iOrder[0] = 0; iOrder[1] = 1; iOrder[2] = 2; break;
  2394. case SORT_TIMESUSED: iOrder[0] = 1; iOrder[1] = 0; iOrder[2] = 2; break;
  2395. case SORT_LASTUSED: iOrder[0] = 2; iOrder[1] = 0; iOrder[2] = 1; break;
  2396. }
  2397. }
  2398. void ARPItem::SortBy(int iNew, int iOld)
  2399. {
  2400. Element* pe[3][2]; // size, timesused, lastused
  2401. int iOrderOld[3]; // size, timesused, lastused
  2402. int iOrderNew[3]; // size, timesused, lastused
  2403. GetOrder(iOld, iOrderOld);
  2404. GetOrder(iNew, iOrderNew);
  2405. //
  2406. // First get all the DUI elements to be sorted. If we
  2407. // can't get all of them, this sort fails.
  2408. //
  2409. bool bAllFound = true;
  2410. int i;
  2411. Element* peRow[3]; // row1, row2, row3
  2412. for (i = 0; i < ARRAYSIZE(peRow); i++)
  2413. {
  2414. if (iOrderOld[i] != iOrderNew[i])
  2415. {
  2416. peRow[i] = FindDescendent(ARPItem::_idRow[i]);
  2417. if (NULL == peRow[i])
  2418. {
  2419. bAllFound = false;
  2420. }
  2421. }
  2422. }
  2423. if (bAllFound)
  2424. {
  2425. for (i = 0; i < ARRAYSIZE(iOrderOld); i++) // loop through rows
  2426. {
  2427. int row = iOrderOld[i];
  2428. if (row == iOrderNew[i])
  2429. iOrderNew[i] = -1;
  2430. else
  2431. {
  2432. DUIAssertNoMsg(NULL != peRow[i]);
  2433. Value* pvChildren;
  2434. ElementList* pel;
  2435. pel = peRow[i]->GetChildren(&pvChildren);
  2436. pe[row][0] = pel->GetItem(0);
  2437. pe[row][1] = pel->GetItem(1);
  2438. pvChildren->Release();
  2439. }
  2440. }
  2441. for (i = 0; i < 3; i++)
  2442. {
  2443. int row = iOrderNew[i];
  2444. if (row != -1) // meaning that this row doesn't change
  2445. peRow[i]->Add(pe[row], 2);
  2446. }
  2447. }
  2448. }
  2449. ////////////////////////////////////////////////////////
  2450. // ClassInfo (must appear after property definitions)
  2451. // Define class info with type and base type, set static class pointer
  2452. IClassInfo* ARPItem::Class = NULL;
  2453. HRESULT ARPItem::Register()
  2454. {
  2455. return ClassInfo<ARPItem,Button>::Register(L"ARPItem", NULL, 0);
  2456. }
  2457. ////////////////////////////////////////////////////////
  2458. // ARPHelp
  2459. ////////////////////////////////////////////////////////
  2460. HRESULT ARPHelp::Create(OUT Element** ppElement)
  2461. {
  2462. UNREFERENCED_PARAMETER(ppElement);
  2463. DUIAssertForce("Cannot instantiate an HWND host derived Element via parser. Must use substitution.");
  2464. return E_NOTIMPL;
  2465. }
  2466. HRESULT ARPHelp::Create(NativeHWNDHost* pnhh, ARPFrame* paf, bool bDblBuffer, OUT Element** ppElement)
  2467. {
  2468. *ppElement = NULL;
  2469. ARPHelp* pah = HNew<ARPHelp>();
  2470. if (!pah)
  2471. return E_OUTOFMEMORY;
  2472. HRESULT hr = pah->Initialize(pnhh, paf, bDblBuffer);
  2473. if (FAILED(hr))
  2474. {
  2475. pah->Destroy();
  2476. return hr;
  2477. }
  2478. *ppElement = pah;
  2479. return S_OK;
  2480. }
  2481. HRESULT ARPHelp::Initialize(NativeHWNDHost* pnhh, ARPFrame* paf, bool bDblBuffer)
  2482. {
  2483. // Do base class initialization
  2484. HRESULT hr = HWNDElement::Initialize(pnhh->GetHWND(), bDblBuffer, 0);
  2485. if (FAILED(hr))
  2486. return hr;
  2487. // Initialize
  2488. // SetActive(AE_MouseAndKeyboard);
  2489. _pnhh = pnhh;
  2490. _paf = paf;
  2491. return S_OK;
  2492. }
  2493. void ARPHelp::SetDefaultFocus()
  2494. {
  2495. Element* pe = FindDescendentByName(this, L"close");
  2496. if (pe)
  2497. {
  2498. pe->SetKeyFocus();
  2499. }
  2500. }
  2501. ////////////////////////////////////////////////////////
  2502. // Generic eventing
  2503. void ARPHelp::OnEvent(Event* pEvent)
  2504. {
  2505. // Handle only bubbled generic events
  2506. if (pEvent->nStage == GMF_BUBBLED)
  2507. {
  2508. if (pEvent->uidType == Button::Click)
  2509. {
  2510. ATOM id = pEvent->peTarget->GetID();
  2511. if (id == StrToID(L"repair"))
  2512. _piia->Repair(NULL);
  2513. if (pEvent->peTarget->GetID() == StrToID(L"close"))
  2514. {
  2515. _pnhh->DestroyWindow();
  2516. }
  2517. pEvent->fHandled = true;
  2518. return;
  2519. }
  2520. }
  2521. HWNDElement::OnEvent(pEvent);
  2522. }
  2523. void ARPHelp::OnDestroy()
  2524. {
  2525. HWNDElement::OnDestroy();
  2526. if (_paf)
  2527. {
  2528. _paf->SetModalMode(false);
  2529. }
  2530. }
  2531. ARPHelp::~ARPHelp()
  2532. {
  2533. if (_paf)
  2534. {
  2535. EnableWindow(_paf->GetHWND(), TRUE);
  2536. SetFocus(_paf->GetHWND());
  2537. _paf->RestoreKeyFocus();
  2538. }
  2539. if (_pnhh)
  2540. {
  2541. _pnhh->Destroy();
  2542. }
  2543. }
  2544. ////////////////////////////////////////////////////////
  2545. // ClassInfo (must appear after property definitions)
  2546. // Define class info with type and base type, set static class pointer
  2547. IClassInfo* ARPHelp::Class = NULL;
  2548. HRESULT ARPHelp::Register()
  2549. {
  2550. return ClassInfo<ARPHelp,HWNDElement>::Register(L"ARPHelp", NULL, 0);
  2551. }
  2552. ////////////////////////////////////////////////////////
  2553. // ARPSupportItem
  2554. ////////////////////////////////////////////////////////
  2555. HRESULT ARPSupportItem::Create(OUT Element** ppElement)
  2556. {
  2557. *ppElement = NULL;
  2558. ARPSupportItem* pasi = HNew<ARPSupportItem>();
  2559. if (!pasi)
  2560. return E_OUTOFMEMORY;
  2561. HRESULT hr = pasi->Initialize();
  2562. if (FAILED(hr))
  2563. {
  2564. pasi->Destroy();
  2565. return hr;
  2566. }
  2567. *ppElement = pasi;
  2568. return S_OK;
  2569. }
  2570. Value* _pvRowLayout = NULL;
  2571. HRESULT ARPSupportItem::Initialize()
  2572. {
  2573. // Do base class initialization
  2574. HRESULT hr = Element::Initialize(0);
  2575. if (FAILED(hr))
  2576. return hr;
  2577. // Initialize
  2578. bool fCreateLayout = !_pvRowLayout;
  2579. if (fCreateLayout)
  2580. {
  2581. int ari[3] = { -1, 0, 3 };
  2582. hr = RowLayout::Create(3, ari, &_pvRowLayout);
  2583. if (FAILED(hr))
  2584. return hr;
  2585. }
  2586. Element* peName;
  2587. hr = Element::Create(AE_Inactive, &peName);
  2588. if (FAILED(hr))
  2589. return hr;
  2590. Button* peValue;
  2591. hr = Button::Create((Element**) &peValue);
  2592. if (FAILED(hr))
  2593. {
  2594. peName->Destroy();
  2595. return hr;
  2596. }
  2597. peValue->SetEnabled(false);
  2598. Add(peName);
  2599. Add(peValue);
  2600. SetValue(LayoutProp, PI_Local, _pvRowLayout);
  2601. SetLayoutPos(LP_None);
  2602. if (fCreateLayout)
  2603. {
  2604. // todo: need to track in propertychanged to know when it reaches null, which is
  2605. // when we need to set it to NULL
  2606. }
  2607. return S_OK;
  2608. }
  2609. ////////////////////////////////////////////////////////
  2610. // System events
  2611. #define ASI_Name 0
  2612. #define ASI_Value 1
  2613. Element* GetNthChild(Element *peRoot, UINT index)
  2614. {
  2615. Value* pvChildren;
  2616. ElementList* pel = peRoot->GetChildren(&pvChildren);
  2617. Element* pe = NULL;
  2618. if (pel && (pel->GetSize() > index))
  2619. pe = pel->GetItem(index);
  2620. pvChildren->Release();
  2621. return pe;
  2622. }
  2623. Element* ARPSupportItem::GetChild(UINT index)
  2624. {
  2625. return GetNthChild(this, index);
  2626. }
  2627. void ARPSupportItem::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  2628. {
  2629. int index = -1;
  2630. if (IsProp(AccName))
  2631. index = ASI_Name;
  2632. else if (IsProp(AccValue))
  2633. index = ASI_Value;
  2634. else if (IsProp(URL))
  2635. {
  2636. Element* pe = GetChild(ASI_Value);
  2637. if (pe)
  2638. {
  2639. if (pvNew && pvNew->GetString() && *(pvNew->GetString()))
  2640. pe->RemoveLocalValue(EnabledProp);
  2641. else
  2642. pe->SetEnabled(false);
  2643. }
  2644. }
  2645. if (index != -1)
  2646. {
  2647. Element* pe = GetChild(index);
  2648. if (index == ASI_Value)
  2649. {
  2650. // WARNING -- this code assumes you will not put a layoutpos on this element
  2651. // as this code toggles between LP_None and unset, ignoring any previous setting
  2652. // to the property -- verify this with Mark -- could be that this is local
  2653. // and the markup is specified? then there wouldn't be a problem
  2654. if (pvNew && pvNew->GetString() && *(pvNew->GetString()))
  2655. RemoveLocalValue(LayoutPosProp);
  2656. else
  2657. SetLayoutPos(LP_None);
  2658. }
  2659. if (pe)
  2660. pe->SetValue(ContentProp, PI_Local, pvNew);
  2661. }
  2662. Element::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  2663. }
  2664. ////////////////////////////////////////////////////////
  2665. // Generic eventing
  2666. void ARPSupportItem::OnEvent(Event* pEvent)
  2667. {
  2668. // Handle only bubbled generic events
  2669. if (pEvent->nStage == GMF_BUBBLED)
  2670. {
  2671. if (pEvent->uidType == Button::Click)
  2672. {
  2673. Value* pvURL;
  2674. LPCWSTR lpszURL = GetURL(&pvURL);
  2675. if (*lpszURL)
  2676. {
  2677. ShellExecuteW(NULL, NULL, lpszURL, NULL, NULL, SW_SHOWDEFAULT);
  2678. }
  2679. pvURL->Release();
  2680. pEvent->fHandled = true;
  2681. return;
  2682. }
  2683. }
  2684. Element::OnEvent(pEvent);
  2685. }
  2686. // URL property
  2687. static int vvURL[] = { DUIV_STRING, -1 }; StaticValuePtr(svDefaultURL, DUIV_STRING, (void*)L"");
  2688. static PropertyInfo impURLProp = { L"URL", PF_Normal|PF_Cascade, 0, vvURL, NULL, (Value*)&svDefaultURL };
  2689. PropertyInfo* ARPSupportItem::URLProp = &impURLProp;
  2690. ////////////////////////////////////////////////////////
  2691. // ClassInfo (must appear after property definitions)
  2692. // Class properties
  2693. static PropertyInfo* _aPI[] = {
  2694. ARPSupportItem::URLProp,
  2695. };
  2696. // Define class info with type and base type, set static class pointer
  2697. IClassInfo* ARPSupportItem::Class = NULL;
  2698. HRESULT ARPSupportItem::Register()
  2699. {
  2700. return ClassInfo<ARPSupportItem,Element>::Register(L"ARPSupportItem", _aPI, DUIARRAYSIZE(_aPI));
  2701. }
  2702. ////////////////////////////////////////////////////////
  2703. //
  2704. // ARPSelector
  2705. //
  2706. // A Selector whose children are all buttons. If the user clicks
  2707. // any of the buttons, that button automatically becomes the new
  2708. // selection.
  2709. // Define class info with type and base type, set static class pointer
  2710. HRESULT ARPSelector::Create(OUT Element** ppElement)
  2711. {
  2712. *ppElement = NULL;
  2713. ARPSelector* ps = HNew<ARPSelector>();
  2714. if (!ps)
  2715. return E_OUTOFMEMORY;
  2716. HRESULT hr = ps->Initialize();
  2717. if (FAILED(hr))
  2718. {
  2719. ps->Destroy();
  2720. return hr;
  2721. }
  2722. *ppElement = ps;
  2723. return S_OK;
  2724. }
  2725. ////////////////////////////////////////////////////////
  2726. // Generic eventing
  2727. HRESULT CALLBACK CollapseExpandosExceptCB(Expando* pex, LPARAM lParam)
  2728. {
  2729. if (pex != (Expando*)lParam)
  2730. {
  2731. pex->SetExpanded(false);
  2732. }
  2733. return S_OK;
  2734. }
  2735. void CALLBACK s_Repaint(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  2736. {
  2737. KillTimer(hwnd, idEvent);
  2738. ARPSelector* self = (ARPSelector*)idEvent;
  2739. Element* pe;
  2740. if (SUCCEEDED(Element::Create(0, &pe)))
  2741. {
  2742. pe->SetLayoutPos(BLP_Client);
  2743. if (SUCCEEDED(self->Add(pe)))
  2744. {
  2745. self->Remove(pe);
  2746. }
  2747. pe->Destroy();
  2748. }
  2749. }
  2750. void ARPSelector::OnEvent(Event* pEvent)
  2751. {
  2752. // Handle only bubbled generic events
  2753. if (pEvent->nStage == GMF_BUBBLED)
  2754. {
  2755. // Selection occurs only for Button::Click or Expando::Click events
  2756. if (pEvent->uidType == Button::Click ||
  2757. pEvent->uidType == Expando::Click)
  2758. {
  2759. pEvent->fHandled = true;
  2760. SetSelection(pEvent->peTarget);
  2761. // If it was a Click from an Expando, then unexpand all the
  2762. // other Expandos and expand this expando
  2763. if (pEvent->uidType == Expando::Click)
  2764. {
  2765. TraverseTree<Expando>(this, CollapseExpandosExceptCB, (LPARAM)pEvent->peTarget);
  2766. Expando* pex = (Expando*)pEvent->peTarget;
  2767. pex->SetExpanded(true);
  2768. // Hack for DUI painting weirdness
  2769. // After the animation is over, repaint ourselves
  2770. // to get rid of the detritus.
  2771. ARPFrame* paf = FindAncestorElement<ARPFrame>(this);
  2772. if (paf->GetHostWindow())
  2773. {
  2774. SetTimer(paf->GetHostWindow(),
  2775. (UINT_PTR)this,
  2776. paf->GetAnimationTime(), s_Repaint);
  2777. }
  2778. }
  2779. return;
  2780. }
  2781. }
  2782. Selector::OnEvent(pEvent);
  2783. }
  2784. // If we are not the option list, bypass Selector::GetAdjacent because
  2785. // Selector navigates from the selected element but we want to navigate
  2786. // from the focus element because the focus element has interesting
  2787. // subelements...
  2788. Element *ARPSelector::GetAdjacent(Element *peFrom, int iNavDir, NavReference const *pnr, bool bKeyable)
  2789. {
  2790. if (GetID() == ARPFrame::_idOptionList)
  2791. {
  2792. // Let the option list navigate normally
  2793. return Selector::GetAdjacent(peFrom, iNavDir, pnr, bKeyable);
  2794. }
  2795. else
  2796. {
  2797. // All other selectors navigate from selection
  2798. return Element::GetAdjacent(peFrom, iNavDir, pnr, bKeyable);
  2799. }
  2800. }
  2801. IClassInfo* ARPSelector::Class = NULL;
  2802. HRESULT ARPSelector::Register()
  2803. {
  2804. return ClassInfo<ARPSelector,Selector>::Register(L"ARPSelector", NULL, 0);
  2805. }
  2806. ////////////////////////////////////////////////////////
  2807. //
  2808. // CLIENTINFO
  2809. //
  2810. // Tracks information about a specific client.
  2811. //
  2812. bool CLIENTINFO::GetInstallFile(HKEY hkInfo, LPCTSTR pszValue, LPTSTR pszBuf, UINT cchBuf, bool fFile)
  2813. {
  2814. DWORD dwType;
  2815. DWORD cb = cchBuf * sizeof(TCHAR);
  2816. if (SHQueryValueEx(hkInfo, pszValue, NULL, &dwType, pszBuf, &cb) != ERROR_SUCCESS ||
  2817. dwType != REG_SZ)
  2818. {
  2819. // If a file, then failure is okay (it means nothing to verify)
  2820. return fFile;
  2821. }
  2822. TCHAR szBuf[MAX_PATH];
  2823. lstrcpyn(szBuf, pszBuf, DUIARRAYSIZE(szBuf));
  2824. if (!fFile)
  2825. {
  2826. // Now validate that the program exists
  2827. PathRemoveArgs(szBuf);
  2828. PathUnquoteSpaces(szBuf);
  2829. }
  2830. // Must be fully-qualified
  2831. if (PathIsRelative(szBuf))
  2832. {
  2833. return false;
  2834. }
  2835. // File must exist, but don't hit the network to validate it
  2836. if (!PathIsNetworkPath(szBuf) &&
  2837. !PathFileExists(szBuf))
  2838. {
  2839. return false;
  2840. }
  2841. return true;
  2842. }
  2843. bool CLIENTINFO::GetInstallCommand(HKEY hkInfo, LPCTSTR pszValue, LPTSTR pszBuf, UINT cchBuf)
  2844. {
  2845. return GetInstallFile(hkInfo, pszValue, pszBuf, cchBuf, FALSE);
  2846. }
  2847. LONG RegQueryDWORD(HKEY hk, LPCTSTR pszValue, DWORD* pdwOut)
  2848. {
  2849. DWORD dwType;
  2850. DWORD cb = sizeof(*pdwOut);
  2851. LONG lRc = RegQueryValueEx(hk, pszValue, NULL, &dwType, (LPBYTE)pdwOut, &cb);
  2852. if (lRc == ERROR_SUCCESS && dwType != REG_DWORD)
  2853. {
  2854. lRc = ERROR_INVALID_DATA;
  2855. }
  2856. return lRc;
  2857. }
  2858. //
  2859. // hkInfo = NULL means that pzsKey is actually the friendlyname for
  2860. // "keep this item"
  2861. //
  2862. bool CLIENTINFO::Initialize(HKEY hkApp, HKEY hkInfo, LPCWSTR pszKey)
  2863. {
  2864. LPCWSTR pszName;
  2865. WCHAR szBuf[MAX_PATH];
  2866. DUIAssertNoMsg(_tOEMShown == TRIBIT_UNDEFINED);
  2867. if (hkInfo)
  2868. {
  2869. _pszKey = StrDupW(pszKey);
  2870. if (!_pszKey) return false;
  2871. // Program must have properly registered IconsVisible status
  2872. DWORD dwValue;
  2873. if (RegQueryDWORD(hkInfo, TEXT("IconsVisible"), &dwValue) != ERROR_SUCCESS)
  2874. {
  2875. return false;
  2876. }
  2877. // If there is a VerifyFile, the file must exist
  2878. if (!GetInstallFile(hkInfo, TEXT("VerifyFile"), szBuf, DUIARRAYSIZE(szBuf), TRUE))
  2879. {
  2880. return false;
  2881. }
  2882. _bShown = BOOLIFY(dwValue);
  2883. // Program must have properly registered Reinstall, HideIcons and ShowIcons commands
  2884. if (!GetInstallCommand(hkInfo, TEXT("ReinstallCommand"), szBuf, DUIARRAYSIZE(szBuf)) ||
  2885. !GetInstallCommand(hkInfo, TEXT("HideIconsCommand"), szBuf, DUIARRAYSIZE(szBuf)) ||
  2886. !GetInstallCommand(hkInfo, TEXT("ShowIconsCommand"), szBuf, DUIARRAYSIZE(szBuf)))
  2887. {
  2888. return false;
  2889. }
  2890. // Get the OEM's desired hide/show setting for this app, if any
  2891. if (RegQueryDWORD(hkInfo, TEXT("OEMShowIcons"), &dwValue) == ERROR_SUCCESS)
  2892. {
  2893. _tOEMShown = dwValue ? TRIBIT_TRUE : TRIBIT_FALSE;
  2894. }
  2895. // See if this is the OEM's default client
  2896. if (RegQueryDWORD(hkInfo, TEXT("OEMDefault"), &dwValue) == ERROR_SUCCESS &&
  2897. dwValue != 0)
  2898. {
  2899. _bOEMDefault = BOOLIFY(dwValue);
  2900. }
  2901. SHLoadLegacyRegUIStringW(hkApp, NULL, szBuf, ARRAYSIZE(szBuf));
  2902. if (!szBuf[0]) return false;
  2903. pszName = szBuf;
  2904. }
  2905. else
  2906. {
  2907. pszName = pszKey;
  2908. }
  2909. _pszName = StrDupW(pszName);
  2910. if (!_pszName) return false;
  2911. return true;
  2912. }
  2913. CLIENTINFO* CLIENTINFO::Create(HKEY hkApp, HKEY hkInfo, LPCWSTR pszKey)
  2914. {
  2915. CLIENTINFO* pci = HNewAndZero<CLIENTINFO>();
  2916. if (pci)
  2917. {
  2918. if (!pci->Initialize(hkApp, hkInfo, pszKey))
  2919. {
  2920. pci->Delete();
  2921. pci = NULL;
  2922. }
  2923. }
  2924. return pci;
  2925. }
  2926. CLIENTINFO::~CLIENTINFO()
  2927. {
  2928. LocalFree(_pszKey);
  2929. LocalFree(_pszName);
  2930. if (_pvMSName)
  2931. {
  2932. _pvMSName->Release();
  2933. }
  2934. }
  2935. int CLIENTINFO::QSortCMP(const void* p1, const void* p2)
  2936. {
  2937. CLIENTINFO* pci1 = *(CLIENTINFO**)p1;
  2938. CLIENTINFO* pci2 = *(CLIENTINFO**)p2;
  2939. return lstrcmpi(pci1->_pszName, pci2->_pszName);
  2940. }
  2941. ////////////////////////////////////////////////////////
  2942. //
  2943. // StringList
  2944. //
  2945. // A list of strings. The buffer for all the strings is allocated
  2946. // in _pszBuf; the DynamicArray contains pointers into that buffer.
  2947. //
  2948. void StringList::Reset()
  2949. {
  2950. if (_pdaStrings)
  2951. {
  2952. _pdaStrings->Destroy();
  2953. _pdaStrings = NULL;
  2954. }
  2955. LocalFree(_pszBuf);
  2956. _pszBuf = NULL;
  2957. }
  2958. // pszInit is a semicolon-separated list
  2959. HRESULT StringList::SetStringList(LPCTSTR pszInit)
  2960. {
  2961. HRESULT hr;
  2962. Reset();
  2963. if (!pszInit)
  2964. {
  2965. hr = S_OK; // empty list
  2966. }
  2967. else if (SUCCEEDED(hr = DynamicArray<LPTSTR>::Create(0, false, &_pdaStrings)))
  2968. {
  2969. _pszBuf = StrDup(pszInit);
  2970. if (_pszBuf)
  2971. {
  2972. LPTSTR psz = _pszBuf;
  2973. hr = S_OK;
  2974. while (SUCCEEDED(hr) && psz && *psz)
  2975. {
  2976. LPTSTR pszT = StrChr(psz, L';');
  2977. if (pszT)
  2978. {
  2979. *pszT++ = L'\0';
  2980. }
  2981. hr = _pdaStrings->Add(psz);
  2982. psz = pszT;
  2983. }
  2984. }
  2985. else
  2986. {
  2987. hr = E_OUTOFMEMORY;
  2988. }
  2989. }
  2990. return hr;
  2991. }
  2992. bool StringList::IsStringInList(LPCTSTR pszFind)
  2993. {
  2994. if (_pdaStrings)
  2995. {
  2996. for (UINT i = 0; i < _pdaStrings->GetSize(); i++)
  2997. {
  2998. if (AreEnglishStringsEqual(_pdaStrings->GetItem(i), pszFind))
  2999. {
  3000. return true;
  3001. }
  3002. }
  3003. }
  3004. return false;
  3005. }
  3006. ////////////////////////////////////////////////////////
  3007. //
  3008. // ClientPicker
  3009. //
  3010. // An element which manages a list of registered clients.
  3011. //
  3012. // If there is only one item in the list, then the element is static.
  3013. // Otherwise, the element hosts a combo box.
  3014. //
  3015. // The clienttype attribute is the name of the registry key under Clients.
  3016. //
  3017. HRESULT ClientPicker::Create(OUT Element** ppElement)
  3018. {
  3019. *ppElement = NULL;
  3020. ClientPicker* pcc = HNewAndZero<ClientPicker>();
  3021. if (!pcc)
  3022. return E_OUTOFMEMORY;
  3023. HRESULT hr = pcc->Initialize();
  3024. if (FAILED(hr))
  3025. {
  3026. pcc->Destroy();
  3027. return hr;
  3028. }
  3029. *ppElement = pcc;
  3030. return S_OK;
  3031. };
  3032. HRESULT ClientPicker::Initialize()
  3033. {
  3034. HRESULT hr;
  3035. // Initialize base
  3036. hr = super::Initialize(0); // Normal display node creation
  3037. if (FAILED(hr))
  3038. return hr;
  3039. // Initialize members
  3040. hr = DynamicArray<CLIENTINFO*>::Create(0, false, &_pdaClients);
  3041. if (FAILED(hr))
  3042. return hr;
  3043. hr = Element::Create(0, &_peStatic);
  3044. if (FAILED(hr))
  3045. return hr;
  3046. if (FAILED(hr = _peStatic->SetClass(L"clientstatic")) ||
  3047. FAILED(hr = Add(_peStatic)))
  3048. {
  3049. _peStatic->Destroy();
  3050. return hr;
  3051. }
  3052. _peStatic->SetAccessible(true);
  3053. _peStatic->SetAccRole(ROLE_SYSTEM_STATICTEXT);
  3054. hr = Combobox::Create((Element**)&_peCombo);
  3055. if (FAILED(hr))
  3056. return hr;
  3057. if (FAILED(hr = Add(_peCombo)) ||
  3058. FAILED(hr = _peCombo->SetVisible(false)))
  3059. {
  3060. _peCombo->Destroy();
  3061. return hr;
  3062. }
  3063. // JeffBog says I should mess with the width here
  3064. SetWidth(10);
  3065. return S_OK;
  3066. }
  3067. ClientPicker::~ClientPicker()
  3068. {
  3069. _CancelDelayShowCombo();
  3070. if (_pdaClients)
  3071. {
  3072. _pdaClients->Destroy();
  3073. }
  3074. }
  3075. void ClientPicker::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  3076. {
  3077. super::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  3078. // Since UIActive = Selected && ParentEnabled, we need to call
  3079. // _SyncUIActive if either property changes.
  3080. if (IsProp(Selected))
  3081. {
  3082. // Change in selection may require us to block or unblock the OK button.
  3083. _CheckBlockOK(pvNew->GetBool());
  3084. _SyncUIActive();
  3085. }
  3086. else if (IsProp(ParentExpanded))
  3087. {
  3088. _SyncUIActive();
  3089. }
  3090. }
  3091. // To keep accessibility happy, we reflect content in the AccName.
  3092. void _SetStaticTextAndAccName(Element* pe, Value* pv)
  3093. {
  3094. pe->SetValue(Element::ContentProp, PI_Local, pv);
  3095. pe->SetValue(Element::AccNameProp, PI_Local, pv);
  3096. }
  3097. void _SetStaticTextAndAccName(Element* pe, LPCWSTR pszText)
  3098. {
  3099. Value* pv = Value::CreateString(pszText);
  3100. _SetStaticTextAndAccName(pe, pv);
  3101. pv->Release();
  3102. }
  3103. //
  3104. // When UI Active, show the combo box.
  3105. // When not UI Active, hide our combo box so animation doesn't tube it.
  3106. //
  3107. void ClientPicker::_SyncUIActive()
  3108. {
  3109. ARPFrame* paf = FindAncestorElement<ARPFrame>(this);
  3110. bool bUIActive = GetSelected() && GetParentExpanded();
  3111. if (_bUIActive != bUIActive)
  3112. {
  3113. _bUIActive = bUIActive;
  3114. if (_bUIActive)
  3115. {
  3116. // Normally we would just _peCombo->SetVisible(_NeedsCombo())
  3117. // and go home. Unfortunately, DirectUI gets confused if a
  3118. // combo box moves around, so we have to change the visibility
  3119. // after the world has gone quiet
  3120. _hwndHost = paf->GetHostWindow();
  3121. if (_hwndHost)
  3122. {
  3123. SetTimer(_hwndHost,
  3124. (UINT_PTR)this,
  3125. paf->GetAnimationTime(), s_DelayShowCombo);
  3126. }
  3127. }
  3128. else
  3129. {
  3130. // Inactive - copy current combo selection to static
  3131. // and hide the combo
  3132. UINT iSel = _peCombo->GetSelection();
  3133. if (iSel < GetClientList()->GetSize())
  3134. {
  3135. _SetStaticTextAndAccName(_peStatic, GetClientList()->GetItem(iSel)->GetFilteredName(GetFilter()));
  3136. }
  3137. _peCombo->SetVisible(false);
  3138. _peStatic->SetVisible(true);
  3139. _CancelDelayShowCombo();
  3140. }
  3141. }
  3142. }
  3143. void ClientPicker::_DelayShowCombo()
  3144. {
  3145. // Tell DirectUI to let the combo participate in layout again
  3146. bool bNeedsCombo = _NeedsCombo();
  3147. _peCombo->SetVisible(bNeedsCombo);
  3148. _peStatic->SetVisible(!bNeedsCombo);
  3149. // Force a relayout by shrinking the combo box a teensy bit, then
  3150. // returning it to normal size. This cannot be done inside a
  3151. // Defer because that ends up optimizing out the relayout.
  3152. _peCombo->SetWidth(_peCombo->GetWidth()-1);
  3153. _peCombo->RemoveLocalValue(WidthProp);
  3154. if (!_bFilledCombo)
  3155. {
  3156. _bFilledCombo = true;
  3157. SendMessage(_peCombo->GetHWND(), CB_RESETCONTENT, 0, 0);
  3158. for (UINT i = 0; i < GetClientList()->GetSize(); i++)
  3159. {
  3160. _peCombo->AddString(GetClientList()->GetItem(i)->GetFilteredName(GetFilter()));
  3161. }
  3162. _peCombo->SetSelection(0);
  3163. }
  3164. }
  3165. // If the user picked "Choose from list" and we are selected,
  3166. // then block OK since the user actually needs to choose something.
  3167. void ClientPicker::_CheckBlockOK(bool bSelected)
  3168. {
  3169. ARPFrame* paf = FindAncestorElement<ARPFrame>(this);
  3170. CLIENTINFO* pci = GetSelectedClient();
  3171. if (pci)
  3172. {
  3173. if (bSelected && pci->IsPickFromList())
  3174. {
  3175. if (!_bBlockedOK)
  3176. {
  3177. _bBlockedOK = true;
  3178. paf->BlockOKButton();
  3179. }
  3180. }
  3181. else
  3182. {
  3183. if (_bBlockedOK)
  3184. {
  3185. _bBlockedOK = false;
  3186. paf->UnblockOKButton();
  3187. }
  3188. }
  3189. }
  3190. }
  3191. void ClientPicker::s_DelayShowCombo(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  3192. {
  3193. KillTimer(hwnd, idEvent);
  3194. ClientPicker* self = (ClientPicker*)idEvent;
  3195. self->_DelayShowCombo();
  3196. }
  3197. void ClientPicker::_CancelDelayShowCombo()
  3198. {
  3199. if (_hwndHost)
  3200. {
  3201. KillTimer(_hwndHost, (UINT_PTR)this);
  3202. _hwndHost = NULL;
  3203. }
  3204. }
  3205. void ClientPicker::OnEvent(Event* pEvent)
  3206. {
  3207. // Handle only bubbled generic events
  3208. if (pEvent->nStage == GMF_BUBBLED)
  3209. {
  3210. // If the selection changed, then see if it's a change
  3211. // that should block the OK button.
  3212. if (pEvent->uidType == Combobox::SelectionChange)
  3213. {
  3214. _CheckBlockOK(GetSelected());
  3215. }
  3216. }
  3217. super::OnEvent(pEvent);
  3218. }
  3219. //
  3220. // CLIENTFILTER_OEM - add one if marked OEM, else "Keep unchanged"
  3221. // CLIENTFILTER_MS - add any that are marked MS, else "Keep unchanged"
  3222. // CLIENTFILTER_NONMS - add any that are not marked MS, else "Keep unchanged"
  3223. // furthermore, if more than one non-MS, then
  3224. // add and select "Choose from list"
  3225. //
  3226. // On success, returns the number of items added
  3227. // (not counting "Keep unchanged" / "Choose from list")
  3228. //
  3229. HRESULT ClientPicker::SetFilter(CLIENTFILTER cf, ARPFrame* paf)
  3230. {
  3231. HRESULT hr = E_FAIL;
  3232. DUIAssert(_cf == 0, "SetFilter called more than once");
  3233. _cf = cf;
  3234. _bEmpty = true;
  3235. _bFilledCombo = false;
  3236. Value* pv;
  3237. LPWSTR pszType = GetClientTypeString(&pv);
  3238. if (pszType)
  3239. {
  3240. _pcb = paf->FindClientBlock(pszType);
  3241. if (_pcb)
  3242. {
  3243. hr = _pcb->InitializeClientPicker(this);
  3244. }
  3245. }
  3246. pv->Release();
  3247. // The static element gets the first item in the list
  3248. if (SUCCEEDED(hr) && GetClientList()->GetSize())
  3249. {
  3250. _SetStaticTextAndAccName(_peStatic, GetClientList()->GetItem(0)->_pszName);
  3251. }
  3252. if (SUCCEEDED(hr))
  3253. {
  3254. CalculateWidth();
  3255. _SyncUIActive();
  3256. }
  3257. return hr;
  3258. }
  3259. // Set our width to the width of the longest string in our combo box.
  3260. // Combo boxes don't do this themselves, so they need our help. We have
  3261. // to set the width on ourselves and not on the combobox because
  3262. // RowLayout will change the width of the combobox and HWNDHost will
  3263. // treat the HWND width as authoritative, overwriting the combobox width
  3264. // we had set.
  3265. void ClientPicker::CalculateWidth()
  3266. {
  3267. HWND hwndCombo = _peCombo->GetHWND();
  3268. HDC hdc = GetDC(hwndCombo);
  3269. if (hdc)
  3270. {
  3271. HFONT hfPrev = SelectFont(hdc, GetWindowFont(hwndCombo));
  3272. int cxMax = 0;
  3273. SIZE siz;
  3274. for (UINT i = 0; i < GetClientList()->GetSize(); i++)
  3275. {
  3276. LPCTSTR pszName = GetClientList()->GetItem(i)->GetFilteredName(GetFilter());
  3277. if (GetTextExtentPoint(hdc, pszName, lstrlen(pszName), &siz) &&
  3278. cxMax < siz.cx)
  3279. {
  3280. cxMax = siz.cx;
  3281. }
  3282. }
  3283. SelectFont(hdc, hfPrev);
  3284. ReleaseDC(hwndCombo, hdc);
  3285. // Add in the borders that USER adds to the combo box.
  3286. // Unfortunately, we get called when the combo box has been
  3287. // squished to zero width, so GetComboBoxInfo is of no use.
  3288. // We have to replicate the computations.
  3289. //
  3290. // The client space is arranged horizontally like so:
  3291. //
  3292. // SM_CXFIXEDFRAME
  3293. // v v
  3294. // | | edit | | |
  3295. // ^
  3296. // SM_CXVSCROLL
  3297. RECT rc = { 0, 0, cxMax, 0 };
  3298. rc.right += 2 * GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CXVSCROLL);
  3299. rc.right += GetSystemMetrics(SM_CXEDGE); // extra edge for Hebrew/Arabic
  3300. AdjustWindowRect(&rc, GetWindowStyle(hwndCombo), FALSE);
  3301. SetWidth(rc.right - rc.left);
  3302. }
  3303. }
  3304. HRESULT ClientPicker::TransferToCustom()
  3305. {
  3306. HRESULT hr = E_FAIL;
  3307. if (_pcb)
  3308. {
  3309. hr = _pcb->TransferFromClientPicker(this);
  3310. }
  3311. return hr;
  3312. }
  3313. CLIENTINFO* ClientPicker::GetSelectedClient()
  3314. {
  3315. if (_peCombo)
  3316. {
  3317. UINT iSel = _peCombo->GetSelection();
  3318. if (iSel < GetClientList()->GetSize())
  3319. {
  3320. return GetClientList()->GetItem(iSel);
  3321. }
  3322. }
  3323. return NULL;
  3324. }
  3325. ////////////////////////////////////////////////////////
  3326. // Property definitions
  3327. /** Property template (replace !!!), also update private PropertyInfo* parray and class header (element.h)
  3328. // !!! property
  3329. static int vv!!![] = { DUIV_INT, -1 }; StaticValue(svDefault!!!, DUIV_INT, 0);
  3330. static PropertyInfo imp!!!Prop = { L"!!!", PF_Normal, 0, vv!!!, (Value*)&svDefault!!! };
  3331. PropertyInfo* Element::!!!Prop = &imp!!!Prop;
  3332. **/
  3333. // ClientType property
  3334. static int vvCCClientType[] = { DUIV_STRING, -1 };
  3335. static PropertyInfo impCCClientTypeProp = { L"ClientType", PF_Normal, 0, vvCCClientType, NULL, Value::pvStringNull };
  3336. PropertyInfo* ClientPicker::ClientTypeProp = &impCCClientTypeProp;
  3337. // ParentExpanded property
  3338. static int vvParentExpanded[] = { DUIV_BOOL, -1 };
  3339. static PropertyInfo impParentExpandedProp = { L"parentexpanded", PF_Normal, 0, vvParentExpanded, NULL, Value::pvBoolFalse };
  3340. PropertyInfo* ClientPicker::ParentExpandedProp = &impParentExpandedProp;
  3341. ////////////////////////////////////////////////////////
  3342. // ClassInfo (must appear after property definitions)
  3343. // Class properties
  3344. PropertyInfo* _aClientPickerPI[] = {
  3345. ClientPicker::ClientTypeProp,
  3346. ClientPicker::ParentExpandedProp,
  3347. };
  3348. // Define class info with type and base type, set static class pointer
  3349. IClassInfo* ClientPicker::Class = NULL;
  3350. HRESULT ClientPicker::Register()
  3351. {
  3352. return ClassInfo<ClientPicker,super>::Register(L"clientpicker", _aClientPickerPI, DUIARRAYSIZE(_aClientPickerPI));
  3353. }
  3354. ////////////////////////////////////////////////////////
  3355. // ARP Parser
  3356. HRESULT ARPParser::Create(ARPFrame* paf, UINT uRCID, HINSTANCE hInst, PPARSEERRORCB pfnErrorCB, OUT Parser** ppParser)
  3357. {
  3358. *ppParser = NULL;
  3359. ARPParser* ap = HNew<ARPParser>();
  3360. if (!ap)
  3361. return E_OUTOFMEMORY;
  3362. HRESULT hr = ap->Initialize(paf, uRCID, hInst, pfnErrorCB);
  3363. if (FAILED(hr))
  3364. {
  3365. ap->Destroy();
  3366. return hr;
  3367. }
  3368. *ppParser = ap;
  3369. return S_OK;
  3370. }
  3371. HRESULT ARPParser::Initialize(ARPFrame* paf, UINT uRCID, HINSTANCE hInst, PPARSEERRORCB pfnErrorCB)
  3372. {
  3373. _paf = paf;
  3374. return Parser::Initialize(uRCID, hInst, pfnErrorCB);
  3375. }
  3376. Value* ARPParser::GetSheet(LPCWSTR pszResID)
  3377. {
  3378. // All style sheet mappings go through here. Redirect sheet queries to appropriate
  3379. // style sheets (i.e. themed or standard look). _pParserStyle points to the
  3380. // appropriate stylesheet-only Parser instance
  3381. return _paf->GetStyleParser()->GetSheet(pszResID);
  3382. }
  3383. ////////////////////////////////////////////////////////
  3384. //
  3385. // AutoButton
  3386. //
  3387. // A button that does a bunch of stuff that USER does automagically,
  3388. // if it were a regular button control.
  3389. //
  3390. // - Automatically updates its own accessibility state and action
  3391. // - If a checkbox, autotoggles on click
  3392. HRESULT AutoButton::Create(OUT Element** ppElement)
  3393. {
  3394. *ppElement = NULL;
  3395. AutoButton* pb = HNew<AutoButton>();
  3396. if (!pb)
  3397. return E_OUTOFMEMORY;
  3398. HRESULT hr = pb->Initialize(AE_MouseAndKeyboard);
  3399. if (FAILED(hr))
  3400. {
  3401. pb->Destroy();
  3402. return hr;
  3403. }
  3404. *ppElement = pb;
  3405. return S_OK;
  3406. }
  3407. void AutoButton::OnEvent(Event* pev)
  3408. {
  3409. // Checkboxes auto-toggle on click
  3410. if (pev->nStage == GMF_DIRECT &&
  3411. pev->uidType == Button::Click &&
  3412. GetAccRole() == ROLE_SYSTEM_CHECKBUTTON)
  3413. {
  3414. pev->fHandled = true;
  3415. // Toggle the selected state
  3416. SetSelected(!GetSelected());
  3417. }
  3418. super::OnEvent(pev);
  3419. }
  3420. //
  3421. // Reflect the selected state to accessibility.
  3422. //
  3423. void AutoButton::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  3424. {
  3425. super::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  3426. if (IsProp(Selected))
  3427. {
  3428. int state = GetAccState();
  3429. if (GetAccRole() == ROLE_SYSTEM_OUTLINEBUTTON)
  3430. {
  3431. // Outline buttons expose Selection as expanded/collapsed
  3432. state &= ~(STATE_SYSTEM_EXPANDED | STATE_SYSTEM_COLLAPSED);
  3433. if (pvNew->GetBool())
  3434. {
  3435. state |= STATE_SYSTEM_EXPANDED;
  3436. }
  3437. else
  3438. {
  3439. state |= STATE_SYSTEM_COLLAPSED;
  3440. }
  3441. }
  3442. else
  3443. {
  3444. // Radio buttons and checkboxes expose Selection as checked/unchecked
  3445. if (pvNew->GetBool())
  3446. {
  3447. state |= STATE_SYSTEM_CHECKED;
  3448. }
  3449. else
  3450. {
  3451. state &= ~STATE_SYSTEM_CHECKED;
  3452. }
  3453. }
  3454. SetAccState(state);
  3455. SyncDefAction();
  3456. }
  3457. else if (IsProp(AccRole))
  3458. {
  3459. SyncDefAction();
  3460. }
  3461. }
  3462. //
  3463. // Role strings from oleacc. They are biased by 1100 since that is
  3464. // where roles begin.
  3465. //
  3466. #define OLEACCROLE_EXPAND (305-1100)
  3467. #define OLEACCROLE_COLLAPSE (306-1100)
  3468. #define OLEACCROLE_CHECK (309-1100)
  3469. #define OLEACCROLE_UNCHECK (310-1100)
  3470. // Default action is "Check" if a radio button or an unchecked
  3471. // checkbox. Default action is "Uncheck" if an unchecked checkbox.
  3472. void AutoButton::SyncDefAction()
  3473. {
  3474. UINT idsAction;
  3475. switch (GetAccRole())
  3476. {
  3477. // Checkbuttons will check or uncheck depending on state
  3478. case ROLE_SYSTEM_CHECKBUTTON:
  3479. idsAction = (GetAccState() & STATE_SYSTEM_CHECKED) ?
  3480. OLEACCROLE_UNCHECK :
  3481. OLEACCROLE_CHECK;
  3482. break;
  3483. // Radiobutton always checks.
  3484. case ROLE_SYSTEM_RADIOBUTTON:
  3485. idsAction = OLEACCROLE_CHECK;
  3486. break;
  3487. // Expando button expands or collapses.
  3488. case ROLE_SYSTEM_OUTLINEBUTTON:
  3489. idsAction = (GetAccState() & STATE_SYSTEM_EXPANDED) ?
  3490. OLEACCROLE_COLLAPSE :
  3491. OLEACCROLE_EXPAND;
  3492. break;
  3493. default:
  3494. DUIAssert(0, "Unknown AccRole");
  3495. return;
  3496. }
  3497. SetDefAction(this, idsAction);
  3498. }
  3499. ////////////////////////////////////////////////////////
  3500. // ClassInfo (must appear after property definitions)
  3501. // Define class info with type and base type, set static class pointer
  3502. IClassInfo* AutoButton::Class = NULL;
  3503. HRESULT AutoButton::Register()
  3504. {
  3505. return ClassInfo<AutoButton,super>::Register(L"AutoButton", NULL, 0);
  3506. }
  3507. ////////////////////////////////////////////////////////
  3508. // ClientBlock class
  3509. //
  3510. // Manages a block of elements which expose all the clients registered
  3511. // to a particular client category.
  3512. HRESULT ClientBlock::Create(OUT Element** ppElement)
  3513. {
  3514. *ppElement = NULL;
  3515. ClientBlock* pcb = HNewAndZero<ClientBlock>();
  3516. if (!pcb)
  3517. return E_OUTOFMEMORY;
  3518. HRESULT hr = pcb->Initialize();
  3519. if (FAILED(hr))
  3520. {
  3521. pcb->Destroy();
  3522. return hr;
  3523. }
  3524. *ppElement = pcb;
  3525. return S_OK;
  3526. }
  3527. HRESULT ClientBlock::Initialize()
  3528. {
  3529. HRESULT hr;
  3530. // Initialize base
  3531. hr = super::Initialize(0); // Normal display node creation
  3532. if (FAILED(hr))
  3533. return hr;
  3534. // Initialize members
  3535. hr = DynamicArray<CLIENTINFO*>::Create(0, false, &_pdaClients);
  3536. if (FAILED(hr))
  3537. return hr;
  3538. return S_OK;
  3539. }
  3540. ClientBlock::~ClientBlock()
  3541. {
  3542. if (_pdaClients)
  3543. {
  3544. for (UINT i = 0; i < _pdaClients->GetSize(); i++)
  3545. {
  3546. _pdaClients->GetItem(i)->Delete();
  3547. }
  3548. _pdaClients->Destroy();
  3549. }
  3550. }
  3551. //
  3552. // If the user clicks a new default application, force it to be checked
  3553. // and disable it so it cannot be unchecked. Also re-enable the old one.
  3554. //
  3555. void ClientBlock::OnEvent(Event* pev)
  3556. {
  3557. if (pev->nStage == GMF_BUBBLED &&
  3558. pev->uidType == Selector::SelectionChange)
  3559. {
  3560. SelectionChangeEvent* sce = (SelectionChangeEvent*)pev;
  3561. // Re-enable the previous guy, if any
  3562. _EnableShowCheckbox(sce->peOld, true);
  3563. // Disable the new guy, if any
  3564. _EnableShowCheckbox(sce->peNew, false);
  3565. }
  3566. super::OnEvent(pev);
  3567. }
  3568. void ClientBlock::_EnableShowCheckbox(Element* peRadio, bool fEnable)
  3569. {
  3570. if (peRadio)
  3571. {
  3572. Element* peRow = peRadio->GetParent();
  3573. if (peRow)
  3574. {
  3575. Element* peShow = MaybeFindDescendentByName(peRow, L"show");
  3576. if (peShow)
  3577. {
  3578. peShow->SetEnabled(fEnable);
  3579. peShow->SetSelected(true); // force checked
  3580. // HACKHACK - DUI doesn't realize that the checkbox needs
  3581. // to be repainted so I have to kick it.
  3582. InvalidateGadget(peShow->GetDisplayNode());
  3583. }
  3584. }
  3585. }
  3586. }
  3587. //
  3588. // ClientBlock initialization / apply methods...
  3589. //
  3590. HKEY ClientBlock::_OpenClientKey(HKEY hkRoot, DWORD dwAccess)
  3591. {
  3592. HKEY hkClient = NULL;
  3593. Value *pv;
  3594. LPCWSTR pszClient = GetClientTypeString(&pv);
  3595. if (pszClient)
  3596. {
  3597. WCHAR szBuf[MAX_PATH];
  3598. wnsprintfW(szBuf, ARRAYSIZE(szBuf), TEXT("Software\\Clients\\%s"),
  3599. pszClient);
  3600. RegOpenKeyExW(hkRoot, szBuf, 0, dwAccess, &hkClient);
  3601. pv->Release();
  3602. }
  3603. return hkClient;
  3604. }
  3605. bool ClientBlock::_GetDefaultClient(HKEY hkClient, HKEY hkRoot, LPTSTR pszBuf, LONG cchBuf)
  3606. {
  3607. bool bResult = false;
  3608. HKEY hk = _OpenClientKey(hkRoot);
  3609. if (hk)
  3610. {
  3611. DWORD cbSize = cchBuf * sizeof(*pszBuf);
  3612. DWORD dwType;
  3613. // Client must be defined, be of type REG_SZ, be non-NULL, and have
  3614. // a corresponding entry in HKLM\Software\Clients. RegQueryValue
  3615. // is a handy abbreviatio for RegQueryKeyExists.
  3616. LONG l;
  3617. if (SHGetValue(hk, NULL, NULL, &dwType, pszBuf, &cbSize) == ERROR_SUCCESS &&
  3618. dwType == REG_SZ && pszBuf[0] &&
  3619. RegQueryValue(hkClient, pszBuf, NULL, &l) == ERROR_SUCCESS)
  3620. {
  3621. bResult = true;
  3622. }
  3623. RegCloseKey(hk);
  3624. }
  3625. return bResult;
  3626. }
  3627. // Determines whether the current client is a Microsoft client different
  3628. // from the Windows default client. Usually, this is when the current
  3629. // client is Outlook but the Windows default client is Outlook Express.
  3630. bool ClientBlock::_IsCurrentClientNonWindowsMS()
  3631. {
  3632. bool bResult = false;
  3633. HKEY hkClient = _OpenClientKey();
  3634. if (hkClient)
  3635. {
  3636. TCHAR szClient[MAX_PATH];
  3637. if (_GetDefaultClient(hkClient, HKEY_CURRENT_USER, szClient, ARRAYSIZE(szClient)) ||
  3638. _GetDefaultClient(hkClient, HKEY_LOCAL_MACHINE, szClient, ARRAYSIZE(szClient)))
  3639. {
  3640. // Is it a Microsoft client that isn't the Windows default?
  3641. if (_GetClientTier(szClient) == CBT_MS)
  3642. {
  3643. bResult = true;
  3644. }
  3645. }
  3646. RegCloseKey(hkClient);
  3647. }
  3648. return bResult;
  3649. }
  3650. //
  3651. // Called after the entire tree has been parsed and hosted.
  3652. // (Sort of like readystatecomplete.)
  3653. //
  3654. HRESULT ClientBlock::ParseCompleted(ARPFrame *paf)
  3655. {
  3656. HRESULT hr = S_OK;
  3657. Value* pv;
  3658. hr = _slOtherMSClients.SetStringList(GetOtherMSClientsString(&pv));
  3659. pv->Release();
  3660. if (SUCCEEDED(hr))
  3661. {
  3662. hr = paf->CreateElement(L"clientblockselector", NULL, (Element**)&_peSel);
  3663. if (SUCCEEDED(hr))
  3664. {
  3665. hr = Add(_peSel);
  3666. if (SUCCEEDED(hr))
  3667. {
  3668. // Failure to open the client key is not fatal; it just means that
  3669. // there are vacuously no clients.
  3670. HKEY hkClient = _OpenClientKey();
  3671. if (hkClient)
  3672. {
  3673. // Enumerate each app under the client key and look for those which
  3674. // have a "InstallInfo" subkey.
  3675. TCHAR szKey[MAX_PATH];
  3676. for (DWORD dwIndex = 0;
  3677. SUCCEEDED(hr) &&
  3678. RegEnumKey(hkClient, dwIndex, szKey, ARRAYSIZE(szKey)) == ERROR_SUCCESS;
  3679. dwIndex++)
  3680. {
  3681. HKEY hkApp;
  3682. if (RegOpenKeyEx(hkClient, szKey, 0, KEY_READ, &hkApp) == ERROR_SUCCESS)
  3683. {
  3684. HKEY hkInfo;
  3685. if (RegOpenKeyEx(hkApp, TEXT("InstallInfo"), 0, KEY_READ, &hkInfo) == ERROR_SUCCESS)
  3686. {
  3687. // Woo-hoo, this client provided install info
  3688. // Let's see if it's complete.
  3689. CLIENTINFO* pci = CLIENTINFO::Create(hkApp, hkInfo, szKey);
  3690. if (pci)
  3691. {
  3692. if (SUCCEEDED(hr = _pdaClients->Add(pci)))
  3693. {
  3694. // success
  3695. }
  3696. else
  3697. {
  3698. pci->Delete();
  3699. }
  3700. }
  3701. RegCloseKey(hkInfo);
  3702. }
  3703. RegCloseKey(hkApp);
  3704. }
  3705. }
  3706. RegCloseKey(hkClient);
  3707. //
  3708. // Sort the clients alphabetically to look nice.
  3709. // (Otherwise they show up alphabetical by registry key name,
  3710. // which is not very useful to an end-user.)
  3711. //
  3712. _pdaClients->Sort(CLIENTINFO::QSortCMP);
  3713. }
  3714. //
  3715. // Insert "Keep unchanged" and "Pick from list".
  3716. // Do this after sorting because we want those two
  3717. // to be at the top. Since we are adding to the top,
  3718. // we add them in the reverse order so
  3719. // "Keep unchanged" = 1, "Pick from list" = 0.
  3720. hr = AddStaticClientInfoToTop(KeepTextProp);
  3721. if (SUCCEEDED(hr))
  3722. {
  3723. hr = AddStaticClientInfoToTop(PickTextProp);
  3724. }
  3725. // Now create one row for each client we found
  3726. // Start at i=1 to skip over "Pick from list"
  3727. for (UINT i = 1; SUCCEEDED(hr) && i < _pdaClients->GetSize(); i++)
  3728. {
  3729. CLIENTINFO* pci = _pdaClients->GetItem(i);
  3730. Element* pe;
  3731. hr = paf->CreateElement(L"clientitem", NULL, &pe);
  3732. if (SUCCEEDED(hr))
  3733. {
  3734. hr = _peSel->Add(pe);
  3735. if (SUCCEEDED(hr))
  3736. {
  3737. pci->_pe = pe;
  3738. // Set friendly name
  3739. pci->SetFriendlyName(pci->_pszName);
  3740. if (pci->IsSentinel())
  3741. {
  3742. // "Keep Unchanged" loses the checkboxes and defaults selected
  3743. // Merely hide the checkboxes instead of destroying them;
  3744. // this keeps RowLayout happy.
  3745. FindDescendentByName(pe, L"show")->SetVisible(false);
  3746. _peSel->SetSelection(pe);
  3747. }
  3748. else
  3749. {
  3750. // Others initialize the checkbox and default unselected
  3751. pci->SetShowCheckbox(pci->_bShown);
  3752. }
  3753. }
  3754. else // _peSel->Add(pe) failed
  3755. {
  3756. pe->Destroy();
  3757. }
  3758. }
  3759. }
  3760. }
  3761. else // Add(_peSel) failed
  3762. {
  3763. _peSel->Destroy();
  3764. _peSel = NULL;
  3765. }
  3766. }
  3767. }
  3768. return hr;
  3769. }
  3770. HRESULT ClientBlock::AddStaticClientInfoToTop(PropertyInfo* ppi)
  3771. {
  3772. HRESULT hr;
  3773. Value* pv;
  3774. pv = GetValue(ppi, PI_Specified);
  3775. CLIENTINFO* pci = CLIENTINFO::Create(NULL, NULL, pv->GetString());
  3776. pv->Release();
  3777. if (pci)
  3778. {
  3779. if (SUCCEEDED(hr = _pdaClients->Insert(0, pci)))
  3780. {
  3781. // maybe this block has a custom replacement text for the
  3782. // Microsoft section if the current app is a Microsoft app.
  3783. GetKeepMSTextString(&pci->_pvMSName);
  3784. }
  3785. else
  3786. {
  3787. pci->Delete();
  3788. }
  3789. }
  3790. else
  3791. {
  3792. hr = E_OUTOFMEMORY;
  3793. }
  3794. return hr;
  3795. }
  3796. ClientBlock::CBTIER ClientBlock::_GetClientTier(LPCTSTR pszClient)
  3797. {
  3798. Value* pv;
  3799. LPWSTR pwsz;
  3800. // Highest tier is "Windows default client"
  3801. pwsz = GetWindowsClientString(&pv);
  3802. bool bRet = pwsz && AreEnglishStringsEqual(pwsz, pszClient);
  3803. pv->Release();
  3804. if (bRet)
  3805. {
  3806. return CBT_WINDOWSDEFAULT;
  3807. }
  3808. // next best is "Microsoft client"
  3809. if (_slOtherMSClients.IsStringInList(pszClient))
  3810. {
  3811. return CBT_MS;
  3812. }
  3813. // otherwise, it's a thirdparty app
  3814. return CBT_NONMS;
  3815. }
  3816. //
  3817. // Based on the filter, determine whether the specified item should
  3818. // be shown, hidden, or left alone (returned as a TRIBIT), and optionally
  3819. // determine whether the item should be added to the client picker.
  3820. //
  3821. TRIBIT ClientBlock::_GetFilterShowAdd(CLIENTINFO* pci, ClientPicker* pcp, bool* pbAdd)
  3822. {
  3823. bool bAdd = false;
  3824. TRIBIT tShow = TRIBIT_UNDEFINED;
  3825. CBTIER cbt = _GetClientTier(pci->_pszKey);
  3826. switch (pcp->GetFilter())
  3827. {
  3828. case CLIENTFILTER_OEM:
  3829. //
  3830. // Add the one that is marked "OEM Default".
  3831. // (Caller will catch the "more than one" scenario.)
  3832. // Set show/hide state according to OEM preference.
  3833. //
  3834. bAdd = pci->_bOEMDefault;
  3835. if (bAdd) {
  3836. tShow = TRIBIT_TRUE;
  3837. } else {
  3838. tShow = pci->_tOEMShown;
  3839. }
  3840. break;
  3841. case CLIENTFILTER_MS:
  3842. //
  3843. // Add the Windows preferred client.
  3844. // Show all applications except for "keep unchanged" (which
  3845. // isn't really an application anyway).
  3846. //
  3847. bAdd = IsWindowsDefaultClient(cbt);
  3848. tShow = TRIBIT_TRUE;
  3849. break;
  3850. case CLIENTFILTER_NONMS:
  3851. //
  3852. // Hide all Microsoft clients.
  3853. // Add all thirdparty clients and show them.
  3854. //
  3855. if (IsMicrosoftClient(cbt))
  3856. {
  3857. bAdd = false;
  3858. tShow = TRIBIT_FALSE;
  3859. }
  3860. else
  3861. {
  3862. bAdd = true;
  3863. tShow = TRIBIT_TRUE;
  3864. }
  3865. break;
  3866. default:
  3867. DUIAssert(0, "Invalid client filter category");
  3868. break;
  3869. }
  3870. if (pbAdd)
  3871. {
  3872. *pbAdd = bAdd;
  3873. }
  3874. if (pci->IsSentinel())
  3875. {
  3876. tShow = TRIBIT_UNDEFINED;
  3877. }
  3878. return tShow;
  3879. }
  3880. //
  3881. // On success, returns the number of items added
  3882. // (not counting "Keep unchanged")
  3883. //
  3884. HRESULT ClientBlock::InitializeClientPicker(ClientPicker* pcp)
  3885. {
  3886. HRESULT hr = S_OK;
  3887. ARPFrame* paf = FindAncestorElement<ARPFrame>(this);
  3888. // Walk our children looking for ones that match the filter.
  3889. HKEY hkClient = _OpenClientKey();
  3890. if (hkClient)
  3891. {
  3892. if (SUCCEEDED(paf->CreateElement(L"oemclientshowhide", NULL, &pcp->_peShowHide)))
  3893. {
  3894. // Insert the template after our parent
  3895. Element* peParent = pcp->GetParent();
  3896. peParent->GetParent()->Insert(pcp->_peShowHide, peParent->GetIndex() + 1);
  3897. }
  3898. // Note! Start loop with 2 because we don't care about
  3899. // "Pick from list" or "Keep Unchanged" yet
  3900. DUIAssert(_pdaClients->GetItem(0)->IsPickFromList(), "GetItem(0) must be 'Pick from list'");
  3901. DUIAssert(_pdaClients->GetItem(1)->IsKeepUnchanged(), "GetItem(1) must be 'Keep unchanged'");
  3902. for (UINT i = 2; SUCCEEDED(hr) && i < _pdaClients->GetSize(); i++)
  3903. {
  3904. CLIENTINFO* pci = _pdaClients->GetItem(i);
  3905. bool bAdd;
  3906. TRIBIT tShow = _GetFilterShowAdd(pci, pcp, &bAdd);
  3907. if (pcp->_peShowHide)
  3908. {
  3909. switch (tShow)
  3910. {
  3911. case TRIBIT_TRUE:
  3912. pcp->AddClientToOEMRow(L"show", pci);
  3913. pcp->SetNotEmpty();
  3914. break;
  3915. case TRIBIT_FALSE:
  3916. pcp->AddClientToOEMRow(L"hide", pci);
  3917. pcp->SetNotEmpty();
  3918. break;
  3919. }
  3920. }
  3921. if (bAdd)
  3922. {
  3923. hr = pcp->GetClientList()->Add(pci);
  3924. pcp->SetNotEmpty();
  3925. }
  3926. }
  3927. RegCloseKey(hkClient);
  3928. }
  3929. if (SUCCEEDED(hr))
  3930. {
  3931. // Now some wacko cleanup rules.
  3932. switch (pcp->GetFilter())
  3933. {
  3934. case CLIENTFILTER_OEM:
  3935. // There can be only one OEM default item.
  3936. // If there's more than one (OEM or app trying to cheat),
  3937. // then throw them all away.
  3938. if (pcp->GetClientList()->GetSize() != 1)
  3939. {
  3940. pcp->GetClientList()->Reset(); // throw away everything
  3941. }
  3942. break;
  3943. case CLIENTFILTER_MS:
  3944. // If the current client is not the default client but
  3945. // does belong to Microsoft, then add "Keep unchanged"
  3946. // and select it. What's more, save the current string
  3947. // to be used if the user picks the Windows client,
  3948. // then append the Windows app to the "Also Show" string
  3949. // and save that too.
  3950. if (_IsCurrentClientNonWindowsMS())
  3951. {
  3952. hr = pcp->AddKeepUnchanged(_pdaClients->GetItem(1));
  3953. }
  3954. break;
  3955. case CLIENTFILTER_NONMS:
  3956. // If there is more than one available, then insert
  3957. // "Pick an app"
  3958. if (pcp->GetClientList()->GetSize() > 1)
  3959. {
  3960. hr = pcp->GetClientList()->Insert(0, _pdaClients->GetItem(0)); // insert "pick an app"
  3961. }
  3962. break;
  3963. }
  3964. // If there are no items, then add "Keep unchanged"
  3965. if (pcp->GetClientList()->GetSize() == 0)
  3966. {
  3967. hr = pcp->GetClientList()->Add(_pdaClients->GetItem(1)); // add "keep unchanged"
  3968. }
  3969. }
  3970. if (pcp->_peShowHide)
  3971. {
  3972. _RemoveEmptyOEMRow(pcp->_peShowHide, L"show");
  3973. _RemoveEmptyOEMRow(pcp->_peShowHide, L"hide");
  3974. }
  3975. return hr;
  3976. }
  3977. HRESULT ClientPicker::AddKeepUnchanged(CLIENTINFO* pciKeepUnchanged)
  3978. {
  3979. HRESULT hr = GetClientList()->Insert(0, pciKeepUnchanged); // insert "keep unchanged"
  3980. return hr;
  3981. }
  3982. void ClientPicker::AddClientToOEMRow(LPCWSTR pszName, CLIENTINFO* pci)
  3983. {
  3984. Element* peRow = FindDescendentByName(_peShowHide, pszName);
  3985. Element* peList = FindDescendentByName(peRow, L"list");
  3986. Value* pv;
  3987. LPCWSTR pszContent = peList->GetContentString(&pv);
  3988. if (!pszContent)
  3989. {
  3990. _SetStaticTextAndAccName(peList, pci->_pszName);
  3991. }
  3992. else
  3993. {
  3994. TCHAR szFormat[20];
  3995. LPCWSTR rgpszInsert[2] = { pszContent, pci->_pszName };
  3996. LoadString(g_hinst, IDS_ADDITIONALCLIENTFORMAT, szFormat, SIZECHARS(szFormat));
  3997. LPWSTR pszFormatted;
  3998. if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  3999. szFormat, 0, 0, (LPWSTR)&pszFormatted, 0, (va_list*)rgpszInsert))
  4000. {
  4001. _SetStaticTextAndAccName(peList, pszFormatted);
  4002. LocalFree(pszFormatted);
  4003. }
  4004. }
  4005. pv->Release();
  4006. }
  4007. void ClientBlock::_RemoveEmptyOEMRow(Element* peShowHide, LPCWSTR pszName)
  4008. {
  4009. Element* peRow = FindDescendentByName(peShowHide, pszName);
  4010. Element* peList = FindDescendentByName(peRow, L"list");
  4011. Value* pv;
  4012. LPCWSTR pszContent = peList->GetContentString(&pv);
  4013. if (!pszContent || !pszContent[0])
  4014. {
  4015. peRow->Destroy();
  4016. }
  4017. pv->Release();
  4018. }
  4019. // Take the setting from the ClientPicker and copy it to the Custom item
  4020. // This is done in preparation for Apply()ing the custom item to make the
  4021. // changes stick.
  4022. HRESULT ClientBlock::TransferFromClientPicker(ClientPicker* pcp)
  4023. {
  4024. HRESULT hr = S_OK;
  4025. CLIENTINFO* pciSel = pcp->GetSelectedClient();
  4026. for (UINT i = 0; SUCCEEDED(hr) && i < _pdaClients->GetSize(); i++)
  4027. {
  4028. CLIENTINFO* pci = _pdaClients->GetItem(i);
  4029. // If this is the one the guy selected, then select it here too
  4030. if (pci == pciSel && _peSel)
  4031. {
  4032. if (pci->IsPickFromList())
  4033. {
  4034. // "Pick from list" -> "Keep unchanged"
  4035. _peSel->SetSelection(_pdaClients->GetItem(1)->GetSetDefault());
  4036. }
  4037. else
  4038. {
  4039. _peSel->SetSelection(pci->GetSetDefault());
  4040. }
  4041. }
  4042. // Transfer the hide/show setting into the element
  4043. TRIBIT tShow = _GetFilterShowAdd(pci, pcp, NULL);
  4044. if (tShow != TRIBIT_UNDEFINED)
  4045. {
  4046. pci->SetShowCheckbox(tShow == TRIBIT_TRUE);
  4047. }
  4048. }
  4049. return hr;
  4050. }
  4051. //
  4052. // Okay, here it is, the whole reason we're here. Apply the user's
  4053. // choices.
  4054. //
  4055. HRESULT ClientBlock::Apply(ARPFrame* paf)
  4056. {
  4057. HRESULT hr = S_OK;
  4058. HKEY hkClient = _OpenClientKey(HKEY_LOCAL_MACHINE, KEY_READ | KEY_WRITE);
  4059. if (hkClient)
  4060. {
  4061. // Note! Start loop with 2 because we don't care about applying "Keep Unchanged"
  4062. // or "Pick an app"
  4063. DUIAssert(_pdaClients->GetItem(0)->IsPickFromList(), "GetItem(0) must be 'Pick from list'");
  4064. DUIAssert(_pdaClients->GetItem(1)->IsKeepUnchanged(), "GetItem(1) must be 'Keep unchanged'");
  4065. for (UINT i = 2; SUCCEEDED(hr) && i < _pdaClients->GetSize(); i++)
  4066. {
  4067. CLIENTINFO* pci = _pdaClients->GetItem(i);
  4068. TCHAR szBuf[MAX_PATH];
  4069. wnsprintf(szBuf, ARRAYSIZE(szBuf), TEXT("%s\\InstallInfo"), pci->_pszKey);
  4070. HKEY hkInfo;
  4071. if (RegOpenKeyEx(hkClient, szBuf, 0, KEY_READ, &hkInfo) == ERROR_SUCCESS)
  4072. {
  4073. // Always do hide/show first. That way, an application being
  4074. // asked to set itself as the default always does so while its
  4075. // icons are shown.
  4076. bool bShow = pci->IsShowChecked();
  4077. if (bShow != pci->_bShown)
  4078. {
  4079. if (pci->GetInstallCommand(hkInfo, bShow ? TEXT("ShowIconsCommand") : TEXT("HideIconsCommand"),
  4080. szBuf, DUIARRAYSIZE(szBuf)))
  4081. {
  4082. hr = paf->LaunchClientCommandAndWait(bShow ? IDS_SHOWINGICONS : IDS_HIDINGICONS, pci->_pszName, szBuf);
  4083. }
  4084. }
  4085. if (pci->GetSetDefault()->GetSelected())
  4086. {
  4087. if (pci->GetInstallCommand(hkInfo, TEXT("ReinstallCommand"),
  4088. szBuf, DUIARRAYSIZE(szBuf)))
  4089. {
  4090. FILETIME ft;
  4091. GetSystemTimeAsFileTime(&ft);
  4092. SHSetValue(hkClient, NULL, TEXT("LastUserInitiatedDefaultChange"),
  4093. REG_BINARY, &ft, sizeof(ft));
  4094. hr = paf->LaunchClientCommandAndWait(IDS_SETTINGDEFAULT, pci->_pszName, szBuf);
  4095. }
  4096. }
  4097. RegCloseKey(hkInfo);
  4098. }
  4099. }
  4100. RegCloseKey(hkClient);
  4101. }
  4102. return hr;
  4103. }
  4104. ////////////////////////////////////////////////////////
  4105. // ClassInfo (must appear after property definitions)
  4106. // ClientType property
  4107. static int vvClientType[] = { DUIV_STRING, -1 };
  4108. static PropertyInfo impClientTypeProp = { L"ClientType", PF_Normal, 0, vvClientType, NULL, Value::pvStringNull };
  4109. PropertyInfo* ClientBlock::ClientTypeProp = &impClientTypeProp;
  4110. // WindowsClient property
  4111. static int vvWindowsClient[] = { DUIV_STRING, -1 };
  4112. static PropertyInfo impWindowsClientProp = { L"WindowsClient", PF_Normal, 0, vvWindowsClient, NULL, Value::pvStringNull };
  4113. PropertyInfo* ClientBlock::WindowsClientProp = &impWindowsClientProp;
  4114. // OtherMSClients property
  4115. static int vvOtherMSClients[] = { DUIV_STRING, -1 };
  4116. static PropertyInfo impOtherMSClientsProp = { L"OtherMSClients", PF_Normal, 0, vvOtherMSClients, NULL, Value::pvStringNull };
  4117. PropertyInfo* ClientBlock::OtherMSClientsProp = &impOtherMSClientsProp;
  4118. // KeepText property
  4119. static int vvKeepText[] = { DUIV_STRING, -1 };
  4120. static PropertyInfo impKeepTextProp = { L"KeepText", PF_Normal, 0, vvKeepText, NULL, Value::pvStringNull };
  4121. PropertyInfo* ClientBlock::KeepTextProp = &impKeepTextProp;
  4122. // KeepMSText property
  4123. static int vvKeepMSText[] = { DUIV_STRING, -1 };
  4124. static PropertyInfo impKeepMSTextProp = { L"KeepMSText", PF_Normal, 0, vvKeepMSText, NULL, Value::pvStringNull };
  4125. PropertyInfo* ClientBlock::KeepMSTextProp = &impKeepMSTextProp;
  4126. // PickText property
  4127. static int vvPickText[] = { DUIV_STRING, -1 };
  4128. static PropertyInfo impPickTextProp = { L"PickText", PF_Normal, 0, vvPickText, NULL, Value::pvStringNull };
  4129. PropertyInfo* ClientBlock::PickTextProp = &impPickTextProp;
  4130. // Class properties
  4131. PropertyInfo* _aClientBlockPI[] = {
  4132. ClientBlock::ClientTypeProp,
  4133. ClientBlock::WindowsClientProp,
  4134. ClientBlock::OtherMSClientsProp,
  4135. ClientBlock::KeepTextProp,
  4136. ClientBlock::KeepMSTextProp,
  4137. ClientBlock::PickTextProp,
  4138. };
  4139. // Define class info with type and base type, set static class pointer
  4140. IClassInfo* ClientBlock::Class = NULL;
  4141. HRESULT ClientBlock::Register()
  4142. {
  4143. return ClassInfo<ClientBlock,super>::Register(L"clientblock", _aClientBlockPI, DUIARRAYSIZE(_aClientBlockPI));
  4144. }
  4145. ////////////////////////////////////////////////////////
  4146. // Expandable class
  4147. //
  4148. // Base class for Expando and Clipper. It is just an element
  4149. // with an "expanded" property. This property inherits from parent
  4150. // to child. This is used so Clipper can inherit (and therefore
  4151. // react to) the expanded state of its parent Expando.
  4152. //
  4153. HRESULT Expandable::Create(OUT Element** ppElement)
  4154. {
  4155. *ppElement = NULL;
  4156. Expandable* pe = HNew<Expandable>();
  4157. if (!pe)
  4158. return E_OUTOFMEMORY;
  4159. HRESULT hr = pe->Initialize(0);
  4160. if (FAILED(hr))
  4161. {
  4162. pe->Destroy();
  4163. return hr;
  4164. }
  4165. *ppElement = pe;
  4166. return S_OK;
  4167. }
  4168. ////////////////////////////////////////////////////////
  4169. // Property definitions
  4170. /** Property template (replace !!!), also update private PropertyInfo* parray and class header (element.h)
  4171. // !!! property
  4172. static int vv!!![] = { DUIV_INT, -1 }; StaticValue(svDefault!!!, DUIV_INT, 0);
  4173. static PropertyInfo imp!!!Prop = { L"!!!", PF_Normal, 0, vv!!!, (Value*)&svDefault!!! };
  4174. PropertyInfo* Element::!!!Prop = &imp!!!Prop;
  4175. **/
  4176. // Expanded property
  4177. static int vvExpanded[] = { DUIV_BOOL, -1 };
  4178. static PropertyInfo impExpandedProp = { L"Expanded", PF_Normal|PF_Inherit, 0, vvExpanded, NULL, Value::pvBoolTrue };
  4179. PropertyInfo* Expandable::ExpandedProp = &impExpandedProp;
  4180. ////////////////////////////////////////////////////////
  4181. // ClassInfo (must appear after property definitions)
  4182. // Class properties
  4183. PropertyInfo* _aExpandablePI[] = { Expandable::ExpandedProp };
  4184. // Define class info with type and base type, set static class pointer
  4185. IClassInfo* Expandable::Class = NULL;
  4186. HRESULT Expandable::Register()
  4187. {
  4188. return ClassInfo<Expandable,super>::Register(L"Expandable", _aExpandablePI, DUIARRAYSIZE(_aExpandablePI));
  4189. }
  4190. ////////////////////////////////////////////////////////
  4191. // Expando class
  4192. //
  4193. // An Expando element works in conjunction with a Clipper element
  4194. // to provide expand/collapse functionality.
  4195. //
  4196. // The Expando element manages the expanded/contracted state.
  4197. // The Expando element has two child elements:
  4198. //
  4199. // The first element is a button (the "header").
  4200. // The second element is a Clipper.
  4201. //
  4202. // The Clipper vanishes when contracted and is shown when expanded.
  4203. // The header is always shown.
  4204. //
  4205. // One of the elements in the header must be a button of type "arrow".
  4206. // Clicking this button causes the Expando to expand/collapse.
  4207. //
  4208. // A click on any other element causes an Expando::Click event
  4209. // to fire (to be caught by an ancestor element.)
  4210. //
  4211. // The "selected" property on the "arrow" tracks the "expanded"
  4212. // property on the Expando.
  4213. //
  4214. DefineClassUniqueID(Expando, Click)
  4215. HRESULT Expando::Create(OUT Element** ppElement)
  4216. {
  4217. *ppElement = NULL;
  4218. Expando* pex = HNewAndZero<Expando>();
  4219. if (!pex)
  4220. return E_OUTOFMEMORY;
  4221. HRESULT hr = pex->Initialize();
  4222. if (FAILED(hr))
  4223. {
  4224. pex->Destroy();
  4225. return hr;
  4226. }
  4227. *ppElement = pex;
  4228. return S_OK;
  4229. }
  4230. HRESULT Expando::Initialize()
  4231. {
  4232. HRESULT hr;
  4233. // Initialize base
  4234. hr = super::Initialize(0); // Normal display node creation
  4235. if (FAILED(hr))
  4236. return hr;
  4237. // Initialize
  4238. _fExpanding = false;
  4239. return S_OK;
  4240. }
  4241. Clipper* Expando::GetClipper()
  4242. {
  4243. Element* pe = GetNthChild(this, 1);
  4244. DUIAssertNoMsg(pe->GetClassInfo()->IsSubclassOf(Clipper::Class));
  4245. return (Clipper*)pe;
  4246. }
  4247. //
  4248. // Do this so ARPSelector will select us and deselect our siblings
  4249. //
  4250. void Expando::FireClickEvent()
  4251. {
  4252. Event e;
  4253. e.uidType = Expando::Click;
  4254. FireEvent(&e); // Will route and bubble
  4255. }
  4256. void Expando::OnEvent(Event* pev)
  4257. {
  4258. if (pev->nStage == GMF_BUBBLED)
  4259. {
  4260. if (pev->uidType == Button::Click)
  4261. {
  4262. pev->fHandled = true;
  4263. // Clicking the arrow toggles the expanded state
  4264. if (pev->peTarget->GetID() == StrToID(L"arrow"))
  4265. {
  4266. SetExpanded(!GetExpanded());
  4267. }
  4268. else
  4269. {
  4270. // Clicking anything else activates our section
  4271. FireClickEvent();
  4272. }
  4273. }
  4274. }
  4275. Element::OnEvent(pev);
  4276. }
  4277. ////////////////////////////////////////////////////////
  4278. // System events
  4279. HRESULT _SetParentExpandedProp(ClientPicker* pcp, LPARAM lParam)
  4280. {
  4281. Value* pv = (Value*)lParam;
  4282. pcp->SetValue(ClientPicker::ParentExpandedProp, PI_Local, pv);
  4283. return S_OK;
  4284. }
  4285. void Expando::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  4286. {
  4287. // Do default processing
  4288. Element::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  4289. if (IsProp(Selected))
  4290. {
  4291. // BUGBUG something goes here?
  4292. }
  4293. else if (IsProp(Expanded))
  4294. {
  4295. // Update height of clipper based on expanded state
  4296. Element* pe = GetClipper();
  4297. if (pe)
  4298. {
  4299. // The following will cause a relayout, mark object so that
  4300. // when the expando's Extent changes, it'll go through
  4301. // with the EnsureVisible. Otherwise, it's being resized
  4302. // as a result of something else. In which case, do nothing.
  4303. _fExpanding = true;
  4304. // To achieve "pulldown" animation, we use a clipper control that will
  4305. // size it's child based on it's unconstrained desired size in its Y direction.
  4306. // We also push the Expanded property into all child ClientPicker
  4307. // elements as the Selected property so they can turn static when
  4308. // collapsed.
  4309. if (pvNew->GetBool())
  4310. {
  4311. pe->RemoveLocalValue(HeightProp);
  4312. }
  4313. else
  4314. {
  4315. pe->SetHeight(0);
  4316. }
  4317. TraverseTree<ClientPicker>(pe, _SetParentExpandedProp, (LPARAM)pvNew);
  4318. }
  4319. // child Clipper object inherits the Expanded state
  4320. // Push the Expanded state as the arrow's Selected state
  4321. FindDescendentByName(this, L"arrow")->SetValue(SelectedProp, PI_Local, pvNew);
  4322. }
  4323. else if (IsProp(Extent))
  4324. {
  4325. if (_fExpanding && GetExpanded())
  4326. {
  4327. _fExpanding = false;
  4328. // On extent, we want to ensure that not just the client area but
  4329. // also the bottom margin of the expando is visible. Why? Simply
  4330. // because it looks better to scroll the expando plus its margin
  4331. // into view versus just the expando.
  4332. //
  4333. Value* pvSize;
  4334. Value* pvMargin;
  4335. const SIZE* psize = GetExtent(&pvSize);
  4336. const RECT* prect = GetMargin(&pvMargin);
  4337. EnsureVisible(0, 0, psize->cx, psize->cy + prect->bottom);
  4338. pvSize->Release();
  4339. pvMargin->Release();
  4340. }
  4341. }
  4342. }
  4343. ////////////////////////////////////////////////////////
  4344. // ClassInfo (must appear after property definitions)
  4345. // Define class info with type and base type, set static class pointer
  4346. IClassInfo* Expando::Class = NULL;
  4347. HRESULT Expando::Register()
  4348. {
  4349. return ClassInfo<Expando,super>::Register(L"Expando", NULL, 0);
  4350. }
  4351. ////////////////////////////////////////////////////////
  4352. //
  4353. // Clipper class
  4354. //
  4355. // Used to do the smooth hide/show animation.
  4356. //
  4357. // The Clipper element animates away its one child, typically
  4358. // an <element> with layout and inner child elements.
  4359. //
  4360. HRESULT Clipper::Create(OUT Element** ppElement)
  4361. {
  4362. *ppElement = NULL;
  4363. Clipper* pc = HNewAndZero<Clipper>();
  4364. if (!pc)
  4365. return E_OUTOFMEMORY;
  4366. HRESULT hr = pc->Initialize();
  4367. if (FAILED(hr))
  4368. {
  4369. pc->Destroy();
  4370. return hr;
  4371. }
  4372. *ppElement = pc;
  4373. return S_OK;
  4374. }
  4375. HRESULT Clipper::Initialize()
  4376. {
  4377. // Initialize base
  4378. HRESULT hr = super::Initialize(EC_SelfLayout); // Normal display node creation, self layout
  4379. if (FAILED(hr))
  4380. return hr;
  4381. // Children can exist outside of Element bounds
  4382. SetGadgetStyle(GetDisplayNode(), GS_CLIPINSIDE, GS_CLIPINSIDE);
  4383. return S_OK;
  4384. }
  4385. ////////////////////////////////////////////////////////
  4386. // Self-layout methods
  4387. SIZE Clipper::_SelfLayoutUpdateDesiredSize(int cxConstraint, int cyConstraint, Surface* psrf)
  4388. {
  4389. UNREFERENCED_PARAMETER(cyConstraint);
  4390. SIZE size = { 0, 0 };
  4391. // Desired size of this is based solely on it's first child.
  4392. // Width is child's width, height is unconstrained height of child.
  4393. Element* pec = GetNthChild(this, 0);
  4394. if (pec)
  4395. {
  4396. size = pec->_UpdateDesiredSize(cxConstraint, INT_MAX, psrf);
  4397. if (size.cx > cxConstraint)
  4398. size.cx = cxConstraint;
  4399. if (size.cy > cyConstraint)
  4400. size.cy = cyConstraint;
  4401. }
  4402. return size;
  4403. }
  4404. void Clipper::_SelfLayoutDoLayout(int cx, int cy)
  4405. {
  4406. // Layout first child giving it's desired height and aligning
  4407. // it with the clipper's bottom edge
  4408. Element* pec = GetNthChild(this, 0);
  4409. if (pec)
  4410. {
  4411. const SIZE* pds = pec->GetDesiredSize();
  4412. pec->_UpdateLayoutPosition(0, cy - pds->cy);
  4413. pec->_UpdateLayoutSize(cx, pds->cy);
  4414. }
  4415. }
  4416. ////////////////////////////////////////////////////////
  4417. // Property definitions
  4418. ////////////////////////////////////////////////////////
  4419. // ClassInfo (must appear after property definitions)
  4420. // Define class info with type and base type, set static class pointer
  4421. IClassInfo* Clipper::Class = NULL;
  4422. HRESULT Clipper::Register()
  4423. {
  4424. return ClassInfo<Clipper,super>::Register(L"Clipper", NULL, 0);
  4425. }
  4426. ////////////////////////////////////////////////////////
  4427. // GradientLine class
  4428. //
  4429. // This is necessary for two reasons.
  4430. //
  4431. // 1. gradient(...) doesn't support FILLTYPE_TriHGradient.
  4432. // The code to implement tri-gradients exists only in
  4433. // the GdiPlus version. We can fake it by putting two
  4434. // FILLTYPE_HGradient elements next to each other, except
  4435. // for the second problem...
  4436. // 2. gradient(...) doesn't support system colors like "buttonface".
  4437. //
  4438. HRESULT GradientLine::Create(OUT Element** ppElement)
  4439. {
  4440. *ppElement = NULL;
  4441. GradientLine* pe = HNew<GradientLine>();
  4442. if (!pe)
  4443. return E_OUTOFMEMORY;
  4444. HRESULT hr = pe->Initialize(0);
  4445. if (FAILED(hr))
  4446. {
  4447. pe->Destroy();
  4448. return hr;
  4449. }
  4450. *ppElement = pe;
  4451. return S_OK;
  4452. }
  4453. COLORREF GradientLine::GetColorProperty(PropertyInfo* ppi)
  4454. {
  4455. // on failure, use transparent color (i.e., nothing happens)
  4456. COLORREF cr = ARGB(0xFF, 0, 0, 0);
  4457. Value* pv = GetValue(ppi, PI_Specified);
  4458. switch (pv->GetType())
  4459. {
  4460. case DUIV_INT:
  4461. cr = ColorFromEnumI(pv->GetInt());
  4462. break;
  4463. case DUIV_FILL:
  4464. {
  4465. const Fill* pf = pv->GetFill();
  4466. if (pf->dType == FILLTYPE_Solid)
  4467. {
  4468. cr = pf->ref.cr;
  4469. }
  4470. else
  4471. {
  4472. DUIAssert(0, "GradientLine supports only solid colors");
  4473. }
  4474. }
  4475. break;
  4476. default:
  4477. DUIAssert(0, "GradientLine supports only solid colors");
  4478. }
  4479. pv->Release();
  4480. return cr;
  4481. }
  4482. void GradientLine::Paint(HDC hDC, const RECT* prcBounds, const RECT* prcInvalid, RECT* prcSkipBorder, RECT* prcSkipContent)
  4483. {
  4484. // Paint default except content
  4485. RECT rcContent;
  4486. Element::Paint(hDC, prcBounds, prcInvalid, prcSkipBorder, &rcContent);
  4487. // Render gradient content if requested
  4488. if (!prcSkipContent)
  4489. {
  4490. //
  4491. // Vertices are as indicated. The two rectangles are (0-1) and (1-2).
  4492. //
  4493. // 0(bgcolor) 2(bgcolor)
  4494. // +-----------------+----------------+
  4495. // | |
  4496. // | |
  4497. // | |
  4498. // +-----------------+----------------+
  4499. // 1(fgcolor)
  4500. TRIVERTEX rgvert[3];
  4501. GRADIENT_RECT rggr[2];
  4502. COLORREF cr;
  4503. cr = GetColorProperty(BackgroundProp);
  4504. rgvert[0].x = rcContent.left;
  4505. rgvert[0].y = rcContent.top;
  4506. rgvert[0].Red = GetRValue(cr) << 8;
  4507. rgvert[0].Green = GetGValue(cr) << 8;
  4508. rgvert[0].Blue = GetBValue(cr) << 8;
  4509. rgvert[0].Alpha = GetAValue(cr) << 8;
  4510. rgvert[2] = rgvert[0];
  4511. rgvert[2].x = rcContent.right;
  4512. cr = GetColorProperty(ForegroundProp);
  4513. rgvert[1].x = (rcContent.left + rcContent.right) / 2;
  4514. rgvert[1].y = rcContent.bottom;
  4515. rgvert[1].Red = GetRValue(cr) << 8;
  4516. rgvert[1].Green = GetGValue(cr) << 8;
  4517. rgvert[1].Blue = GetBValue(cr) << 8;
  4518. rgvert[1].Alpha = GetAValue(cr) << 8;
  4519. rggr[0].UpperLeft = 0;
  4520. rggr[0].LowerRight = 1;
  4521. rggr[1].UpperLeft = 1;
  4522. rggr[1].LowerRight = 2;
  4523. GradientFill(hDC, rgvert, DUIARRAYSIZE(rgvert), rggr, DUIARRAYSIZE(rggr), GRADIENT_FILL_RECT_H);
  4524. }
  4525. else
  4526. {
  4527. *prcSkipContent = rcContent;
  4528. }
  4529. }
  4530. ////////////////////////////////////////////////////////
  4531. // ClassInfo (must appear after property definitions)
  4532. // Define class info with type and base type, set static class pointer
  4533. IClassInfo* GradientLine::Class = NULL;
  4534. HRESULT GradientLine::Register()
  4535. {
  4536. return ClassInfo<GradientLine,super>::Register(L"GradientLine", NULL, 0);
  4537. }
  4538. ////////////////////////////////////////////////////////
  4539. // BigElement class
  4540. //
  4541. // This is necessary because the DUI parser limits rcstr() to 256
  4542. // characters and we have strings that are dangerously close to that
  4543. // limit. (So localization will likely push them over the limit.)
  4544. //
  4545. HRESULT BigElement::Create(OUT Element** ppElement)
  4546. {
  4547. *ppElement = NULL;
  4548. BigElement* pe = HNew<BigElement>();
  4549. if (!pe)
  4550. return E_OUTOFMEMORY;
  4551. HRESULT hr = pe->Initialize(0);
  4552. if (FAILED(hr))
  4553. {
  4554. pe->Destroy();
  4555. return hr;
  4556. }
  4557. *ppElement = pe;
  4558. return S_OK;
  4559. }
  4560. void BigElement::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  4561. {
  4562. // Do default processing
  4563. Element::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  4564. if (IsProp(StringResID))
  4565. {
  4566. UINT uID = pvNew->GetInt();
  4567. HRSRC hrsrc = FindResource(g_hinst, (LPTSTR)(LONG_PTR)(1 + uID / 16), RT_STRING);
  4568. if (hrsrc)
  4569. {
  4570. PWCHAR pwch = (PWCHAR)LoadResource(g_hinst, hrsrc);
  4571. if (pwch)
  4572. {
  4573. // Now skip over strings until we hit the one we want.
  4574. for (uID %= 16; uID; uID--)
  4575. {
  4576. pwch += *pwch + 1;
  4577. }
  4578. // Found it -- load the entire string and set it
  4579. LPWSTR pszString = new WCHAR[*pwch + 1];
  4580. if (pszString)
  4581. {
  4582. memcpy(pszString, pwch+1, *pwch * sizeof(WCHAR));
  4583. pszString[*pwch] = L'\0';
  4584. SetContentString(pszString);
  4585. SetAccName(pszString);
  4586. delete[] pszString;
  4587. }
  4588. }
  4589. }
  4590. }
  4591. }
  4592. ////////////////////////////////////////////////////////
  4593. // Property definitions
  4594. // StringResID property
  4595. static int vvStringResID[] = { DUIV_INT, -1 };
  4596. static PropertyInfo impStringResIDProp = { L"StringResID", PF_Normal, 0, vvStringResID, NULL, Value::pvIntZero };
  4597. PropertyInfo* BigElement::StringResIDProp = &impStringResIDProp;
  4598. ////////////////////////////////////////////////////////
  4599. // ClassInfo (must appear after property definitions)
  4600. // Class properties
  4601. PropertyInfo* _aBigElementPI[] = { BigElement::StringResIDProp };
  4602. // Define class info with type and base type, set static class pointer
  4603. IClassInfo* BigElement::Class = NULL;
  4604. HRESULT BigElement::Register()
  4605. {
  4606. return ClassInfo<BigElement,super>::Register(L"BigElement", _aBigElementPI, DUIARRAYSIZE(_aBigElementPI));
  4607. }
  4608. ////////////////////////////////////////////////////////
  4609. // ARP Parser callback
  4610. void CALLBACK ARPParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine)
  4611. {
  4612. WCHAR buf[201];
  4613. if (dLine != -1)
  4614. {
  4615. StringCchPrintfW(buf, ARRAYSIZE(buf), L"%s '%s' at line %d", pszError, pszToken, dLine);
  4616. }
  4617. else
  4618. {
  4619. StringCchPrintfW(buf, ARRAYSIZE(buf), L"%s '%s'", pszError, pszToken);
  4620. }
  4621. MessageBoxW(NULL, buf, L"Parser Message", MB_OK);
  4622. }
  4623. void inline SetElementAccessability(Element* pe, bool bAccessible, int iRole, LPCWSTR pszAccName)
  4624. {
  4625. if (pe)
  4626. {
  4627. pe->SetAccessible(bAccessible);
  4628. pe->SetAccRole(iRole);
  4629. pe->SetAccName(pszAccName);
  4630. }
  4631. }
  4632. void EnablePane(Element* pePane, bool fEnable)
  4633. {
  4634. if (fEnable)
  4635. {
  4636. pePane->SetLayoutPos(BLP_Client);
  4637. EnableElementTreeAccessibility(pePane);
  4638. }
  4639. else
  4640. {
  4641. pePane->SetLayoutPos(LP_None);
  4642. DisableElementTreeAccessibility(pePane);
  4643. }
  4644. }
  4645. void BestFitOnDesktop(RECT* r)
  4646. {
  4647. ASSERT(r != NULL);
  4648. RECT wr; // Rect to hold size of work area
  4649. if (SystemParametersInfo(SPI_GETWORKAREA, 0, &wr, 0))
  4650. {
  4651. if ((wr.right-wr.left) < ARP_DEFAULT_WIDTH)
  4652. {
  4653. // Default width is too large, use the entire width of the desktop area
  4654. r->left = wr.left;
  4655. r->right = wr.right - wr.left;
  4656. }
  4657. else
  4658. {
  4659. // Center on screen using default width
  4660. r->left = wr.left + (((wr.right-wr.left) - ARP_DEFAULT_WIDTH) / 2);
  4661. r->right = ARP_DEFAULT_WIDTH;
  4662. }
  4663. if ((wr.bottom-wr.top) < ARP_DEFAULT_HEIGHT)
  4664. {
  4665. // Default height is too large, use the entire height of the desktop area
  4666. r->top = wr.top;
  4667. r->bottom = wr.bottom - wr.top;
  4668. }
  4669. else
  4670. {
  4671. // Center on screen using default height
  4672. r->top = wr.top + (((wr.bottom-wr.top) - ARP_DEFAULT_HEIGHT) / 2);
  4673. r->bottom = ARP_DEFAULT_HEIGHT;
  4674. }
  4675. }
  4676. else
  4677. {
  4678. // Don't know why the function would fail, but if it does just use the default size
  4679. // and position
  4680. SetRect(r,
  4681. ARP_DEFAULT_POS_X,
  4682. ARP_DEFAULT_POS_Y,
  4683. ARP_DEFAULT_WIDTH,
  4684. ARP_DEFAULT_HEIGHT);
  4685. }
  4686. }
  4687. ////////////////////////////////////////////////////////
  4688. // ARP entry point
  4689. DWORD WINAPI PopulateInstalledItemList(void* paf);
  4690. STDAPI ARP(HWND hWnd, int nPage)
  4691. {
  4692. HRESULT hr;
  4693. Parser* pParser = NULL;
  4694. NativeHWNDHost* pnhh = NULL;
  4695. ARPFrame* paf = NULL;
  4696. Element* pe = NULL;
  4697. RECT rect;
  4698. WCHAR szTemp[1024];
  4699. // DirectUI init process
  4700. hr = InitProcess();
  4701. if (FAILED(hr))
  4702. goto Failure;
  4703. // Register classes
  4704. hr = ARPFrame::Register();
  4705. if (FAILED(hr))
  4706. goto Failure;
  4707. hr = ARPItem::Register();
  4708. if (FAILED(hr))
  4709. goto Failure;
  4710. hr = ARPHelp::Register();
  4711. if (FAILED(hr))
  4712. goto Failure;
  4713. hr = ARPSupportItem::Register();
  4714. if (FAILED(hr))
  4715. goto Failure;
  4716. hr = ARPSelector::Register();
  4717. if (FAILED(hr))
  4718. goto Failure;
  4719. hr = ClientPicker::Register();
  4720. if (FAILED(hr))
  4721. goto Failure;
  4722. hr = AutoButton::Register();
  4723. if (FAILED(hr))
  4724. goto Failure;
  4725. hr = ClientBlock::Register();
  4726. if (FAILED(hr))
  4727. goto Failure;
  4728. hr = Expandable::Register();
  4729. if (FAILED(hr))
  4730. goto Failure;
  4731. hr = Expando::Register();
  4732. if (FAILED(hr))
  4733. goto Failure;
  4734. hr = Clipper::Register();
  4735. if (FAILED(hr))
  4736. goto Failure;
  4737. hr = GradientLine::Register();
  4738. if (FAILED(hr))
  4739. goto Failure;
  4740. hr = BigElement::Register();
  4741. if (FAILED(hr))
  4742. goto Failure;
  4743. // DirectUI init thread
  4744. hr = InitThread();
  4745. if (FAILED(hr))
  4746. goto Failure;
  4747. hr = CoInitialize(NULL);
  4748. if (FAILED(hr))
  4749. goto Failure;
  4750. Element::StartDefer();
  4751. // Create host
  4752. LoadStringW(g_hinst, IDS_ARPTITLE, szTemp, DUIARRAYSIZE(szTemp));
  4753. BestFitOnDesktop(&rect);
  4754. hr = NativeHWNDHost::Create(szTemp, hWnd, LoadIcon(g_hinst, MAKEINTRESOURCE(IDI_CPLICON)), rect.left, rect.top, rect.right, rect.bottom, WS_EX_APPWINDOW, WS_OVERLAPPEDWINDOW, 0, &pnhh);
  4755. if (FAILED(hr))
  4756. goto Failure;
  4757. hr = ARPFrame::Create(pnhh, true, (Element**)&paf);
  4758. if (FAILED(hr))
  4759. goto Failure;
  4760. // Load resources
  4761. ARPParser::Create(paf, IDR_ARP, g_hinst, ARPParseError, &pParser);
  4762. if (!pParser || pParser->WasParseError())
  4763. goto Failure;
  4764. pParser->CreateElement(L"main", paf, &pe);
  4765. if (pe && // Fill contents using substitution
  4766. paf->Setup(pParser, nPage)) // Set ARPFrame state (incluing ID initialization)
  4767. {
  4768. // Set visible and host
  4769. paf->SetVisible(true);
  4770. pnhh->Host(paf);
  4771. Element::EndDefer();
  4772. // Do initial show
  4773. pnhh->ShowWindow();
  4774. Element* peClose = ((ARPFrame*)pe)->FallbackFocus();
  4775. if (peClose)
  4776. {
  4777. peClose->SetKeyFocus();
  4778. }
  4779. if (!paf->IsChangeRestricted())
  4780. {
  4781. paf->UpdateInstalledItems();
  4782. }
  4783. // Pump messages
  4784. MSG msg;
  4785. bool fDispatch = true;
  4786. while (GetMessageW(&msg, 0, 0, 0) != 0)
  4787. {
  4788. // Check for destruction of top-level window (always async)
  4789. if (msg.hwnd == pnhh->GetHWND() && msg.message == NHHM_ASYNCDESTROY)
  4790. {
  4791. // Async destroy requested, clean up secondary threads
  4792. // Signal that secondary threads should complete as soon as possible
  4793. // Any requests from secondary threads will be ignored
  4794. // No more secondary threads will be allowed to start
  4795. g_fRun = false;
  4796. // Hide window, some threads may need more time to exit normally
  4797. pnhh->HideWindow();
  4798. // Don't dispatch this one
  4799. if (!g_fAppShuttingDown)
  4800. fDispatch = false;
  4801. }
  4802. // Check for pending threads
  4803. if (!g_fRun)
  4804. {
  4805. if (!ARPFrame::htPopulateInstalledItemList &&
  4806. !ARPFrame::htPopulateAndRenderOCSetupItemList &&
  4807. !ARPFrame::htPopulateAndRenderPublishedItemList)
  4808. {
  4809. if (!g_fAppShuttingDown)
  4810. {
  4811. // Done, reissue async destroy
  4812. DUITrace(">> App shutting down, async destroying main window\n");
  4813. g_fAppShuttingDown = true;
  4814. pnhh->DestroyWindow();
  4815. }
  4816. }
  4817. }
  4818. if (fDispatch)
  4819. {
  4820. TranslateMessage(&msg);
  4821. DispatchMessageW(&msg);
  4822. }
  4823. else
  4824. fDispatch = true;
  4825. }
  4826. // paf will be deleted by native HWND host when destroyed
  4827. }
  4828. else
  4829. Element::EndDefer();
  4830. Failure:
  4831. if (pnhh)
  4832. {
  4833. if (pnhh->GetHWND())
  4834. {
  4835. // In the error case we didn't destroy the window cleanly, so
  4836. // we need to do it viciously. Cannot use pnhh->DestroyWindow()
  4837. // because that defers the destroy but we need it to happen now.
  4838. DestroyWindow(pnhh->GetHWND());
  4839. }
  4840. pnhh->Destroy();
  4841. }
  4842. if (pParser)
  4843. pParser->Destroy();
  4844. CoUninitialize();
  4845. UnInitThread();
  4846. UnInitProcess();
  4847. return 0;
  4848. }
  4849. DWORD _cdecl ARPIsRestricted(LPCWSTR pszPolicy)
  4850. {
  4851. return SHGetRestriction(NULL, L"Uninstall", pszPolicy);
  4852. }
  4853. bool _cdecl ARPIsOnDomain()
  4854. {
  4855. // NOTE: assume it's on the domain
  4856. bool bRet = true;
  4857. LPWSTR pszDomain;
  4858. NETSETUP_JOIN_STATUS nsjs;
  4859. if (NERR_Success == NetGetJoinInformation(NULL, &pszDomain, &nsjs))
  4860. {
  4861. if (nsjs != NetSetupDomainName)
  4862. bRet = FALSE;
  4863. NetApiBufferFree(pszDomain);
  4864. }
  4865. return bRet;
  4866. }
  4867. ////////////////////////////////////////////////////////
  4868. // Async ARP item population thread
  4869. ////////////////////////////////////////////////////////
  4870. // Query system and enumerate installed apps
  4871. HRESULT BuildPublishedAppArray(IEnumPublishedApps *penum, HDSA *phdsaPubApps);
  4872. HRESULT InstallPublishedAppArray(ARPFrame *paf, HDSA hdsaPubApps, UINT *piCount);
  4873. HRESULT InsertPubAppInPubAppArray(HDSA hdsa, IPublishedApp *ppa);
  4874. HRESULT GetPubAppName(IPublishedApp *ppa, LPWSTR *ppszName);
  4875. int CALLBACK DestroyPublishedAppArrayEntry(void *p, void *pData);
  4876. DWORD WINAPI PopulateAndRenderPublishedItemList(void* paf)
  4877. {
  4878. DUITrace(">> Thread 'htPopulateAndRenderPublishedItemList' STARTED.\n");
  4879. HRESULT hr;
  4880. UINT iCount = 0;
  4881. IShellAppManager* pisam = NULL;
  4882. IEnumPublishedApps* piepa = NULL;
  4883. IPublishedApp* pipa = NULL;
  4884. HDCONTEXT hctx = NULL;
  4885. // Initialize
  4886. HRESULT hrOle = CoInitialize(NULL);
  4887. INITGADGET ig;
  4888. ZeroMemory(&ig, sizeof(ig));
  4889. ig.cbSize = sizeof(ig);
  4890. ig.nThreadMode = IGTM_MULTIPLE;
  4891. ig.nMsgMode = IGMM_ADVANCED;
  4892. ig.hctxShare = NULL;
  4893. hctx = InitGadgets(&ig);
  4894. if (hctx == NULL) {
  4895. goto Cleanup;
  4896. }
  4897. // Create shell manager
  4898. hr = CoCreateInstance(__uuidof(ShellAppManager), NULL, CLSCTX_INPROC_SERVER, __uuidof(IShellAppManager), (void**)&pisam);
  4899. HRCHK(hr);
  4900. if (!((ARPFrame*)paf)->GetPublishedComboFilled())
  4901. {
  4902. // Get the list of categories
  4903. SHELLAPPCATEGORYLIST* psacl = ((ARPFrame*)paf)->GetShellAppCategoryList();
  4904. if (psacl == NULL)
  4905. {
  4906. psacl = new SHELLAPPCATEGORYLIST;
  4907. }
  4908. if (psacl == NULL)
  4909. {
  4910. goto Cleanup;
  4911. }
  4912. else
  4913. {
  4914. ((ARPFrame*)paf)->SetShellAppCategoryList(psacl);
  4915. }
  4916. hr = pisam->GetPublishedAppCategories(psacl);
  4917. ((ARPFrame*)paf)->PopulateCategoryCombobox();
  4918. ((ARPFrame*)paf)->SetPublishedComboFilled(true);
  4919. }
  4920. hr = pisam->EnumPublishedApps(((ARPFrame*)paf)->GetCurrentPublishedCategory(), &piepa);
  4921. HRCHK(hr);
  4922. HDSA hdsaPubApps = NULL;
  4923. hr = BuildPublishedAppArray(piepa, &hdsaPubApps);
  4924. HRCHK(hr);
  4925. hr = InstallPublishedAppArray((ARPFrame *)paf, hdsaPubApps, &iCount);
  4926. HRCHK(hr);
  4927. if (iCount == 0)
  4928. {
  4929. ((ARPFrame*)paf)->FeedbackEmptyPublishedList();
  4930. }
  4931. Cleanup:
  4932. if (NULL != hdsaPubApps)
  4933. {
  4934. DSA_DestroyCallback(hdsaPubApps, DestroyPublishedAppArrayEntry, NULL);
  4935. hdsaPubApps = NULL;
  4936. }
  4937. if (paf)
  4938. {
  4939. ((ARPFrame*)paf)->OnPublishedListComplete();
  4940. ((ARPFrame*)paf)->SetPublishedListFilled(true);
  4941. }
  4942. if (pisam)
  4943. pisam->Release();
  4944. if (piepa)
  4945. piepa->Release();
  4946. if (hctx)
  4947. DeleteHandle(hctx);
  4948. if (SUCCEEDED(hrOle))
  4949. {
  4950. CoUninitialize();
  4951. }
  4952. // Thread is done
  4953. ARPFrame::htPopulateAndRenderPublishedItemList = NULL;
  4954. // Information primary thread that this worker is complete
  4955. PostMessage(((ARPFrame*)paf)->GetHWND(), WM_ARPWORKERCOMPLETE, 0, 0);
  4956. DUITrace(">> Thread 'htPopulateAndRenderPublishedItemList' DONE.\n");
  4957. return 0;
  4958. }
  4959. // ----------------------------------------------------------------------------
  4960. // Handling published apps with duplicate names
  4961. // ----------------------------------------------------------------------------
  4962. //
  4963. // Entry in dynamic array of published app items.
  4964. // Entries with duplicate application names must be identifed
  4965. // in the UI by appending the applicable publishing source name
  4966. // to the display name of the application. In order to do this,
  4967. // we need to assemble all of the published entries in a sorted
  4968. // array then mark as such those that have duplicate names.
  4969. // When the array items are added to the ARP frame, the items
  4970. // marked 'duplicate' have their publisher's name appended to
  4971. // their application name.
  4972. //
  4973. struct PubItemListEntry
  4974. {
  4975. IPublishedApp *ppa; // The published app object.
  4976. bool bDuplicateName; // Does it have a duplicate name?
  4977. };
  4978. //
  4979. // Build the dynamic array of app/duplicate information.
  4980. // One entry for each published app. If this function succeeds,
  4981. // the caller is responsible for destroying the returnd DSA.
  4982. //
  4983. HRESULT
  4984. BuildPublishedAppArray(
  4985. IEnumPublishedApps *penum,
  4986. HDSA *phdsaPubApps
  4987. )
  4988. {
  4989. ASSERT(NULL != penum);
  4990. ASSERT(NULL != phdsaPubApps);
  4991. HRESULT hr = S_OK;
  4992. //
  4993. // Create a large DSA so that we minimize resizing.
  4994. //
  4995. HDSA hdsa = DSA_Create(sizeof(PubItemListEntry), 512);
  4996. if (NULL != hdsa)
  4997. {
  4998. IPublishedApp *ppa;
  4999. while(g_fRun)
  5000. {
  5001. hr = THR(penum->Next(&ppa));
  5002. if (S_OK == hr)
  5003. {
  5004. //
  5005. // Ignore any errors related to a specific published app.
  5006. //
  5007. THR(InsertPubAppInPubAppArray(hdsa, ppa));
  5008. ppa->Release();
  5009. }
  5010. else
  5011. {
  5012. break;
  5013. }
  5014. }
  5015. if (FAILED(hr))
  5016. {
  5017. DSA_DestroyCallback(hdsa, DestroyPublishedAppArrayEntry, NULL);
  5018. hdsa = NULL;
  5019. }
  5020. }
  5021. else
  5022. {
  5023. hr = E_OUTOFMEMORY;
  5024. }
  5025. ASSERT(FAILED(hr) || NULL != hdsa);
  5026. *phdsaPubApps = hdsa;
  5027. return THR(hr);
  5028. }
  5029. //
  5030. // Retrieve the application name string for a given published app.
  5031. // If this function succeeds, the caller is responsible for freeing
  5032. // the name string by using SHFree.
  5033. //
  5034. HRESULT
  5035. GetPubAppName(
  5036. IPublishedApp *ppa,
  5037. LPWSTR *ppszName
  5038. )
  5039. {
  5040. ASSERT(NULL != ppa);
  5041. ASSERT(NULL != ppszName);
  5042. APPINFODATA aid;
  5043. aid.cbSize = sizeof(aid);
  5044. aid.dwMask = AIM_DISPLAYNAME;
  5045. *ppszName = NULL;
  5046. HRESULT hr = THR(ppa->GetAppInfo(&aid));
  5047. if (SUCCEEDED(hr))
  5048. {
  5049. if (AIM_DISPLAYNAME & aid.dwMask)
  5050. {
  5051. *ppszName = aid.pszDisplayName;
  5052. }
  5053. else
  5054. {
  5055. hr = E_FAIL;
  5056. }
  5057. }
  5058. return THR(hr);
  5059. }
  5060. //
  5061. // Insert a published app into the published app array.
  5062. // Upon return, the dynamic array is sorted by published app name
  5063. // and all duplicate entries are marked with their bDuplicateName
  5064. // member set to 'true'.
  5065. //
  5066. HRESULT
  5067. InsertPubAppInPubAppArray(
  5068. HDSA hdsa,
  5069. IPublishedApp *ppa
  5070. )
  5071. {
  5072. ASSERT(NULL != hdsa);
  5073. ASSERT(NULL != ppa);
  5074. LPWSTR pszAppName;
  5075. HRESULT hr = THR(GetPubAppName(ppa, &pszAppName));
  5076. if (SUCCEEDED(hr))
  5077. {
  5078. //
  5079. // Create the new entry. We'll addref the COM pointer
  5080. // only after the item is successfully inserted into the array.
  5081. //
  5082. PubItemListEntry entryNew = { ppa, false };
  5083. //
  5084. // Find the insertion point so that the array is
  5085. // sorted by app name.
  5086. //
  5087. const int cEntries = DSA_GetItemCount(hdsa);
  5088. int iInsertHere = 0; // Insertion point.
  5089. PubItemListEntry *pEntry = NULL;
  5090. for (iInsertHere = 0; iInsertHere < cEntries; iInsertHere++)
  5091. {
  5092. pEntry = (PubItemListEntry *)DSA_GetItemPtr(hdsa, iInsertHere);
  5093. TBOOL(NULL != pEntry);
  5094. if (NULL != pEntry)
  5095. {
  5096. LPWSTR psz;
  5097. hr = THR(GetPubAppName(pEntry->ppa, &psz));
  5098. if (SUCCEEDED(hr))
  5099. {
  5100. int iCompare = lstrcmpi(psz, pszAppName);
  5101. SHFree(psz);
  5102. psz = NULL;
  5103. if (0 <= iCompare)
  5104. {
  5105. //
  5106. // This is the insertion point.
  5107. //
  5108. if (0 == iCompare)
  5109. {
  5110. //
  5111. // This entry has the same name.
  5112. //
  5113. entryNew.bDuplicateName = true;
  5114. pEntry->bDuplicateName = true;
  5115. }
  5116. break;
  5117. }
  5118. }
  5119. }
  5120. }
  5121. //
  5122. // Now mark all other duplicates. Note that if the entry
  5123. // currently at the insertion point is a duplicate of the
  5124. // entry we're inserting, we've already marked it as a duplicate
  5125. // above. Therefore, we can start with the next entry.
  5126. //
  5127. for (int i = iInsertHere + 1; i < cEntries; i++)
  5128. {
  5129. pEntry = (PubItemListEntry *)DSA_GetItemPtr(hdsa, i);
  5130. TBOOL(NULL != pEntry);
  5131. if (NULL != pEntry)
  5132. {
  5133. LPWSTR psz;
  5134. hr = THR(GetPubAppName(pEntry->ppa, &psz));
  5135. if (SUCCEEDED(hr))
  5136. {
  5137. int iCompare = lstrcmpi(psz, pszAppName);
  5138. SHFree(psz);
  5139. psz = NULL;
  5140. //
  5141. // Assert that the array is sorted alphabetically.
  5142. //
  5143. ASSERT(0 <= iCompare);
  5144. if (0 == iCompare)
  5145. {
  5146. //
  5147. // Yep, another duplicate.
  5148. //
  5149. pEntry->bDuplicateName = true;
  5150. }
  5151. else
  5152. {
  5153. break; // No need to look further.
  5154. }
  5155. }
  5156. }
  5157. }
  5158. //
  5159. // Insert the new item.
  5160. //
  5161. if (-1 != DSA_InsertItem(hdsa, iInsertHere, &entryNew))
  5162. {
  5163. entryNew.ppa->AddRef();
  5164. }
  5165. else
  5166. {
  5167. hr = E_OUTOFMEMORY;
  5168. }
  5169. SHFree(pszAppName);
  5170. }
  5171. return THR(hr);
  5172. }
  5173. //
  5174. // Given a DSA of application/duplicate-flag pairs, install
  5175. // the items in the ARP frame.
  5176. //
  5177. HRESULT
  5178. InstallPublishedAppArray(
  5179. ARPFrame *paf,
  5180. HDSA hdsaPubApps,
  5181. UINT *piCount // optional. Can be NULL.
  5182. )
  5183. {
  5184. ASSERT(NULL != paf);
  5185. ASSERT(NULL != hdsaPubApps);
  5186. int cEntries = DSA_GetItemCount(hdsaPubApps);
  5187. paf->SetPublishedItemCount(cEntries);
  5188. UINT iCount = 0;
  5189. for (int i = 0; i < cEntries && g_fRun; i++)
  5190. {
  5191. PubItemListEntry *pEntry = (PubItemListEntry *)DSA_GetItemPtr(hdsaPubApps, i);
  5192. TBOOL(NULL != pEntry);
  5193. if (NULL != pEntry)
  5194. {
  5195. //
  5196. // Unfortunately, InsertPublishedItem() doesn't return a value.
  5197. //
  5198. paf->InsertPublishedItem(pEntry->ppa, pEntry->bDuplicateName);
  5199. iCount++;
  5200. }
  5201. }
  5202. if (NULL != piCount)
  5203. {
  5204. *piCount = iCount;
  5205. }
  5206. return S_OK;
  5207. }
  5208. //
  5209. // Callback for destroying the DSA of application/duplicate-flag pairs.
  5210. // Need to release the IPublishedApp ptr for each entry.
  5211. //
  5212. int CALLBACK
  5213. DestroyPublishedAppArrayEntry(
  5214. void *p,
  5215. void *pData
  5216. )
  5217. {
  5218. PubItemListEntry *pEntry = (PubItemListEntry *)p;
  5219. ASSERT(NULL != pEntry && NULL != pEntry->ppa);
  5220. ATOMICRELEASE(pEntry->ppa);
  5221. return 1;
  5222. }
  5223. DWORD WINAPI PopulateAndRenderOCSetupItemList(void* paf)
  5224. {
  5225. DUITrace(">> Thread 'htPopulateAndRenderOCSetupItemList' STARTED.\n");
  5226. HDCONTEXT hctx = NULL;
  5227. INITGADGET ig;
  5228. ZeroMemory(&ig, sizeof(ig));
  5229. ig.cbSize = sizeof(ig);
  5230. ig.nThreadMode = IGTM_MULTIPLE;
  5231. ig.nMsgMode = IGMM_ADVANCED;
  5232. ig.hctxShare = NULL;
  5233. hctx = InitGadgets(&ig);
  5234. if (hctx == NULL) {
  5235. goto Cleanup;
  5236. }
  5237. // Create an object that enums the OCSetup items
  5238. COCSetupEnum * pocse = new COCSetupEnum;
  5239. if (pocse)
  5240. {
  5241. if (pocse->EnumOCSetupItems())
  5242. {
  5243. COCSetupApp* pocsa;
  5244. while (g_fRun && pocse->Next(&pocsa))
  5245. {
  5246. APPINFODATA ai = {0};
  5247. ai.cbSize = sizeof(ai);
  5248. ai.dwMask = AIM_DISPLAYNAME;
  5249. if ( pocsa->GetAppInfo(&ai) && (lstrlen(ai.pszDisplayName) > 0) )
  5250. {
  5251. //
  5252. // InsertOCSetupItem doesn't return a status value
  5253. // so we have no way of knowing if the item was
  5254. // added to ARP or not. So... we have no way of knowing
  5255. // if we should delete it to prevent a leak.
  5256. // I've added code to ARPFrame::OnInvoke to delete
  5257. // the pocsa object if it cannot be added to ARP.
  5258. // [brianau - 2/27/01]
  5259. //
  5260. // Insert item
  5261. ((ARPFrame*)paf)->InsertOCSetupItem(pocsa);
  5262. }
  5263. else
  5264. {
  5265. delete pocsa;
  5266. pocsa = NULL;
  5267. }
  5268. }
  5269. }
  5270. delete pocse;
  5271. pocse = NULL;
  5272. }
  5273. Cleanup:
  5274. if (hctx)
  5275. DeleteHandle(hctx);
  5276. // Thread is done
  5277. ARPFrame::htPopulateAndRenderOCSetupItemList = NULL;
  5278. // Information primary thread that this worker is complete
  5279. PostMessage(((ARPFrame*)paf)->GetHWND(), WM_ARPWORKERCOMPLETE, 0, 0);
  5280. DUITrace(">> Thread 'htPopulateAndRenderOCSetupItemList' DONE.\n");
  5281. return 0;
  5282. }
  5283. DWORD WINAPI PopulateInstalledItemList(void* paf)
  5284. {
  5285. DUITrace(">> Thread 'htPopulateInstalledItemList' STARTED.\n");
  5286. HRESULT hr;
  5287. IShellAppManager* pisam = NULL;
  5288. IEnumInstalledApps* pieia = NULL;
  5289. IInstalledApp* piia = NULL;
  5290. DWORD dwAppCount = 0;
  5291. APPINFODATA aid = {0};
  5292. HDCONTEXT hctx = NULL;
  5293. // Initialize
  5294. CoInitialize(NULL);
  5295. INITGADGET ig;
  5296. ZeroMemory(&ig, sizeof(ig));
  5297. ig.cbSize = sizeof(ig);
  5298. ig.nThreadMode = IGTM_MULTIPLE;
  5299. ig.nMsgMode = IGMM_ADVANCED;
  5300. ig.hctxShare = NULL;
  5301. hctx = InitGadgets(&ig);
  5302. if (hctx == NULL) {
  5303. goto Cleanup;
  5304. }
  5305. aid.cbSize = sizeof(APPINFODATA);
  5306. aid.dwMask = AIM_DISPLAYNAME | AIM_VERSION | AIM_PUBLISHER | AIM_PRODUCTID |
  5307. AIM_REGISTEREDOWNER | AIM_REGISTEREDCOMPANY | AIM_SUPPORTURL |
  5308. AIM_SUPPORTTELEPHONE | AIM_HELPLINK | AIM_INSTALLLOCATION | AIM_INSTALLDATE |
  5309. AIM_COMMENTS | AIM_IMAGE | AIM_READMEURL | AIM_CONTACT | AIM_UPDATEINFOURL;
  5310. // Create shell manager
  5311. hr = CoCreateInstance(__uuidof(ShellAppManager), NULL, CLSCTX_INPROC_SERVER, __uuidof(IShellAppManager), (void**)&pisam);
  5312. HRCHK(hr);
  5313. hr = pisam->EnumInstalledApps(&pieia);
  5314. HRCHK(hr);
  5315. // Count installed apps, IShellAppManager::GetNumberofInstalledApps() not impl
  5316. while (g_fRun)
  5317. {
  5318. hr = pieia->Next(&piia);
  5319. if (hr == S_FALSE) // Done with enumeration
  5320. break;
  5321. dwAppCount++;
  5322. }
  5323. // IEnumInstalledApps::Reset() doesn't work
  5324. pieia->Release();
  5325. pieia = NULL;
  5326. hr = pisam->EnumInstalledApps(&pieia);
  5327. HRCHK(hr);
  5328. // Set app count in frame
  5329. ((ARPFrame*)paf)->SetInstalledItemCount(dwAppCount);
  5330. // Enumerate apps
  5331. while (g_fRun)
  5332. {
  5333. hr = pieia->Next(&piia);
  5334. if (hr == S_FALSE) // Done with enumeration
  5335. break;
  5336. // Insert item
  5337. if (piia != NULL)
  5338. {
  5339. ((ARPFrame*)paf)->InsertInstalledItem(piia);
  5340. }
  5341. }
  5342. // Passing NULL to InsertInstalledItem signals ARP that it is finished
  5343. // inserting items and should now display the list.
  5344. if (dwAppCount > 0)
  5345. {
  5346. ((ARPFrame*)paf)->InsertInstalledItem(NULL);
  5347. }
  5348. Cleanup:
  5349. if (pisam)
  5350. pisam->Release();
  5351. if (pieia)
  5352. pieia->Release();
  5353. if (hctx)
  5354. DeleteHandle(hctx);
  5355. CoUninitialize();
  5356. if (g_fRun)
  5357. ((ARPFrame*)paf)->FlushWorkingSet();
  5358. // Thread is done
  5359. ARPFrame::htPopulateInstalledItemList = NULL;
  5360. // Information primary thread that this worker is complete
  5361. PostMessage(((ARPFrame*)paf)->GetHWND(), WM_ARPWORKERCOMPLETE, 0, 0);
  5362. DUITrace(">> Thread 'htPopulateInstalledItemList' DONE.\n");
  5363. return 0;
  5364. }
  5365. // Sorting
  5366. int __cdecl CompareElementDataName(const void* pA, const void* pB)
  5367. {
  5368. Value* pvName1 = NULL;
  5369. Value* pvName2 = NULL;
  5370. LPCWSTR pszName1 = NULL;
  5371. LPCWSTR pszName2 = NULL;
  5372. Element *pe;
  5373. if (NULL != pA)
  5374. {
  5375. pe = (*(ARPItem**)pA)->FindDescendent(ARPItem::_idTitle);
  5376. if (NULL != pe)
  5377. {
  5378. pszName1 = pe->GetContentString(&pvName1);
  5379. }
  5380. }
  5381. if (NULL != pB)
  5382. {
  5383. pe = (*(ARPItem**)pB)->FindDescendent(ARPItem::_idTitle);
  5384. if (NULL != pe)
  5385. {
  5386. pszName2 = pe->GetContentString(&pvName2);
  5387. }
  5388. }
  5389. static const int rgResults[2][2] = {
  5390. /* pszName2 == NULL, pszName2 != NULL */
  5391. /* pszName1 == NULL */ { 0, 1 },
  5392. /* pszName1 != NULL */ { -1, 2 }
  5393. };
  5394. int iResult = rgResults[int(NULL != pszName1)][int(NULL != pszName2)];
  5395. if (2 == iResult)
  5396. {
  5397. iResult = StrCmpW(pszName1, pszName2);
  5398. }
  5399. if (NULL != pvName1)
  5400. {
  5401. pvName1->Release();
  5402. }
  5403. if (NULL != pvName2)
  5404. {
  5405. pvName2->Release();
  5406. }
  5407. return iResult;
  5408. }
  5409. int __cdecl CompareElementDataSize(const void* pA, const void* pB)
  5410. {
  5411. ULONGLONG ull1 = (*(ARPItem**)pA)->_ullSize;
  5412. ULONGLONG ull2 = (*(ARPItem**)pB)->_ullSize;
  5413. if (!IsValidSize(ull1))
  5414. ull1 = 0;
  5415. if (!IsValidSize(ull2))
  5416. ull2 = 0;
  5417. // Big apps come before smaller apps
  5418. if (ull1 > ull2)
  5419. return -1;
  5420. else if (ull1 < ull2)
  5421. return 1;
  5422. return CompareElementDataName(pA, pB);
  5423. }
  5424. int __cdecl CompareElementDataFreq(const void* pA, const void* pB)
  5425. {
  5426. // Rarely used apps come before frequently used apps. Blank
  5427. // (unknown) apps go last. Unknown apps are -1, so those sort
  5428. // to the bottom if we simply compare unsigned values.
  5429. UINT u1 = (UINT)(*(ARPItem**)pA)->_iTimesUsed;
  5430. UINT u2 = (UINT)(*(ARPItem**)pB)->_iTimesUsed;
  5431. if (u1 < u2)
  5432. return -1;
  5433. else if (u1 > u2)
  5434. return 1;
  5435. return CompareElementDataName(pA, pB);
  5436. }
  5437. int __cdecl CompareElementDataLast(const void* pA, const void* pB)
  5438. {
  5439. FILETIME ft1 = (*(ARPItem**)pA)->_ftLastUsed;
  5440. FILETIME ft2 = (*(ARPItem**)pB)->_ftLastUsed;
  5441. BOOL bTime1 = IsValidFileTime(ft1);
  5442. BOOL bTime2 = IsValidFileTime(ft2);
  5443. if (!bTime1 || !bTime2)
  5444. {
  5445. if (bTime1)
  5446. return -1;
  5447. if (bTime2)
  5448. return 1;
  5449. // else they're both not set -- use name
  5450. }
  5451. else
  5452. {
  5453. LONG diff = CompareFileTime(&ft1, &ft2);
  5454. if (diff)
  5455. return diff;
  5456. }
  5457. return CompareElementDataName(pA, pB);
  5458. }
  5459. //
  5460. // Stuff imported from other modules which have been deleted.
  5461. //
  5462. const TCHAR c_szStubWindowClass[] = TEXT("Add/Remove Stub Window");
  5463. HWND _CreateTransparentStubWindow(HWND hwndParent)
  5464. {
  5465. WNDCLASS wc;
  5466. RECT rc = {0};
  5467. if (hwndParent)
  5468. {
  5469. RECT rcParent = {0};
  5470. GetWindowRect(hwndParent, &rcParent);
  5471. rc.left = (rcParent.left + RECTWIDTH(rcParent)) / 2;
  5472. rc.top = (rcParent.top + RECTHEIGHT(rcParent)) / 2;
  5473. }
  5474. else
  5475. {
  5476. rc.left = CW_USEDEFAULT;
  5477. rc.top = CW_USEDEFAULT;
  5478. }
  5479. if (!GetClassInfo(HINST_THISDLL, c_szStubWindowClass, &wc))
  5480. {
  5481. wc.style = 0;
  5482. wc.lpfnWndProc = DefWindowProc;
  5483. wc.cbClsExtra = 0;
  5484. wc.cbWndExtra = SIZEOF(DWORD) * 2;
  5485. wc.hInstance = HINST_THISDLL;
  5486. wc.hIcon = NULL;
  5487. wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  5488. wc.hbrBackground = (HBRUSH)GetStockObject (WHITE_BRUSH);
  5489. wc.lpszMenuName = NULL;
  5490. wc.lpszClassName = c_szStubWindowClass;
  5491. RegisterClass(&wc);
  5492. }
  5493. // WS_EX_APPWINDOW makes this show up in ALT+TAB, but not the tray.
  5494. return CreateWindowEx(WS_EX_TRANSPARENT, c_szStubWindowClass, TEXT(""), WS_POPUP | WS_VISIBLE, rc.left,
  5495. rc.top, 1, 1, hwndParent, NULL, HINST_THISDLL, NULL);
  5496. }