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.

591 lines
15 KiB

  1. // CCtl.CPP
  2. //
  3. // Implementation of the control
  4. //
  5. // Created 17-Apr-98 [JonT]
  6. #include "priv.h"
  7. #include "resource.h"
  8. #include "cctl.h"
  9. #include "util.h"
  10. #include "dump.h" // for Dbg_* functions
  11. //--------------------------------------------------------------------
  12. //
  13. //
  14. // CARPCtl class
  15. //
  16. //
  17. //--------------------------------------------------------------------
  18. // ARPCtlEnumCB
  19. // Callback for EnumAppItems that adds the appdata item to
  20. // the array.
  21. void CALLBACK ARPCtlEnumCB(CAppData * pcad, LPARAM lParam)
  22. {
  23. ((CARPCtl *)lParam)->EnumCallback(pcad);
  24. }
  25. //--------------------------------------------------------------------
  26. // Methods
  27. // CARPCtl::EnumCallback
  28. // EnumAppItems callback for the ARPCtl.
  29. void CARPCtl::EnumCallback(CAppData * pcad)
  30. {
  31. switch (_dwEnum)
  32. {
  33. case ENUM_INSTALLED:
  34. case ENUM_PUBLISHED:
  35. case ENUM_OCSETUP:
  36. if (S_OK == _pmtxarray->AddItem(pcad, NULL))
  37. {
  38. _dwcItems++;
  39. TraceMsg(TF_CTL, "ARP: Added item \"%s\" to list", pcad->GetData()->pszDisplayName);
  40. // Fire the event saying the new row is ready.
  41. // Note that this has to be AFTER we increment so that
  42. // the ItemCount property will be correct at this point.
  43. Fire_OnRowReady(_dwcItems - 1);
  44. }
  45. break;
  46. case ENUM_CATEGORIES:
  47. if (S_OK == _pmtxarray->AddItem(pcad, NULL))
  48. {
  49. _dwcItems++;
  50. TraceMsg(TF_CTL, "ARP: Added item \"%s\" to list", pcad->GetCategory());
  51. // Fire the event saying the new row is ready.
  52. // Note that this has to be AFTER we increment so that
  53. // the ItemCount property will be correct at this point.
  54. Fire_OnRowReady(_dwcItems - 1);
  55. }
  56. break;
  57. }
  58. }
  59. // CARPCtl::InitData
  60. // Script tells the control to get data from the app management object
  61. // and which order to sort in.
  62. //
  63. // bstrEnum can be:
  64. // "installed" - enumerate currently installed apps.
  65. // "" - ditto.
  66. // "published" - enumerate published apps.
  67. // "categories" - enumerate published categories.
  68. STDMETHODIMP
  69. CARPCtl::InitData(
  70. BSTR bstrEnum,
  71. DWORD dwSortOrder
  72. )
  73. {
  74. HRESULT hres = S_FALSE;
  75. // Determine what we're enumerating
  76. _dwEnum = ENUM_INSTALLED; // default value
  77. if (0 == lstrcmpiW(bstrEnum, L"published"))
  78. _dwEnum = ENUM_PUBLISHED;
  79. else if (0 == lstrcmpiW(bstrEnum, L"categories"))
  80. _dwEnum = ENUM_CATEGORIES;
  81. else if (0 == lstrcmpiW(bstrEnum, L"ocsetup"))
  82. _dwEnum = ENUM_OCSETUP;
  83. // Load the app manager if we haven't already
  84. if (_pam == NULL)
  85. {
  86. if (FAILED(CoCreateInstance(CLSID_ShellAppManager, NULL,
  87. CLSCTX_INPROC, IID_IShellAppManager, (void**)&_pam)))
  88. {
  89. TraceMsg(TF_ERROR, "Couldn't instantiate ShellAppManager object");
  90. return S_FALSE;
  91. }
  92. }
  93. // Make sure the worker thread isn't already running. Stop it if it is.
  94. _workerthread.Kill();
  95. // If we already have a list, nuke it
  96. _FreeAppData();
  97. // Now create the new list
  98. _pmtxarray = new CMtxArray2(_dwEnum);
  99. if (_pmtxarray)
  100. {
  101. // Start enumerating items
  102. hres = EnumAppItems(_dwEnum, _pam, ARPCtlEnumCB, (LPARAM)this);
  103. // Did the enumeration succeed?
  104. if (SUCCEEDED(hres))
  105. {
  106. // Yes; tell the script we're done getting the synchronous data
  107. // This call is synchronous and does not return until the script
  108. // is finished responding. This seems like a bug in Trident.
  109. Fire_OnSyncDataReady();
  110. // We only get slow info for the installed apps
  111. if (ENUM_INSTALLED == _dwEnum)
  112. {
  113. // Create and kick off the worker thread
  114. hres = _workerthread.Initialize(SAFECAST(this, IWorkerEvent *), _pmtxarray);
  115. }
  116. }
  117. }
  118. // Can't return failure to script
  119. if (FAILED(hres))
  120. hres = S_FALSE;
  121. return hres;
  122. }
  123. // CARPCtl::MoveFirst
  124. // Script tells control to move to the first item in the list.
  125. // Returns false if there are no items.
  126. STDMETHODIMP
  127. CARPCtl::MoveFirst(
  128. BOOL* pbool
  129. )
  130. {
  131. // Set our current index to the start
  132. _dwCurrentIndex = 0;
  133. // Return TRUE iff we are pointing to a valid item
  134. *pbool = _dwCurrentIndex >= _dwcItems ? FALSE : TRUE;
  135. return S_OK;
  136. }
  137. // CARPCtl::MoveNext
  138. // Script tells control to move to the next item in the curren tlist.
  139. // Returns false if off the end of the list.
  140. STDMETHODIMP
  141. CARPCtl::MoveNext(
  142. BOOL* pbool
  143. )
  144. {
  145. _dwCurrentIndex++;
  146. // Return TRUE iff we are pointing to a valid item
  147. *pbool = _dwCurrentIndex >= _dwcItems ? FALSE : TRUE;
  148. return S_OK;
  149. }
  150. // CARPCtl::MoveTo
  151. // Tells the control to move to a specific item
  152. STDMETHODIMP
  153. CARPCtl::MoveTo(
  154. DWORD dwRecNum,
  155. BOOL* pbool
  156. )
  157. {
  158. // If they want to go past the end, fail it and don't move the pointer
  159. if (dwRecNum >= _dwcItems)
  160. {
  161. *pbool = FALSE;
  162. return S_OK;
  163. }
  164. // Update the pointer and return success
  165. _dwCurrentIndex = dwRecNum;
  166. *pbool = TRUE;
  167. return S_OK;
  168. }
  169. // CARPCtl::Exec
  170. // Tells the control to exec a command. The command may act
  171. // upon the current record.
  172. STDMETHODIMP
  173. CARPCtl::Exec(
  174. BSTR bstrCmd
  175. )
  176. {
  177. TraceMsg(TF_CTL, "(Ctl) Command (%ls) called", bstrCmd);
  178. #ifdef NOTYET
  179. // security check must pass before we could exec anything.
  180. if (!_fSecure)
  181. {
  182. TraceMsg(TF_CTL, "(Ctl) Security blocked Exec call");
  183. return S_FALSE; // scripting methods cannot return failure
  184. }
  185. #endif
  186. const static struct {
  187. LPCWSTR pszCmd;
  188. APPCMD appcmd;
  189. } s_rgCmds[] = {
  190. { L"install", APPCMD_INSTALL },
  191. { L"uninstall", APPCMD_UNINSTALL },
  192. { L"modify", APPCMD_MODIFY },
  193. { L"upgrade", APPCMD_UPGRADE },
  194. { L"repair", APPCMD_REPAIR },
  195. { L"generic install", APPCMD_GENERICINSTALL },
  196. { L"ntoptions", APPCMD_NTOPTIONS },
  197. { L"winupdate", APPCMD_WINUPDATE },
  198. };
  199. int i;
  200. APPCMD appcmd = APPCMD_UNKNOWN;
  201. for (i = 0; i < ARRAYSIZE(s_rgCmds); i++)
  202. {
  203. if (0 == StrCmpIW(bstrCmd, s_rgCmds[i].pszCmd))
  204. {
  205. appcmd = s_rgCmds[i].appcmd;
  206. break;
  207. }
  208. }
  209. switch (appcmd)
  210. {
  211. case APPCMD_INSTALL:
  212. case APPCMD_UNINSTALL:
  213. case APPCMD_MODIFY:
  214. case APPCMD_UPGRADE:
  215. case APPCMD_REPAIR:
  216. {
  217. CAppData * pappdata = _GetAppData(_dwCurrentIndex);
  218. if (pappdata)
  219. pappdata->DoCommand(appcmd);
  220. }
  221. break;
  222. case APPCMD_GENERICINSTALL:
  223. InstallAppFromFloppyOrCDROM(NULL);
  224. break;
  225. case APPCMD_NTOPTIONS:
  226. // command to invoke and OCMgr
  227. // "sysocmgr /x /i:%systemroot%\system32\sysoc.inf"
  228. TCHAR szInf[MAX_PATH];
  229. if (GetSystemDirectory(szInf, ARRAYSIZE(szInf)) && PathCombine(szInf, szInf, TEXT("sysoc.inf")))
  230. {
  231. TCHAR szParam[MAX_PATH];
  232. wsprintf(szParam, TEXT("/x /i:%s"), szInf);
  233. ShellExecute(NULL, NULL, TEXT("sysocmgr"), szParam, NULL, SW_SHOWDEFAULT);
  234. }
  235. break;
  236. case APPCMD_WINUPDATE:
  237. break;
  238. case APPCMD_UNKNOWN:
  239. TraceMsg(TF_ERROR, "(Ctl) Received invalid appcmd %ls", bstrCmd);
  240. break;
  241. }
  242. return S_OK;
  243. }
  244. // IWorkerEvent::FireOnDataReady
  245. // Called by worker thread when some data is ready.
  246. STDMETHODIMP
  247. CARPCtl::FireOnDataReady(
  248. LONG iRow
  249. )
  250. {
  251. Fire_OnAsyncDataReady(iRow);
  252. return S_OK;
  253. }
  254. // IWorkerEvent::FireOnFinished
  255. // Called by worker thread when it is complete.
  256. STDMETHODIMP
  257. CARPCtl::FireOnFinished(void)
  258. {
  259. return S_OK;
  260. }
  261. //--------------------------------------------------------------------
  262. // Properties
  263. // SIMPLE_PROPERTY_GET
  264. //
  265. // Defines a simple property get method so that we don't type the same
  266. // code over and over. It only works for strings copied from the APPINFODATA
  267. // structure.
  268. //
  269. // This keeps the code cleaned up. but doesn't help
  270. // with the code bloat, so a better approach would be great.
  271. #define SIMPLE_PROPERTY_GET(PropName) \
  272. STDMETHODIMP \
  273. CARPCtl::get_##PropName##(BSTR* pbstr) \
  274. { \
  275. USES_CONVERSION; \
  276. \
  277. if (_dwCurrentIndex >= _dwcItems) \
  278. return E_FAIL; \
  279. \
  280. CAppData * pappdata = _GetAppData(_dwCurrentIndex); \
  281. if (pappdata) \
  282. { \
  283. APPINFODATA * paidata = pappdata->GetData(); \
  284. \
  285. ASSERT(NULL == paidata->psz##PropName || IS_VALID_STRING_PTRW(paidata->psz##PropName, -1)); \
  286. \
  287. *pbstr = W2BSTR(paidata->psz##PropName); \
  288. } \
  289. else \
  290. *pbstr = NULL; \
  291. \
  292. return S_OK; \
  293. }
  294. // TODO: Since this is big code bloat, make sure we really need all these...
  295. SIMPLE_PROPERTY_GET(Version)
  296. SIMPLE_PROPERTY_GET(Publisher)
  297. SIMPLE_PROPERTY_GET(ProductID)
  298. SIMPLE_PROPERTY_GET(RegisteredOwner)
  299. SIMPLE_PROPERTY_GET(Language)
  300. SIMPLE_PROPERTY_GET(SupportUrl)
  301. SIMPLE_PROPERTY_GET(SupportTelephone)
  302. SIMPLE_PROPERTY_GET(HelpLink)
  303. SIMPLE_PROPERTY_GET(InstallLocation)
  304. SIMPLE_PROPERTY_GET(InstallSource)
  305. SIMPLE_PROPERTY_GET(InstallDate)
  306. SIMPLE_PROPERTY_GET(RequiredByPolicy)
  307. SIMPLE_PROPERTY_GET(Contact)
  308. // DisplayName
  309. // The display name of the item.
  310. STDMETHODIMP
  311. CARPCtl::get_DisplayName(BSTR* pbstr)
  312. {
  313. USES_CONVERSION;
  314. CAppData * pappdata;
  315. if (_dwCurrentIndex >= _dwcItems)
  316. return E_FAIL;
  317. pappdata = _GetAppData(_dwCurrentIndex);
  318. if (pappdata)
  319. {
  320. if (ENUM_CATEGORIES == _dwEnum)
  321. {
  322. *pbstr = W2BSTR(pappdata->GetCategory());
  323. }
  324. else
  325. {
  326. *pbstr = W2BSTR(pappdata->GetData()->pszDisplayName);
  327. }
  328. }
  329. else
  330. *pbstr = NULL;
  331. return S_OK;
  332. }
  333. // Size
  334. // The calculated size of the application. Returns "Unknown" if not available
  335. STDMETHODIMP
  336. CARPCtl::get_Size(BSTR* pbstr)
  337. {
  338. USES_CONVERSION;
  339. TCHAR szSize[256];
  340. ULONG ulSize = 0;
  341. LPTSTR WINAPI ShortSizeFormat(DWORD dw, LPTSTR szBuf);
  342. CAppData * pappdata;
  343. if (_dwCurrentIndex >= _dwcItems)
  344. return E_FAIL;
  345. // Get the size and truncate to a ULONG. If the app is bigger than 4G,
  346. // well, too bad.
  347. pappdata = _GetAppData(_dwCurrentIndex);
  348. if (pappdata)
  349. ulSize = (ULONG)pappdata->GetSlowData()->ullSize;
  350. // If the size is zero, return unknown, otherwise,
  351. // Use the shell32 function to make a nicely formatted size string
  352. if (ulSize == 0)
  353. LoadString(g_hinst, IDS_UNKNOWN, szSize, ARRAYSIZE(szSize));
  354. else
  355. ShortSizeFormat(ulSize, szSize);
  356. // Return as a BSTR
  357. *pbstr = W2BSTR(szSize);
  358. return S_OK;
  359. }
  360. // TimesUsed
  361. // Returns the number of times used for this item
  362. STDMETHODIMP
  363. CARPCtl::get_TimesUsed(BSTR* pbstr)
  364. {
  365. USES_CONVERSION;
  366. int ncUsed = 0;
  367. WCHAR szUsed[256];
  368. CAppData * pappdata;
  369. if (_dwCurrentIndex >= _dwcItems)
  370. return E_FAIL;
  371. pappdata = _GetAppData(_dwCurrentIndex);
  372. if (pappdata)
  373. ncUsed = pappdata->GetSlowData()->iTimesUsed;
  374. // Convert to a BSTR
  375. wsprintf(szUsed, TEXT("%d"), ncUsed);
  376. *pbstr = W2BSTR(szUsed);
  377. return S_OK;
  378. }
  379. // LastUsed
  380. // Returns last date the app was used
  381. STDMETHODIMP
  382. CARPCtl::get_LastUsed(BSTR* pbstr)
  383. {
  384. USES_CONVERSION;
  385. FILETIME ft = {0};
  386. WCHAR szDate[256];
  387. CAppData * pappdata;
  388. if (_dwCurrentIndex >= _dwcItems)
  389. return E_FAIL;
  390. pappdata = _GetAppData(_dwCurrentIndex);
  391. if (pappdata)
  392. ft = pappdata->GetSlowData()->ftLastUsed;
  393. // Convert to a BSTR
  394. FileTimeToDateTimeString(&ft, szDate, SIZECHARS(szDate));
  395. *pbstr = W2BSTR(szDate);
  396. return S_OK;
  397. }
  398. // Capability
  399. // Flags that indicate the possible actions that can
  400. // be performed on the item. See APPACTION_* flags.
  401. STDMETHODIMP
  402. CARPCtl::get_Capability(long * pVal)
  403. {
  404. CAppData * pappdata;
  405. if (_dwCurrentIndex >= _dwcItems)
  406. return E_FAIL;
  407. pappdata = _GetAppData(_dwCurrentIndex);
  408. if (pappdata)
  409. *pVal = pappdata->GetCapability();
  410. else
  411. *pVal = 0;
  412. return S_OK;
  413. }
  414. // ItemCount
  415. // Number of items in current list
  416. STDMETHODIMP
  417. CARPCtl::get_ItemCount(long * pVal)
  418. {
  419. *pVal = _dwcItems;
  420. return S_OK;
  421. }
  422. //--------------------------------------------------------------------
  423. // Object lifetime stuff
  424. // CARPCtl constructor
  425. CARPCtl::CARPCtl()
  426. {
  427. ASSERT(NULL == _pmtxarray);
  428. ASSERT(NULL == _pam);
  429. }
  430. // CARPCtl destructor
  431. CARPCtl::~CARPCtl()
  432. {
  433. // Kill the worker thread if it's still around
  434. _workerthread.Kill();
  435. // Free our contained object
  436. ATOMICRELEASE(_pam);
  437. // Clean up the application list
  438. _FreeAppData();
  439. }
  440. //--------------------------------------------------------------------
  441. // Private methods
  442. // CARPCtl::_GetAppData
  443. // Returns the appdata of the current record, or NULL if there
  444. // is no such record.
  445. CAppData *
  446. CARPCtl::_GetAppData(DWORD iItem)
  447. {
  448. CAppData * pappdata = NULL;
  449. if (_pmtxarray && iItem < _dwcItems)
  450. pappdata = _pmtxarray->GetAppData(iItem);
  451. return pappdata;
  452. }
  453. // CARPCtl::_FreeAppData
  454. // Frees all memory associated with the application
  455. void
  456. CARPCtl::_FreeAppData()
  457. {
  458. if (_pmtxarray)
  459. {
  460. delete _pmtxarray;
  461. _pmtxarray = NULL;
  462. }
  463. _dwcItems = 0;
  464. }