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

984 lines
30 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998.
  5. //
  6. // File: S M E N G . C P P
  7. //
  8. // Contents: The engine that provides statistics to the status monitor
  9. //
  10. // Notes:
  11. //
  12. // Author: CWill 7 Oct 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "sminc.h"
  18. #include "ncnetcon.h"
  19. #include "ncui.h"
  20. #include "smpsh.h"
  21. #include "smutil.h"
  22. #include "smhelp.h"
  23. extern const WCHAR c_szNetShellDll[];
  24. //+---------------------------------------------------------------------------
  25. //
  26. // Member: CNetStatisticsEngine::CNetStatisticsEngine
  27. //
  28. // Purpose: Initialization
  29. //
  30. // Arguments: None
  31. //
  32. // Returns: Nothing
  33. //
  34. CNetStatisticsEngine::CNetStatisticsEngine(VOID) :
  35. m_pnsc(NULL),
  36. m_psmEngineData(NULL),
  37. m_ppsmg(NULL),
  38. m_ppsmt(NULL),
  39. m_ppsmr(NULL),
  40. m_ppsms(NULL),
  41. m_hwndPsh(NULL),
  42. m_cStatRef(0),
  43. m_fRefreshIcon(FALSE),
  44. m_dwChangeFlags(SMDCF_NULL),
  45. m_fCreatingDialog(FALSE)
  46. {
  47. TraceFileFunc(ttidStatMon);
  48. ::ZeroMemory(&m_PersistConn, sizeof(m_PersistConn));
  49. ::ZeroMemory(&m_guidId, sizeof(m_guidId));
  50. }
  51. //+---------------------------------------------------------------------------
  52. //
  53. // Member: CNetStatisticsEngine::~CNetStatisticsEngine
  54. //
  55. // Purpose: Cleans up all data before destroying the object
  56. //
  57. // Arguments: None
  58. //
  59. // Returns: Nothing
  60. //
  61. CNetStatisticsEngine::~CNetStatisticsEngine(VOID)
  62. {
  63. // Make sure we don't try to update our stats while destroying
  64. //
  65. m_cStatRef = 0;
  66. // Make sure we are no longer in the global list if we are valid
  67. //
  68. if ((GUID_NULL != m_guidId) && (NULL != m_pnsc))
  69. {
  70. (VOID) m_pnsc->RemoveNetStatisticsEngine(&m_guidId);
  71. }
  72. //
  73. // Clear the data
  74. //
  75. if (m_psmEngineData)
  76. {
  77. delete(m_psmEngineData);
  78. m_psmEngineData = NULL;
  79. }
  80. // Release the object because we AddRefed it
  81. //
  82. ::ReleaseObj(m_ppsmg);
  83. delete m_ppsmt;
  84. m_ppsmt = NULL;
  85. delete m_ppsmr;
  86. m_ppsmr = NULL;
  87. delete m_ppsms;
  88. m_ppsms = NULL;
  89. AssertSz(FImplies(m_PersistConn.pbBuf, m_PersistConn.ulSize),
  90. "Buffer with no size.");
  91. MemFree(m_PersistConn.pbBuf);
  92. ::ReleaseObj(m_pnsc);
  93. }
  94. //+---------------------------------------------------------------------------
  95. //
  96. // Member: CNetStatisticsEngine::HrInitStatEngine
  97. //
  98. // Purpose: Initilaizes the statistics engine
  99. //
  100. // Arguments: ccfe - The connection folder entry associated with this
  101. // statistics engine
  102. //
  103. // Returns: Error code
  104. //
  105. HRESULT CNetStatisticsEngine::HrInitStatEngine(const CONFOLDENTRY& ccfe)
  106. {
  107. TraceFileFunc(ttidStatMon);
  108. HRESULT hr;
  109. Assert(!ccfe.empty());
  110. ULONG cb = ccfe.GetPersistSize();
  111. hr = HrMalloc(cb, (PVOID*)&m_PersistConn.pbBuf);
  112. if (SUCCEEDED(hr))
  113. {
  114. CopyMemory(m_PersistConn.pbBuf, ccfe.GetPersistData(), cb);
  115. m_PersistConn.ulSize = cb;
  116. m_PersistConn.clsid = ccfe.GetCLSID();
  117. m_guidId = ccfe.GetGuidID();
  118. }
  119. TraceError("CNetStatisticsEngine::HrInitStatEngine", hr);
  120. return hr;
  121. }
  122. //+---------------------------------------------------------------------------
  123. //
  124. // Member: CNetStatisticsEngine::StartStatistics
  125. //
  126. // Purpose: Start retrieving statistics off of the engine
  127. //
  128. // Arguments: None
  129. //
  130. // Returns: Error code
  131. //
  132. HRESULT CNetStatisticsEngine::StartStatistics(VOID)
  133. {
  134. TraceFileFunc(ttidStatMon);
  135. HRESULT hr = S_OK;
  136. ::InterlockedIncrement(&m_cStatRef);
  137. m_fRefreshIcon = TRUE;
  138. TraceError("CNetStatisticsEngine::StartStatistics", hr);
  139. return hr;
  140. }
  141. //+---------------------------------------------------------------------------
  142. //
  143. // Member: CNetStatisticsEngine::StopStatistics
  144. //
  145. // Purpose: Tell the engine that that statistics are no longer needed
  146. //
  147. // Arguments: None
  148. //
  149. // Returns: Error code
  150. //
  151. HRESULT CNetStatisticsEngine::StopStatistics(VOID)
  152. {
  153. TraceFileFunc(ttidStatMon);
  154. HRESULT hr = S_OK;
  155. if (0 == ::InterlockedDecrement(&m_cStatRef))
  156. {
  157. //$ REVIEW (cwill) 5 Feb 1998: We can stop doing statistics now.
  158. }
  159. TraceError("CNetStatisticsEngine::StopStatistics", hr);
  160. return hr;
  161. }
  162. DWORD CNetStatisticsEngine::MonitorThread(CNetStatisticsEngine * pnse)
  163. {
  164. // Create a new scope since FreeLibraryAndExitThread will not call destructors on global scope
  165. {
  166. TraceFileFunc(ttidStatMon);
  167. HRESULT hr;
  168. BOOL fUninitCom = TRUE;
  169. CWaitCursor WaitCursor;
  170. BOOL fHasSupportPage = FALSE;
  171. int iIndexSupportPage = 0;
  172. // Initialize COM on this thread
  173. //
  174. hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED);
  175. if (RPC_E_CHANGED_MODE == hr)
  176. {
  177. hr = S_OK;
  178. fUninitCom = FALSE;
  179. }
  180. if (SUCCEEDED(hr))
  181. {
  182. INetConnection* pncStatEng;
  183. // Get INetConnection and initialize the pages
  184. //
  185. hr = pnse->HrGetConnectionFromBlob(&pncStatEng);
  186. if (SUCCEEDED(hr))
  187. {
  188. // Initialize the general page
  189. //
  190. hr = pnse->m_ppsmg->HrInitGenPage(pnse, pncStatEng,
  191. g_aHelpIDs_IDD_STATMON_GENERAL);
  192. if (SUCCEEDED(hr))
  193. {
  194. // Initialize the tool page
  195. //
  196. hr = pnse->m_ppsmt->HrInitToolPage(pncStatEng,
  197. g_aHelpIDs_IDD_STATMON_TOOLS);
  198. if (SUCCEEDED(hr))
  199. {
  200. if (pnse->m_ppsmr)
  201. {
  202. // Initialize the RAS page
  203. //
  204. hr = pnse->m_ppsmr->HrInitRasPage(pncStatEng,
  205. pnse->m_ppsmg,
  206. g_aHelpIDs_IDD_STATMON_RAS);
  207. }
  208. if (SUCCEEDED(hr))
  209. {
  210. PROPSHEETHEADER pshTemp = { 0 };
  211. INT nPages = 1; // Start with only the general page
  212. HPROPSHEETPAGE ahpspTemp[4];
  213. // Put together the required property pages
  214. // If we have a RAS page
  215. //
  216. if (pnse->m_ppsmr)
  217. {
  218. ahpspTemp[0] = pnse->m_ppsmg->CreatePage(IDD_STATMON_GENERAL_RAS,
  219. PSP_DEFAULT);
  220. // Create the RAS page
  221. //
  222. ahpspTemp[nPages] = pnse->m_ppsmr->CreatePage(IDD_STATMON_RAS,
  223. PSP_DEFAULT);
  224. nPages++;
  225. }
  226. else if(NCM_LAN == pnse->m_ncmType || NCM_BRIDGE == pnse->m_ncmType)
  227. {
  228. ahpspTemp[0] = pnse->m_ppsmg->CreatePage(IDD_STATMON_GENERAL_LAN,
  229. PSP_DEFAULT);
  230. }
  231. else if(NCM_SHAREDACCESSHOST_LAN == pnse->m_ncmType || NCM_SHAREDACCESSHOST_RAS == pnse->m_ncmType)
  232. {
  233. ahpspTemp[0] = pnse->m_ppsmg->CreatePage(IDD_STATMON_GENERAL_SHAREDACCESS,
  234. PSP_DEFAULT);
  235. }
  236. else
  237. {
  238. AssertSz(FALSE, "Unknown media type");
  239. }
  240. HICON hIcon = NULL;
  241. hr = HrGetIconFromMediaType(GetSystemMetrics(SM_CXSMICON), pnse->m_ncmType, pnse->m_ncsmType, 7, 0, &hIcon);
  242. if (NCM_LAN == pnse->m_ncmType || NCM_BRIDGE == pnse->m_ncmType)
  243. {
  244. hr = pnse->m_ppsms->HrInitPage(pncStatEng,
  245. g_aHelpIDs_IDD_PROPPAGE_IPCFG);
  246. if (SUCCEEDED(hr))
  247. {
  248. ahpspTemp[nPages] = pnse->m_ppsms->CreatePage(IDD_PROPPAGE_IPCFG,
  249. PSP_DEFAULT);
  250. fHasSupportPage = TRUE;
  251. iIndexSupportPage = nPages;
  252. nPages++;
  253. }
  254. }
  255. // If we have any tools to display
  256. //
  257. if (!pnse->m_ppsmt->FToolListEmpty())
  258. {
  259. ahpspTemp[nPages] = pnse->m_ppsmt->CreatePage(IDD_STATMON_TOOLS,
  260. PSP_DEFAULT);
  261. nPages++;
  262. }
  263. // Fill in the property sheet header
  264. //
  265. pshTemp.dwSize = sizeof(PROPSHEETHEADER);
  266. pshTemp.dwFlags = PSH_NOAPPLYNOW | PSH_USECALLBACK;
  267. pshTemp.hwndParent = NULL;
  268. pshTemp.hInstance = _Module.GetResourceInstance();
  269. pshTemp.hIcon = NULL;
  270. pshTemp.nPages = nPages;
  271. if (hIcon)
  272. {
  273. pshTemp.dwFlags |= PSH_USEHICON;
  274. pshTemp.hIcon = hIcon;
  275. }
  276. pshTemp.phpage = ahpspTemp;
  277. pshTemp.pfnCallback = static_cast<PFNPROPSHEETCALLBACK>(
  278. CNetStatisticsEngine::PshCallback);
  279. pshTemp.hbmWatermark = NULL;
  280. pshTemp.hplWatermark = NULL;
  281. pshTemp.hbmHeader = NULL;
  282. // Set propertysheet title
  283. PWSTR pszCaption = NULL;
  284. NETCON_PROPERTIES* pProps;
  285. if (SUCCEEDED(pncStatEng->GetProperties(&pProps)))
  286. {
  287. // Get the title each time in case it has
  288. // changed
  289. //
  290. AssertSz(pProps->pszwName,
  291. "We should have a pProps->pszwName");
  292. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  293. FORMAT_MESSAGE_FROM_STRING |
  294. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  295. SzLoadIds(IDS_SM_CAPTION),
  296. 0, 0, (PWSTR)&pszCaption, 0,
  297. (va_list *)&pProps->pszwName);
  298. pshTemp.pszCaption = pszCaption;
  299. // Get the connection status. If the status is NCS_INVALID_ADDRESS,
  300. // then put the "Support" tab as the start page
  301. if (fHasSupportPage && NCS_INVALID_ADDRESS == pProps->Status)
  302. {
  303. pshTemp.nStartPage = iIndexSupportPage;
  304. Assert(pnse->m_ppsms);
  305. //set the support tab as the first page and m_ppsms is responsible
  306. //for initialize the propsheet
  307. pnse->m_ppsms->SetAsFirstPage(TRUE);
  308. }
  309. else
  310. {
  311. pshTemp.nStartPage = 0;
  312. Assert(pnse->m_ppsmg);
  313. //set the support tab as the first page and m_ppsmg is responsible
  314. //for initialize the propsheet
  315. pnse->m_ppsmg->SetAsFirstPage(TRUE);
  316. }
  317. FreeNetconProperties(pProps);
  318. }
  319. else
  320. {
  321. //$ REVIEW : CWill : 02/17/98 : Better default?
  322. pshTemp.pszCaption = SzLoadIds(IDS_SM_ERROR_CAPTION);
  323. }
  324. // Launch the page
  325. //
  326. INT iRet = (INT)::PropertySheet(&pshTemp);
  327. if (NULL == iRet)
  328. {
  329. hr = ::HrFromLastWin32Error();
  330. }
  331. if (hIcon)
  332. {
  333. DestroyIcon(hIcon);
  334. }
  335. if (NULL != pszCaption)
  336. {
  337. LocalFree(pszCaption);
  338. }
  339. }
  340. }
  341. }
  342. // Make sure the general page clean up correctly.
  343. // Since the "General" page may not be the first page (support page will be the
  344. // first one when the address is invalid, the OnDestroy method (which calls HrCleanupGenPage)
  345. // of the general page may not called in such case. So we always do a cleanup here. It's
  346. // OK to call HrCleanupGenPage mutliple times.
  347. // general page
  348. AssertSz(pnse->m_ppsmg, "We should have a m_ppsmg");
  349. (VOID) pnse->m_ppsmg->HrCleanupGenPage();
  350. //also cleanup the Support page if it exists. It's safe to call this routine mutliple times.
  351. if (fHasSupportPage)
  352. {
  353. pnse->m_ppsms->CleanupPage();
  354. }
  355. // leaving creating mode
  356. pnse->m_fCreatingDialog = FALSE;
  357. ReleaseObj(pncStatEng);
  358. }
  359. if (fUninitCom)
  360. {
  361. CoUninitialize();
  362. }
  363. } // Initialize com succeeded
  364. // Release the 'pnse' object because it was addref'd before
  365. // the thread was created.
  366. //
  367. ReleaseObj(static_cast<INetStatisticsEngine *>(pnse));
  368. }
  369. // release the dll
  370. //
  371. FreeLibraryAndExitThread(GetModuleHandle(c_szNetShellDll), 1);
  372. return 1;
  373. }
  374. //+---------------------------------------------------------------------------
  375. //
  376. // Member: CNetStatisticsEngine::ShowStatusMonitor
  377. //
  378. // Purpose: Create an launch the UI for the status monitor
  379. //
  380. // Arguments: None
  381. //
  382. // Returns: Error code
  383. //
  384. HRESULT CNetStatisticsEngine::ShowStatusMonitor(VOID)
  385. {
  386. TraceFileFunc(ttidStatMon);
  387. HRESULT hr = S_OK;
  388. CExceptionSafeComObjectLock EsLock(m_pnsc);
  389. // Create the property sheet pages if they don't already exist
  390. //
  391. if (!m_ppsmg)
  392. {
  393. CPspStatusMonitorGen* pObj = NULL;
  394. // Make sure we have read in the tools
  395. //
  396. (VOID) m_pnsc->HrReadTools();
  397. if (m_ncmType == NCM_LAN || m_ncmType == NCM_BRIDGE)
  398. {
  399. CPspLanGen* pLanObj = NULL;
  400. // Make the Tool property page
  401. m_ppsmt = new CPspLanTool;
  402. // Create the object
  403. pLanObj = new CComObject <CPspLanGen>;
  404. if (pLanObj)
  405. {
  406. pLanObj->put_MediaType(m_ncmType, m_ncsmType);
  407. }
  408. // Give it back to the page
  409. pObj = pLanObj;
  410. m_ppsms = new CPspStatusMonitorIpcfg;
  411. }
  412. else if(m_ncmType == NCM_SHAREDACCESSHOST_LAN || m_ncmType == NCM_SHAREDACCESSHOST_RAS)
  413. {
  414. m_ppsmt = new CPspSharedAccessTool;
  415. CPspSharedAccessGen* pSharedAccessGen = new CComObject<CPspSharedAccessGen>;
  416. pSharedAccessGen->put_MediaType(m_ncmType, m_ncsmType);
  417. pObj = pSharedAccessGen;
  418. }
  419. else if ((m_dwCharacter & NCCF_INCOMING_ONLY) ||
  420. (m_dwCharacter & NCCF_OUTGOING_ONLY))
  421. {
  422. // RAS connections
  423. CPspRasGen* pRasObj = NULL;
  424. // Make the Tool property page
  425. //
  426. m_ppsmt = new CPspRasTool;
  427. // Make the RAS property page and let it be known there are
  428. // now three pages
  429. //
  430. m_ppsmr = new CPspStatusMonitorRas;
  431. // Create the object
  432. //
  433. pRasObj = new CComObject <CPspRasGen>;
  434. if (pRasObj)
  435. {
  436. pRasObj->put_MediaType(m_ncmType, m_ncsmType);
  437. pRasObj->put_Character(m_dwCharacter);
  438. }
  439. // Give it back to the page
  440. //
  441. pObj = pRasObj;
  442. }
  443. else
  444. {
  445. AssertSz(FALSE, "Unknown connection type.");
  446. }
  447. if (NULL != pObj)
  448. {
  449. // Do the standard CComCreator::CreateInstance stuff.
  450. //
  451. pObj->SetVoid(NULL);
  452. pObj->InternalFinalConstructAddRef();
  453. hr = pObj->FinalConstruct();
  454. pObj->InternalFinalConstructRelease();
  455. if (SUCCEEDED(hr))
  456. {
  457. m_ppsmg = static_cast<CPspStatusMonitorGen*>(pObj);
  458. // Hold on to the interface
  459. ::AddRefObj(m_ppsmg);
  460. }
  461. // Make sure we clean up nicely
  462. //
  463. if (FAILED(hr))
  464. {
  465. delete pObj;
  466. }
  467. }
  468. // Clean up the other pages on failure
  469. //
  470. if (FAILED(hr))
  471. {
  472. if (m_ppsmt)
  473. {
  474. delete m_ppsmt;
  475. m_ppsmt = NULL;
  476. }
  477. if (m_ppsmr)
  478. {
  479. delete m_ppsmr;
  480. m_ppsmr = NULL;
  481. }
  482. }
  483. }
  484. //
  485. // Show the property sheets
  486. //
  487. if (SUCCEEDED(hr))
  488. {
  489. // NOTE: The variable m_fCreatingDialog is reset to FALSE in the following
  490. // 3 places, which should cover all senarios:
  491. //
  492. // 1) In CPspStatusMonitorGen::OnInitDialog, after m_hWnd is assigned.
  493. // 2) In CNetStatisticsEngine::ShowStatusMonitor, in case CreateThread failed.
  494. // 3) In CNetStatisticsEngine::MonitorThread, just before exiting
  495. // (in case of failing to create UI).
  496. //
  497. if (m_hwndPsh)
  498. {
  499. // Bring the existing property sheet page to the foreground
  500. //
  501. ::SetForegroundWindow(m_hwndPsh);
  502. }
  503. else if (!m_fCreatingDialog)
  504. {
  505. // Addref 'this' object
  506. //
  507. AddRefObj(static_cast<INetStatisticsEngine *>(this));
  508. // entering creating mode
  509. m_fCreatingDialog = TRUE;
  510. // Create the property sheet on a different thread
  511. //
  512. // Make sure the dll don't get unloaded while the thread is active
  513. HINSTANCE hInst = LoadLibrary(c_szNetShellDll);
  514. HANDLE hthrd = NULL;
  515. if (hInst)
  516. {
  517. DWORD dwThreadId;
  518. hthrd = CreateThread(NULL, STACK_SIZE_TINY,
  519. (LPTHREAD_START_ROUTINE)CNetStatisticsEngine::MonitorThread,
  520. (LPVOID)this, 0, &dwThreadId);
  521. if (NULL != hthrd)
  522. {
  523. CloseHandle(hthrd);
  524. }
  525. }
  526. // clean up on failure
  527. if (!hthrd)
  528. {
  529. // Release 'this' object on failure
  530. //
  531. ReleaseObj(static_cast<INetStatisticsEngine *>(this));
  532. // Release the dll
  533. //
  534. if (hInst)
  535. FreeLibrary(hInst);
  536. // leaving creating mode
  537. m_fCreatingDialog = FALSE;
  538. hr = HrFromLastWin32Error();
  539. }
  540. }
  541. }
  542. TraceError("CNetStatisticsEngine::ShowStatusMonitor", hr);
  543. return hr;
  544. }
  545. //+---------------------------------------------------------------------------
  546. //
  547. // Member: CNetStatisticsEngine::GetStatistics
  548. //
  549. // Purpose:
  550. //
  551. // Arguments:
  552. //
  553. // Returns:
  554. //
  555. HRESULT CNetStatisticsEngine::GetStatistics(
  556. STATMON_ENGINEDATA** ppseAllData)
  557. {
  558. TraceFileFunc(ttidStatMon);
  559. HRESULT hr = S_OK;
  560. // Make sure we have a valid pointer
  561. if (ppseAllData)
  562. {
  563. STATMON_ENGINEDATA * pEngineData = NULL;
  564. // Allocate space and copy the data ..
  565. EnterCriticalSection(&g_csStatmonData);
  566. if (!m_psmEngineData)
  567. {
  568. DWORD dwChangeFlags;
  569. BOOL fNoLongerConnected;
  570. hr = HrUpdateData(&dwChangeFlags, &fNoLongerConnected);
  571. }
  572. if (m_psmEngineData)
  573. {
  574. DWORD dwBytes = sizeof(STATMON_ENGINEDATA);
  575. PVOID pbBuf;
  576. hr = HrCoTaskMemAlloc(dwBytes, &pbBuf);
  577. if (SUCCEEDED(hr))
  578. {
  579. pEngineData = reinterpret_cast<STATMON_ENGINEDATA *>(pbBuf);
  580. // fill in the data
  581. *pEngineData = *m_psmEngineData;
  582. }
  583. }
  584. LeaveCriticalSection(&g_csStatmonData);
  585. *ppseAllData = pEngineData;
  586. }
  587. else
  588. {
  589. // We should have good data
  590. hr = E_INVALIDARG;
  591. }
  592. TraceError("CNetStatisticsEngine::GetStatistics", hr);
  593. return hr;
  594. }
  595. //+---------------------------------------------------------------------------
  596. //
  597. // Member: CNetStatisticsEngine::UpdateStatistics
  598. //
  599. // Purpose: Get the new statistics from the devices and notify all the
  600. // advises that the data has changed
  601. //
  602. // Arguments: None
  603. //
  604. // Returns: Error code
  605. //
  606. HRESULT
  607. CNetStatisticsEngine::UpdateStatistics (
  608. BOOL* pfNoLongerConnected)
  609. {
  610. TraceFileFunc(ttidStatMon);
  611. HRESULT hr = S_OK;
  612. Assert (pfNoLongerConnected);
  613. // Initialize the output parameter.
  614. //
  615. *pfNoLongerConnected = FALSE;
  616. // Don't bother doing anything if we don't have any ref count
  617. //
  618. if (m_cStatRef)
  619. {
  620. // Get the new data
  621. //
  622. DWORD dwChangeFlags;
  623. hr = HrUpdateData(&dwChangeFlags, pfNoLongerConnected);
  624. // If it represents a change, notify our connection points.
  625. //
  626. if (SUCCEEDED(hr) &&
  627. (m_fRefreshIcon || // Bug#319276, force a refresh if new client is added
  628. (dwChangeFlags != m_dwChangeFlags) ||
  629. (*pfNoLongerConnected)))
  630. {
  631. m_fRefreshIcon = FALSE;
  632. ULONG cpUnk;
  633. IUnknown** apUnk;
  634. hr = HrCopyIUnknownArrayWhileLocked (
  635. this,
  636. &m_vec,
  637. &cpUnk,
  638. &apUnk);
  639. if (SUCCEEDED(hr) && cpUnk && apUnk)
  640. {
  641. // Notify everyone that we have changed
  642. //
  643. for (ULONG i = 0; i < cpUnk; i++)
  644. {
  645. INetConnectionStatisticsNotifySink* pSink =
  646. static_cast<INetConnectionStatisticsNotifySink*>(apUnk[i]);
  647. hr = pSink->OnStatisticsChanged(dwChangeFlags);
  648. ReleaseObj(pSink);
  649. }
  650. MemFree(apUnk);
  651. }
  652. // Remember the change flags for comparison next time.
  653. //
  654. m_dwChangeFlags = dwChangeFlags;
  655. }
  656. }
  657. TraceError("CNetStatisticsEngine::UpdateStatistics", hr);
  658. return hr;
  659. }
  660. //+---------------------------------------------------------------------------
  661. //
  662. // Member: CNetStatisticsEngine::UpdateTitle
  663. //
  664. // Purpose: If the status monitor UI is up, change the title
  665. //
  666. // Arguments: pszwNewName
  667. //
  668. // Returns: None
  669. //
  670. HRESULT CNetStatisticsEngine::UpdateTitle (PCWSTR pszwNewName)
  671. {
  672. TraceFileFunc(ttidStatMon);
  673. if (m_hwndPsh)
  674. {
  675. // Set propertysheet title
  676. PWSTR pszCaption = NULL;
  677. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  678. FORMAT_MESSAGE_FROM_STRING |
  679. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  680. SzLoadIds(IDS_SM_CAPTION),
  681. 0, 0, (PWSTR)&pszCaption, 0,
  682. (va_list *)&pszwNewName);
  683. PropSheet_SetTitle(m_hwndPsh,0,pszCaption);
  684. }
  685. return S_OK;
  686. }
  687. //+---------------------------------------------------------------------------
  688. //
  689. // Member: CNetStatisticsEngine::CloseStatusMonitor
  690. //
  691. // Purpose: If the status monitor UI is up, close it
  692. //
  693. // Arguments: None
  694. //
  695. // Returns: None
  696. //
  697. HRESULT CNetStatisticsEngine::CloseStatusMonitor()
  698. {
  699. TraceFileFunc(ttidStatMon);
  700. if (m_hwndPsh)
  701. {
  702. PropSheet_PressButton(m_hwndPsh, PSBTN_CANCEL);
  703. }
  704. return S_OK;
  705. }
  706. //+---------------------------------------------------------------------------
  707. //
  708. // Member: CNetStatisticsEngine::UpdateRasLinkList
  709. //
  710. // Purpose: If the status monitor UI is up and on the RAS page, update
  711. // the multi-link combo-box and button state
  712. //
  713. // Arguments: None
  714. //
  715. // Returns: Error code
  716. //
  717. HRESULT CNetStatisticsEngine::UpdateRasLinkList()
  718. {
  719. TraceFileFunc(ttidStatMon);
  720. HRESULT hr = S_OK;
  721. if (m_hwndPsh)
  722. {
  723. HWND hwndDlg = PropSheet_GetCurrentPageHwnd(m_hwndPsh);
  724. if (hwndDlg)
  725. {
  726. if (GetDlgItem(hwndDlg, IDC_TXT_SM_NUM_DEVICES_VAL))
  727. {
  728. // we are on the RAS page, update the combo box, active link count etc.
  729. ::PostMessage(hwndDlg, PWM_UPDATE_RAS_LINK_LIST, 0, 0);
  730. }
  731. }
  732. }
  733. TraceError("CNetStatisticsEngine::UpdateRasLinkList", hr);
  734. return hr;
  735. }
  736. //+---------------------------------------------------------------------------
  737. //
  738. // Member: CNetStatisticsEngine::GetGuidId
  739. //
  740. // Purpose: Gets the Connection GUID of the engine into a pre-allocated
  741. // buffer
  742. //
  743. // Arguments: pguidId - Location of buffer to hold the GUID
  744. //
  745. // Returns: Error code
  746. //
  747. HRESULT CNetStatisticsEngine::GetGuidId(GUID* pguidId)
  748. {
  749. TraceFileFunc(ttidStatMon);
  750. HRESULT hr = S_OK;
  751. // Pass back the GUID
  752. //
  753. if (pguidId)
  754. {
  755. *pguidId = m_guidId;
  756. }
  757. else
  758. {
  759. hr = E_POINTER;
  760. }
  761. TraceError("CNetStatisticsEngine::GetGuidId", hr);
  762. return hr;
  763. }
  764. //+------------------------------------------------------------------
  765. //
  766. // CNetStatisticsEngine::PshCallback
  767. //
  768. // Purpose:
  769. //
  770. //
  771. // Parameters:
  772. // hwndDlg [in]
  773. // uMsg [in]
  774. // lParam [in]
  775. //
  776. // Returns:
  777. // a
  778. //
  779. // Side Effects:
  780. //
  781. INT CALLBACK CNetStatisticsEngine::PshCallback(HWND hwndDlg,
  782. UINT uMsg, LPARAM lParam)
  783. {
  784. TraceFileFunc(ttidStatMon);
  785. switch (uMsg)
  786. {
  787. // called before the dialog is created, hwndPropSheet = NULL,
  788. // lParam points to dialog resource
  789. // This would hide the context help "?" on toolbar
  790. #if 0
  791. case PSCB_PRECREATE:
  792. {
  793. LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam;
  794. lpTemplate->style &= ~DS_CONTEXTHELP;
  795. }
  796. break;
  797. #endif
  798. case PSCB_INITIALIZED:
  799. {
  800. HWND hwndTemp = NULL;
  801. // Cancel button becomes close
  802. //
  803. hwndTemp = ::GetDlgItem(hwndDlg, IDCANCEL);
  804. if (NULL != hwndTemp)
  805. {
  806. ::SetWindowText(hwndTemp, ::SzLoadIds(IDS_SM_PSH_CLOSE));
  807. }
  808. HICON hIcon;
  809. hIcon = (HICON)SendMessage(hwndDlg,
  810. WM_GETICON,
  811. ICON_SMALL,
  812. 0);
  813. // Assert(hIcon);
  814. if (hIcon)
  815. {
  816. SendMessage(hwndDlg,
  817. WM_SETICON,
  818. ICON_BIG,
  819. (LPARAM)hIcon);
  820. }
  821. }
  822. break;
  823. }
  824. return 0;
  825. }