Source code of Windows XP (NT5)
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.

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