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.

903 lines
25 KiB

  1. // adcctl.cpp : Implementation of CADCCtl
  2. #include "priv.h"
  3. // Do not build this file if on Win9X or NT4
  4. #ifndef DOWNLEVEL_PLATFORM
  5. #include "adcctl.h"
  6. #include "shdguid.h"
  7. #include "shguidp.h"
  8. #include "util.h" // for InstallAppFromFloppy...
  9. #include "datasrc.h" // for CDataSrc_CreateInstance
  10. #include "dump.h"
  11. EXTERN_C BOOL bForceX86Env;
  12. // Declare the private GUIDs
  13. #include "initguid.h"
  14. #include "iface.h"
  15. #include "mshtml.h"
  16. /*-------------------------------------------------------------------------
  17. Purpose: Returns TRUE if the bstr is an empty string.
  18. */
  19. inline BOOL IsEmptyBSTR(BSTR bstr)
  20. {
  21. return bstr == NULL || bstr[0] == 0;
  22. }
  23. //---------------------------------------------------------------------------
  24. //
  25. //---------------------------------------------------------------------------
  26. BOOL CADCCtl::_IsMyComputerOnDomain()
  27. {
  28. // NOTE: assume it's on the domain
  29. BOOL bRet = TRUE;
  30. #if WINNT
  31. LPWSTR pszDomain;
  32. NETSETUP_JOIN_STATUS nsjs;
  33. if (NERR_Success == NetGetJoinInformation(NULL, &pszDomain, &nsjs))
  34. {
  35. if (nsjs != NetSetupDomainName)
  36. bRet = FALSE;
  37. NetApiBufferFree(pszDomain);
  38. }
  39. #endif
  40. return bRet;
  41. }
  42. // constructor
  43. CADCCtl::CADCCtl()
  44. {
  45. TraceMsg(TF_OBJLIFE, "(Ctl) creating");
  46. // This object cannot be stack-allocated
  47. ASSERT(NULL == _hwndTB);
  48. ASSERT(FALSE == _fInReset);
  49. ASSERT(FALSE == _fSecure);
  50. // We do this so comctl32.dll won't fail to create the DATETIME_PICKER
  51. // control in case we do "Add Later"
  52. INITCOMMONCONTROLSEX icex = {0};
  53. icex.dwSize = sizeof(icex);
  54. icex.dwICC = ICC_DATE_CLASSES;
  55. InitCommonControlsEx(&icex);
  56. _fOnDomain = _IsMyComputerOnDomain();
  57. // Set default sort values
  58. _cbstrSort = L"displayname";
  59. }
  60. // destructor
  61. CADCCtl::~CADCCtl()
  62. {
  63. TraceMsg(TF_OBJLIFE, "(Ctl) destroying");
  64. ATOMICRELEASE(_psam);
  65. _ReleaseAllMatrixObjects();
  66. _ReleaseAllEventBrokers();
  67. }
  68. //------------------------------------------------------------------------
  69. //
  70. // These set/get methods implement the control's properties,
  71. // copying values to and from class members. They perform no
  72. // other processing apart from argument validation.
  73. //
  74. //------------------------------------------------------------------------
  75. STDMETHODIMP CADCCtl::get_Dirty(VARIANT_BOOL * pbDirty)
  76. {
  77. *pbDirty = _fDirty ? VARIANT_TRUE : VARIANT_FALSE;
  78. return S_OK;
  79. }
  80. STDMETHODIMP CADCCtl::put_Dirty(VARIANT_BOOL bDirty)
  81. {
  82. // to its current value.
  83. _fDirty = (bDirty == VARIANT_TRUE) ? TRUE : FALSE;
  84. return S_OK;
  85. }
  86. STDMETHODIMP CADCCtl::get_Category(BSTR* pbstr)
  87. {
  88. *pbstr = _cbstrCategory.Copy();
  89. return *pbstr ? S_OK : E_OUTOFMEMORY;
  90. }
  91. STDMETHODIMP CADCCtl::put_Category(BSTR bstr)
  92. {
  93. if (NULL == (LPWSTR)_cbstrCategory || 0 != StrCmpIW(bstr, _cbstrCategory))
  94. {
  95. _cbstrCategory = bstr;
  96. _fCategoryChanged = TRUE;
  97. }
  98. return S_OK;
  99. }
  100. STDMETHODIMP CADCCtl::get_DefaultCategory(BSTR* pbstr)
  101. {
  102. WCHAR sz[64];
  103. ARPGetPolicyString(L"DefaultCategory", sz, SIZECHARS(sz));
  104. CComBSTR bstr(sz);
  105. *pbstr = bstr.Copy();
  106. return *pbstr ? S_OK : E_OUTOFMEMORY;
  107. }
  108. STDMETHODIMP CADCCtl::get_Sort(BSTR* pbstr)
  109. {
  110. *pbstr = _cbstrSort.Copy();
  111. return *pbstr ? S_OK : E_OUTOFMEMORY;
  112. }
  113. STDMETHODIMP CADCCtl::put_Sort(BSTR bstr)
  114. {
  115. _cbstrSort = bstr;
  116. return S_OK;
  117. }
  118. STDMETHODIMP CADCCtl::get_Forcex86(VARIANT_BOOL * pbForce)
  119. {
  120. *pbForce = VARIANT_FALSE;
  121. #ifdef WX86
  122. *pbForce = bForceX86Env ? VARIANT_TRUE : VARIANT_FALSE;
  123. #endif
  124. return S_OK;
  125. }
  126. STDMETHODIMP CADCCtl::put_Forcex86(VARIANT_BOOL bForce)
  127. {
  128. #ifdef WX86
  129. bForceX86Env = (bForce == VARIANT_TRUE) ? TRUE : FALSE;
  130. #else
  131. // nobody should be calling this if we are not under WX86
  132. ASSERT(0);
  133. #endif
  134. return S_OK;
  135. }
  136. // Property: ShowPostSetup
  137. // Returns TRUE if the Post Setup Page should be shown.
  138. STDMETHODIMP CADCCtl::get_ShowPostSetup(VARIANT_BOOL * pbShow)
  139. {
  140. // Only show the page if it is needed
  141. if (COCSetupEnum::s_OCSetupNeeded())
  142. *pbShow = VARIANT_TRUE;
  143. else
  144. *pbShow = VARIANT_FALSE;
  145. return S_OK;
  146. }
  147. STDMETHODIMP CADCCtl::get_OnDomain(VARIANT_BOOL * pbOnDomain)
  148. {
  149. *pbOnDomain = _fOnDomain ? VARIANT_TRUE : VARIANT_FALSE;
  150. return S_OK;
  151. }
  152. STDMETHODIMP CADCCtl::put_OnDomain(VARIANT_BOOL bOnDomain)
  153. {
  154. // to its current value.
  155. _fOnDomain = (bOnDomain == VARIANT_TRUE) ? TRUE : FALSE;
  156. return S_OK;
  157. }
  158. /*-------------------------------------------------------------------------
  159. Purpose: Creates the data source object. Also initiates the data enumeration.
  160. */
  161. HRESULT CADCCtl::_CreateMatrixObject(DWORD dwEnum, IARPSimpleProvider ** pparposp)
  162. {
  163. HRESULT hres;
  164. IARPSimpleProvider * parposp = NULL;
  165. TraceMsg(TF_CTL, "(Ctl) creating matrix object");
  166. // Security check must pass before we can provide a DSO.
  167. if (!_fSecure)
  168. {
  169. TraceMsg(TF_WARNING, "(Ctl) Security blocked creating DSO");
  170. hres = E_FAIL;
  171. }
  172. else
  173. {
  174. hres = THR(CDataSrc_CreateInstance(IID_IARPSimpleProvider, (LPVOID *)&parposp));
  175. if (SUCCEEDED(hres))
  176. {
  177. if (_psam == NULL)
  178. {
  179. hres = THR(CoCreateInstance(CLSID_ShellAppManager, NULL, CLSCTX_INPROC_SERVER,
  180. IID_IShellAppManager, (LPVOID *)&_psam));
  181. }
  182. if (_psam)
  183. {
  184. ASSERT(_rgparpevt[dwEnum]);
  185. hres = THR(parposp->Initialize(_psam, _rgparpevt[dwEnum], dwEnum));
  186. if (SUCCEEDED(hres))
  187. {
  188. parposp->SetSortCriteria(_cbstrSort);
  189. parposp->SetFilter(_cbstrCategory);
  190. }
  191. }
  192. if (FAILED(hres))
  193. {
  194. parposp->Release();
  195. parposp = NULL;
  196. }
  197. }
  198. }
  199. *pparposp = parposp;
  200. return hres;
  201. }
  202. /*-------------------------------------------------------------------------
  203. Purpose: Helper method to kill the worker thread
  204. */
  205. HRESULT CADCCtl::_KillDatasrcWorkerThread(IARPSimpleProvider * parp)
  206. {
  207. HRESULT hres = S_OK;
  208. if (parp)
  209. {
  210. IARPWorker * pDatasrcWorker;
  211. hres = parp->QueryInterface(IID_IARPWorker, (LPVOID *)&pDatasrcWorker);
  212. if (SUCCEEDED(hres))
  213. {
  214. hres = pDatasrcWorker->KillWT();
  215. pDatasrcWorker->Release();
  216. }
  217. }
  218. return hres;
  219. }
  220. HRESULT CADCCtl::_ReleaseMatrixObject(DWORD dwIndex)
  221. {
  222. _fDirty = FALSE;
  223. _fCategoryChanged = FALSE;
  224. if (_rgparposp[dwIndex])
  225. {
  226. _KillDatasrcWorkerThread(_rgparposp[dwIndex]);
  227. ATOMICRELEASE(_rgparposp[dwIndex]);
  228. if (_rgparpevt[dwIndex])
  229. _rgparpevt[dwIndex]->SetOSPListener(NULL);
  230. }
  231. return S_OK;
  232. }
  233. /*-------------------------------------------------------------------------
  234. Purpose: Release the control's embedded matrix object.
  235. Terminates any pending data download.
  236. */
  237. HRESULT CADCCtl::_ReleaseAllMatrixObjects(void)
  238. {
  239. int i;
  240. for (i = 0; i < ARRAYSIZE(_rgparposp); i++)
  241. _ReleaseMatrixObject(i);
  242. return S_OK;
  243. }
  244. const static struct {
  245. DWORD dwEnum;
  246. LPWSTR pszAreaText;
  247. } c_rgEnumAreas[] = {
  248. {ENUM_INSTALLED, L"Remove"},
  249. {ENUM_PUBLISHED, L"Add"},
  250. {ENUM_CATEGORIES, L"Categories"},
  251. {ENUM_OCSETUP, L"ocsetup"},
  252. };
  253. /*-------------------------------------------------------------------------
  254. Purpose: Release all the event broker objects.
  255. */
  256. HRESULT CADCCtl::_ReleaseAllEventBrokers()
  257. {
  258. HRESULT hres = S_OK;
  259. int i;
  260. for (i = 0; i < NUM_ARP_SIMPLE_PROVIDERS; i++)
  261. {
  262. // Release our previous Event Broker.
  263. ATOMICRELEASE(_rgparpevt[i]);
  264. }
  265. return hres;
  266. }
  267. /*-------------------------------------------------------------------------
  268. Purpose: Initialize the event broker object. This function will create
  269. if it doesn't exist already.
  270. bRecreate - if TRUE, the broker object will be released and recreated.
  271. */
  272. HRESULT CADCCtl::_InitEventBrokers(DataSourceListener * pdsl, BOOL bRecreate)
  273. {
  274. HRESULT hres = S_OK;
  275. TraceMsg(TF_CTL, "(Ctl) initializing event broker");
  276. int i;
  277. for (i = 0; i < NUM_ARP_SIMPLE_PROVIDERS; i++)
  278. {
  279. if (bRecreate)
  280. {
  281. // Release our previous Event Broker.
  282. ATOMICRELEASE(_rgparpevt[i]);
  283. // Create a new event broker for each DSO
  284. hres = CARPEvent_CreateInstance(IID_IARPEvent, (LPVOID *)&_rgparpevt[i], c_rgEnumAreas[i].pszAreaText);
  285. if (FAILED(hres))
  286. break;
  287. }
  288. if (_rgparpevt[i])
  289. {
  290. // Set the DataSourceListener for the event broker.
  291. _rgparpevt[i]->SetDataSourceListener(pdsl);
  292. }
  293. }
  294. return hres;
  295. }
  296. /*--------------------------------------------------------------------------
  297. Purpose: Matches the bstrQualifiers passed in to the Enum Areas we have
  298. */
  299. DWORD CADCCtl::_GetEnumAreaFromQualifier(BSTR bstrQualifier)
  300. {
  301. DWORD dwEnum = ENUM_UNKNOWN;
  302. int i;
  303. for (i = 0; i < ARRAYSIZE(c_rgEnumAreas); i++)
  304. {
  305. // (Trident databinding treats qualifiers case-sensitively, so we
  306. // should too.)
  307. if (0 == StrCmpW(bstrQualifier, c_rgEnumAreas[i].pszAreaText))
  308. {
  309. dwEnum = c_rgEnumAreas[i].dwEnum;
  310. break;
  311. }
  312. }
  313. return dwEnum;
  314. }
  315. /*-------------------------------------------------------------------------
  316. Purpose: Creates an object that supports the OLEDBSimpleProvider interface.
  317. We call this the OSP. This object is the main workhorse that
  318. provides data back to the consumer (Trident's databinding agent).
  319. MSHTML calls this method to obtain the object. It always passes
  320. an empty BSTR for bstrQualifier.
  321. This function can return S_OK and a NULL *ppunk! It actually is
  322. required to do this if the OSP doesn't have any data yet. Then,
  323. once the OSP has some data, it should fire READYSTATE_COMPLETE and
  324. dataSetMemberChanged, which will cause this method to be called
  325. again.
  326. Our implementation immediately enumerates and fills the OSP before
  327. returning, so we always hand back an OSP if we return S_OK.
  328. */
  329. STDMETHODIMP CADCCtl::msDataSourceObject(BSTR bstrQualifier, IUnknown **ppunk)
  330. {
  331. HRESULT hres = E_FAIL;
  332. *ppunk = NULL; // NULL in case of failure
  333. // Let the event brokers initialize even before we have real data
  334. if (NULL == _rgparpevt[ENUM_OCSETUP])
  335. hres = _InitEventBrokers(NULL, TRUE);
  336. // Check the last event broker to determine if they were created correctly
  337. if (_rgparpevt[ENUM_OCSETUP])
  338. {
  339. DWORD dwEnum = _GetEnumAreaFromQualifier(bstrQualifier);
  340. TraceMsg(TF_CTL, "(Ctl) msDataSourceObject called for %d", dwEnum);
  341. if (dwEnum != ENUM_UNKNOWN)
  342. {
  343. // Hand back a data source object
  344. if (NULL == _rgparposp[dwEnum])
  345. {
  346. hres = THR(_CreateMatrixObject(dwEnum, &_rgparposp[dwEnum]));
  347. if (SUCCEEDED(hres))
  348. {
  349. // Tell the OSP to enumerate the items.
  350. hres = THR(_rgparposp[dwEnum]->EnumerateItemsAsync());
  351. if (FAILED(hres))
  352. _ReleaseMatrixObject(dwEnum);
  353. }
  354. }
  355. else
  356. {
  357. // Recalculate all the data.
  358. hres = _rgparposp[dwEnum]->Recalculate();
  359. if (SUCCEEDED(hres))
  360. {
  361. // fetch OLEDBSimpleProvider interface pointer and cache it
  362. hres = THR(_rgparposp[dwEnum]->QueryInterface(IID_OLEDBSimpleProvider, (void **)ppunk));
  363. }
  364. }
  365. }
  366. }
  367. if (FAILED(hres))
  368. TraceMsg(TF_ERROR, "(Ctl) msDataSourceObject failed %s", Dbg_GetHRESULT(hres));
  369. else
  370. TraceMsg(TF_CTL, "(Ctl) msDataSourceObject returned %s and %#lx", Dbg_GetHRESULT(hres), *ppunk);
  371. return hres;
  372. }
  373. const IID IID_IDATASRCListener = {0x3050f380,0x98b5,0x11cf,{0xbb,0x82,0x00,0xaa,0x00,0xbd,0xce,0x0b}};
  374. const IID IID_DataSourceListener = {0x7c0ffab2,0xcd84,0x11d0,{0x94,0x9a,0x00,0xa0,0xc9,0x11,0x10,0xed}};
  375. //------------------------------------------------------------------------
  376. //
  377. // Method: addDataSourceListener()
  378. //
  379. // Synopsis: Sets the COM object which should receive notification
  380. // events.
  381. //
  382. // Arguments: pEvent Pointer to COM object to receive notification
  383. // events, or NULL if no notifications to be sent.
  384. //
  385. // Returns: S_OK upon success.
  386. // Error code upon failure.
  387. //
  388. //------------------------------------------------------------------------
  389. STDMETHODIMP CADCCtl::addDataSourceListener(IUnknown *punkListener)
  390. {
  391. HRESULT hres = E_FAIL;
  392. TraceMsg(TF_CTL, "(Ctl) addDataSourceListener called. Listener is %#lx", punkListener);
  393. ASSERT(IS_VALID_CODE_PTR(punkListener, IUnknown));
  394. DataSourceListener * pdsl;
  395. // Make sure this is the interface we expect
  396. hres = punkListener->QueryInterface(IID_DataSourceListener, (void **)&pdsl);
  397. if (SUCCEEDED(hres))
  398. {
  399. _InitEventBrokers(pdsl, FALSE);
  400. pdsl->Release();
  401. }
  402. return hres;
  403. }
  404. const TCHAR c_szStubWindowClass[] = TEXT("Add/Remove Stub Window");
  405. HWND _CreateTransparentStubWindow(HWND hwndParent)
  406. {
  407. WNDCLASS wc;
  408. RECT rc = {0};
  409. if (hwndParent)
  410. {
  411. RECT rcParent = {0};
  412. GetWindowRect(hwndParent, &rcParent);
  413. rc.left = (rcParent.left + RECTWIDTH(rcParent)) / 2;
  414. rc.top = (rcParent.top + RECTHEIGHT(rcParent)) / 2;
  415. }
  416. else
  417. {
  418. rc.left = CW_USEDEFAULT;
  419. rc.top = CW_USEDEFAULT;
  420. }
  421. if (!GetClassInfo(HINST_THISDLL, c_szStubWindowClass, &wc))
  422. {
  423. wc.style = 0;
  424. wc.lpfnWndProc = DefWindowProc;
  425. wc.cbClsExtra = 0;
  426. wc.cbWndExtra = SIZEOF(DWORD) * 2;
  427. wc.hInstance = HINST_THISDLL;
  428. wc.hIcon = NULL;
  429. wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  430. wc.hbrBackground = (HBRUSH)GetStockObject (WHITE_BRUSH);
  431. wc.lpszMenuName = NULL;
  432. wc.lpszClassName = c_szStubWindowClass;
  433. RegisterClass(&wc);
  434. }
  435. // WS_EX_APPWINDOW makes this show up in ALT+TAB, but not the tray.
  436. return CreateWindowEx(WS_EX_TRANSPARENT, c_szStubWindowClass, TEXT(""), WS_POPUP | WS_VISIBLE, rc.left,
  437. rc.top, 1, 1, hwndParent, NULL, HINST_THISDLL, NULL);
  438. }
  439. /*-------------------------------------------------------------------------
  440. Purpose: Retreive the top level HWND for our HTA host from the clientsite
  441. */
  442. HRESULT CADCCtl::_GetToplevelHWND()
  443. {
  444. HRESULT hres = E_FAIL;
  445. if (_pclientsite)
  446. {
  447. IOleInPlaceSite * pops = NULL;
  448. if (SUCCEEDED(_pclientsite->QueryInterface(IID_IOleInPlaceSite, (void **)&pops)))
  449. {
  450. pops->GetWindow(&_hwndTB);
  451. pops->Release();
  452. // Do we have a valid window?
  453. if (_hwndTB)
  454. {
  455. // Yes, then go up the hwnd chain to find the top level window
  456. HWND hwndTmp = NULL;
  457. while (hwndTmp = ::GetParent(_hwndTB))
  458. _hwndTB = hwndTmp;
  459. hres = S_OK;
  460. }
  461. }
  462. }
  463. return hres;
  464. }
  465. /*-------------------------------------------------------------------------
  466. Purpose: Invoke a specific command. The list of commands are specified
  467. in the APPCMD enumerated type.
  468. This method can be called via script.
  469. */
  470. STDMETHODIMP CADCCtl::Exec(BSTR bstrQualifier, BSTR bstrCmd, LONG nRecord)
  471. {
  472. SetErrorInfo(0, NULL);
  473. TraceMsg(TF_CTL, "(Ctl) Command (%ls, %d) called", bstrCmd, nRecord);
  474. // security check must pass before we could exec anything.
  475. if (!_fSecure)
  476. {
  477. TraceMsg(TF_CTL, "(Ctl) Security blocked Exec call");
  478. return S_OK; // scripting methods cannot return failure
  479. }
  480. // We should always get passed a legal qualifier
  481. DWORD dwEnum = _GetEnumAreaFromQualifier(bstrQualifier);
  482. RIP(dwEnum != ENUM_UNKNOWN);
  483. if (dwEnum == ENUM_UNKNOWN)
  484. return S_OK;
  485. const static struct {
  486. LPCWSTR pszCmd;
  487. APPCMD appcmd;
  488. } s_rgCmds[] = {
  489. { L"install", APPCMD_INSTALL },
  490. { L"uninstall", APPCMD_UNINSTALL },
  491. { L"modify", APPCMD_MODIFY },
  492. { L"upgrade", APPCMD_UPGRADE },
  493. { L"repair", APPCMD_REPAIR },
  494. { L"generic install", APPCMD_GENERICINSTALL },
  495. { L"ntoptions", APPCMD_NTOPTIONS },
  496. { L"winupdate", APPCMD_WINUPDATE },
  497. { L"addlater", APPCMD_ADDLATER },
  498. };
  499. int i;
  500. APPCMD appcmd = APPCMD_UNKNOWN;
  501. for (i = 0; i < ARRAYSIZE(s_rgCmds); i++)
  502. {
  503. if (0 == StrCmpIW(bstrCmd, s_rgCmds[i].pszCmd))
  504. {
  505. appcmd = s_rgCmds[i].appcmd;
  506. break;
  507. }
  508. }
  509. HWND hwndStub = NULL;
  510. if (_hwndTB == NULL)
  511. _GetToplevelHWND();
  512. if (_hwndTB)
  513. {
  514. hwndStub = _CreateTransparentStubWindow(_hwndTB);
  515. ::EnableWindow(_hwndTB, FALSE);
  516. ::SetActiveWindow(hwndStub);
  517. }
  518. switch (appcmd)
  519. {
  520. case APPCMD_INSTALL:
  521. case APPCMD_UNINSTALL:
  522. case APPCMD_MODIFY:
  523. case APPCMD_UPGRADE:
  524. case APPCMD_REPAIR:
  525. case APPCMD_ADDLATER:
  526. if (_rgparposp[dwEnum])
  527. _rgparposp[dwEnum]->DoCommand(hwndStub, appcmd, nRecord);
  528. break;
  529. case APPCMD_GENERICINSTALL:
  530. InstallAppFromFloppyOrCDROM(_hwndTB);
  531. break;
  532. case APPCMD_NTOPTIONS:
  533. {
  534. // command to invoke and OCMgr
  535. // "sysocmgr /x /i:%systemroot%\system32\sysoc.inf"
  536. TCHAR szInf[MAX_PATH];
  537. if (GetSystemDirectory(szInf, ARRAYSIZE(szInf)) && PathCombine(szInf, szInf, TEXT("sysoc.inf")))
  538. {
  539. TCHAR szParam[MAX_PATH];
  540. wsprintf(szParam, TEXT("/i:%s"), szInf);
  541. ShellExecute(NULL, NULL, TEXT("sysocmgr"), szParam, NULL, SW_SHOWDEFAULT);
  542. }
  543. }
  544. break;
  545. case APPCMD_WINUPDATE:
  546. {
  547. TCHAR szUrl[512];
  548. if (0 < LoadString(g_hinst, IDS_WINUPD_URL, szUrl, SIZECHARS(szUrl)))
  549. {
  550. ShellExecute(NULL, NULL, TEXT("wupdmgr.exe"), szUrl, NULL, SW_SHOWDEFAULT);
  551. }
  552. }
  553. break;
  554. case APPCMD_UNKNOWN:
  555. TraceMsg(TF_ERROR, "(Ctl) Received invalid appcmd %ls", bstrCmd);
  556. break;
  557. default:
  558. ASSERTMSG(0, "You forgot to add %d to the command list above", appcmd);
  559. break;
  560. }
  561. if (_hwndTB)
  562. {
  563. ::EnableWindow(_hwndTB, TRUE);
  564. if (hwndStub)
  565. ::DestroyWindow(hwndStub);
  566. ::SetForegroundWindow(_hwndTB);
  567. }
  568. return S_OK;
  569. }
  570. /*-------------------------------------------------------------------------
  571. Purpose: Provide an interface to the policies stored in the registry
  572. to the poor scripting languages
  573. This method can be called via script.
  574. */
  575. STDMETHODIMP CADCCtl::IsRestricted(BSTR bstrPolicy, VARIANT_BOOL * pbRestricted)
  576. {
  577. RIP(pbRestricted);
  578. *pbRestricted = ARPGetRestricted(bstrPolicy) ? VARIANT_TRUE : VARIANT_FALSE;
  579. return S_OK;
  580. }
  581. /*-------------------------------------------------------------------------
  582. Purpose: Reset the control's filter and sort criteria
  583. This method can be called via script.
  584. */
  585. STDMETHODIMP CADCCtl::Reset(BSTR bstrQualifier)
  586. {
  587. HRESULT hres = E_FAIL;
  588. DWORD dwEnum = _GetEnumAreaFromQualifier(bstrQualifier);
  589. // We should always get a legal qualifier
  590. RIP(dwEnum != ENUM_UNKNOWN);
  591. if (dwEnum == ENUM_UNKNOWN)
  592. return S_OK;
  593. // security check must pass before we could exec anything.
  594. if (!_fSecure)
  595. {
  596. TraceMsg(TF_CTL, "(Ctl) Security blocked Reset call");
  597. return S_OK; // scripting methods cannot return failure
  598. }
  599. TraceMsg(TF_CTL, "(Ctl) Reset called");
  600. // Infinite recursive calls to Reset can occur if script code calls reset
  601. // from within the datasetchanged event. This isn't a good idea.
  602. if ( !_fInReset )
  603. {
  604. _fInReset = TRUE; // prevent reentrancy
  605. // Did the EnumArea change OR
  606. // did the category change for these published apps?
  607. if (_fDirty || ((ENUM_PUBLISHED == dwEnum) && _fCategoryChanged))
  608. {
  609. // Yes; release the matrix object and recreate the event broker
  610. _ReleaseMatrixObject(dwEnum);
  611. // Make sure if we call Reset() right away now, we don't re-download
  612. // the data.
  613. _fDirty = FALSE;
  614. _fCategoryChanged = FALSE;
  615. // Create a new matrix object and read the new data into it
  616. hres = THR(_CreateMatrixObject(dwEnum, &_rgparposp[dwEnum]));
  617. if (SUCCEEDED(hres))
  618. {
  619. // Tell the OSP to enumerate the items.
  620. hres = THR(_rgparposp[dwEnum]->EnumerateItemsAsync());
  621. if (FAILED(hres))
  622. ATOMICRELEASE(_rgparposp[dwEnum]);
  623. }
  624. }
  625. else if (_rgparposp[dwEnum])
  626. {
  627. // No; simply re-apply the sort and filter criteria
  628. hres = S_OK;
  629. // Did the sort criteria change since the last sort?
  630. if (S_OK == _rgparposp[dwEnum]->SetSortCriteria(_cbstrSort))
  631. {
  632. // Yes
  633. // Create a new matrix object and transfer the contents of the
  634. // existing object to that. We must do this because Trident's
  635. // databinding expects to get a different object from msDataSourceObject
  636. // when it queries for another dataset.
  637. IARPSimpleProvider * parposp;
  638. hres = THR(_CreateMatrixObject(dwEnum, &parposp));
  639. if (SUCCEEDED(hres))
  640. {
  641. // Transferring the data is much faster than recreating it...
  642. hres = THR(parposp->TransferData(_rgparposp[dwEnum]));
  643. if (SUCCEEDED(hres))
  644. {
  645. // Release the old datasource and remember the new one
  646. _ReleaseMatrixObject(dwEnum);
  647. _rgparposp[dwEnum] = parposp;
  648. // Now apply the sort on the new dataset
  649. hres = _rgparposp[dwEnum]->Sort();
  650. }
  651. }
  652. }
  653. }
  654. _fInReset = FALSE;
  655. }
  656. // reset should always return S_OK, otherwise we get scrip error.
  657. return S_OK;
  658. }
  659. HRESULT CADCCtl::_CheckSecurity(IOleClientSite * pClientSite)
  660. {
  661. IOleContainer * poc;
  662. if (SUCCEEDED(pClientSite->GetContainer(&poc)))
  663. {
  664. IHTMLDocument2 * phd;
  665. if (SUCCEEDED(poc->QueryInterface(IID_IHTMLDocument2, (void **)&phd)))
  666. {
  667. IHTMLWindow2 * phw;
  668. if (SUCCEEDED(phd->get_parentWindow(&phw)))
  669. {
  670. IHTMLWindow2 * phwTop;
  671. if (SUCCEEDED(phw->get_top(&phwTop)))
  672. {
  673. IHTMLLocation * phl;
  674. if (SUCCEEDED(phwTop->get_location(&phl)))
  675. {
  676. BSTR bstrHref;
  677. if (SUCCEEDED(phl->get_href(&bstrHref)))
  678. {
  679. ASSERT(IS_VALID_STRING_PTRW(bstrHref, -1));
  680. WCHAR szResURL[] = L"res://appwiz.cpl/default.hta";
  681. DWORD cchUrl = lstrlen(szResURL);
  682. if (!StrCmpNIW(bstrHref, szResURL, cchUrl))
  683. {
  684. _fSecure = TRUE;
  685. }
  686. SysFreeString(bstrHref);
  687. }
  688. phl->Release();
  689. }
  690. phwTop->Release();
  691. }
  692. phw->Release();
  693. }
  694. phd->Release();
  695. }
  696. poc->Release();
  697. }
  698. return S_OK;
  699. }
  700. /*-------------------------------------------------------------------------
  701. Purpose: IOleObject::SetClientSite
  702. For security reasons, on top of ATL's implementation of this, we need to
  703. check our top level browser's URL location, it must be our official URL
  704. namely "res://appwiz.cpl/frm_*.htm"
  705. */
  706. STDMETHODIMP CADCCtl::IOleObject_SetClientSite(IOleClientSite *pClientSite)
  707. {
  708. HRESULT hres = S_OK;
  709. // Has the site already been set?
  710. if (pClientSite != _pclientsite)
  711. {
  712. ATOMICRELEASE(_pclientsite);
  713. if (pClientSite)
  714. {
  715. // No; check some things out and cache them
  716. _hwndTB = NULL;
  717. _pclientsite = pClientSite;
  718. if (_pclientsite)
  719. _pclientsite->AddRef();
  720. _fSecure = FALSE;
  721. if (g_dwPrototype & PF_NOSECURITYCHECK)
  722. {
  723. _fSecure = TRUE;
  724. }
  725. else
  726. _CheckSecurity(_pclientsite);
  727. }
  728. hres = CComControlBase::IOleObject_SetClientSite(pClientSite);
  729. }
  730. return hres;
  731. }
  732. #endif //DOWNLEVEL_PLATFORM