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.

1412 lines
41 KiB

  1. /*++
  2. Copyright (C) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. ADAPREG.CPP
  5. Abstract:
  6. History:
  7. --*/
  8. #include "precomp.h"
  9. #include <stdio.h>
  10. #include <wtypes.h>
  11. #include <oleauto.h>
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #include <time.h>
  15. #include <malloc.h>
  16. #include <tchar.h>
  17. #include <process.h>
  18. #include <arrtempl.h>
  19. #include <cominit.h>
  20. #include <winmgmtr.h>
  21. #include <wbemcli.h>
  22. #include <throttle.h>
  23. #include <psapi.h>
  24. #include "adapreg.h"
  25. #include "perflibschema.h"
  26. #include "WMIBroker.h"
  27. #include "adaputil.h"
  28. #include "winuser.h"
  29. #include <comdef.h>
  30. // Performance library processing list
  31. // ===================================
  32. CPerfLibList g_PerfLibList;
  33. HANDLE g_hAbort = NULL;
  34. /////////////////////////////////////////////////////////////////////////////
  35. //
  36. // returns the PID (the first found if many are there) if success
  37. // returns ZERO if fails
  38. //
  39. /////////////////////////////////////////////////////////////////////////////
  40. #define MAX_ITERATION 8
  41. #define MAX_MODULE (1024)
  42. DWORD GetExecPid()
  43. {
  44. DWORD ThisProc = 0;
  45. LONG lRet = 0;
  46. HKEY hKey;
  47. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  48. L"Software\\Microsoft\\WBEM\\CIMOM",
  49. NULL,
  50. KEY_READ,
  51. &hKey);
  52. if (ERROR_SUCCESS == lRet)
  53. {
  54. DWORD dwType;
  55. DWORD dwSize = sizeof(DWORD);
  56. RegQueryValueEx(hKey,
  57. L"ProcessID",
  58. NULL,
  59. &dwType,
  60. (BYTE*)&ThisProc,
  61. &dwSize);
  62. RegCloseKey(hKey);
  63. }
  64. return ThisProc;
  65. /*
  66. if (!ExecName){
  67. return 0;
  68. }
  69. DWORD i=1;
  70. DWORD ThisProc = 0;
  71. DWORD Size = i*MAX_MODULE;
  72. DWORD cbReturned = 0;
  73. DWORD * pProcId = new DWORD[Size];
  74. do {
  75. if (pProcId && EnumProcesses(pProcId,Size*sizeof(DWORD),&cbReturned)){
  76. break;
  77. } else {
  78. i++;
  79. delete [] pProcId;
  80. Size = i*MAX_MODULE;
  81. pProcId = new DWORD[Size];
  82. }
  83. } while ( (i<=8) );
  84. cbReturned /= sizeof(DWORD);
  85. if (pProcId && cbReturned) {
  86. DWORD SizeModules = MAX_MODULE;
  87. HMODULE * pModules = new HMODULE[SizeModules];
  88. if (pModules){
  89. for (DWORD j=0;j<cbReturned;j++)
  90. {
  91. HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
  92. PROCESS_VM_READ,
  93. FALSE, pProcId[j] );
  94. DWORD cbRetModules = 0;
  95. if (hProcess &&
  96. EnumProcessModules(hProcess,pModules,sizeof(DWORD)*SizeModules,&cbRetModules))
  97. {
  98. WCHAR ModuleName[MAX_PATH];
  99. if (GetModuleBaseNameW(hProcess,
  100. pModules[0], // first module is executable
  101. ModuleName,
  102. sizeof(ModuleName)/sizeof(WCHAR)))
  103. {
  104. if (0 == _wcsicmp(ExecName,ModuleName))
  105. {
  106. ThisProc = pProcId[j];
  107. CloseHandle(hProcess);
  108. hProcess = NULL;
  109. break;
  110. }
  111. };
  112. }
  113. if (hProcess)
  114. {
  115. CloseHandle(hProcess);
  116. hProcess = NULL;
  117. }
  118. }
  119. delete [] pModules;
  120. }
  121. }
  122. if (pProcId){
  123. delete [] pProcId;
  124. }
  125. return ThisProc;
  126. */
  127. }
  128. void DoResyncPerf( BOOL bDelta, BOOL bThrottle )
  129. {
  130. DEBUGTRACE((LOG_WINMGMT,"ADAP Resync has started\n"));
  131. g_hAbort = CreateEventW( NULL, TRUE, FALSE, L"ADAP_ABORT");
  132. CCloseMe cmAbort( g_hAbort );
  133. if ( NULL != g_hAbort )
  134. {
  135. HRESULT hr = WBEM_S_NO_ERROR;
  136. CAdapRegPerf regPerf(!bDelta);
  137. // Process each perflib that is registered on the system
  138. // =====================================================
  139. hr = regPerf.Initialize( bDelta, bThrottle );
  140. if ( SUCCEEDED( hr ) )
  141. {
  142. hr = regPerf.Dredge( bDelta, bThrottle );
  143. }
  144. if ( FAILED( hr ) )
  145. {
  146. CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_PROCESSING_FAILURE, CHex( hr ) );
  147. }
  148. }
  149. DEBUGTRACE((LOG_WINMGMT,"ADAP Resync has completed\n"));
  150. return;
  151. }
  152. void DoClearADAP()
  153. {
  154. DEBUGTRACE((LOG_WINMGMT,"ADAP registry reset has started\n"));
  155. CAdapRegPerf regPerf(FALSE);
  156. regPerf.Clean();
  157. DEBUGTRACE((LOG_WINMGMT,"ADAP registry reset has completed\n"));
  158. return;
  159. }
  160. HRESULT DoReverseAdapterMaintenance( BOOL bThrottle );
  161. /*
  162. {
  163. ERRORTRACE((LOG_WMIADAP,"DoReverseAdapterDredge called"));
  164. return WBEM_NO_ERROR;
  165. };
  166. */
  167. ///////////////////////////////////////////////////////////////////////////////
  168. //
  169. // Entry Point
  170. // ===========
  171. //
  172. ///////////////////////////////////////////////////////////////////////////////
  173. int WINAPI WinMain(
  174. HINSTANCE hInstance, // handle to current instance
  175. HINSTANCE hPrevInstance, // handle to previous instance
  176. LPSTR szCmdLine, // command line
  177. int nCmdShow // show state
  178. )
  179. {
  180. try
  181. {
  182. // Ensure that we are NT5 or better
  183. // ================================
  184. OSVERSIONINFO OSVer;
  185. OSVer.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
  186. if ( GetVersionEx( &OSVer ) )
  187. {
  188. if ( ! ( ( VER_PLATFORM_WIN32_NT == OSVer.dwPlatformId ) && ( 5 <= OSVer.dwMajorVersion ) ) )
  189. return 0;
  190. }
  191. else
  192. {
  193. return 0;
  194. }
  195. // To avoid messy dialog boxes...
  196. // ==============================
  197. SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX );
  198. // Initialize COM.
  199. // ===============
  200. InitializeCom();
  201. CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
  202. EOAC_NONE, NULL );
  203. // Get the Winmgmt service PID
  204. // ===========================
  205. DWORD dwPID = GetExecPid();
  206. // The semaphore is used so that no more that two copies are running at any time.
  207. // ==============================================================================
  208. WCHAR wszObjName[256];
  209. HANDLE hSemaphore;
  210. swprintf(wszObjName, L"WMI_SysEvent_Semaphore_%d", dwPID);
  211. hSemaphore = CreateSemaphoreW(NULL, 2, 2, wszObjName);
  212. if(hSemaphore == NULL)
  213. return 0;
  214. CCloseMe cm1(hSemaphore);
  215. DWORD dwRet = WaitForSingleObject(hSemaphore, 0);
  216. if(dwRet != WAIT_OBJECT_0)
  217. return 0;
  218. // The mutex makes sure that multiple copies are sequential.
  219. // =========================================================
  220. HANDLE hMutex;
  221. hMutex = CreateMutexW( NULL, FALSE, L"ADAP_WMI_ENTRY" );
  222. if(hMutex == NULL)
  223. return 0;
  224. CCloseMe cm2(hMutex);
  225. switch ( WaitForSingleObject( hMutex, 400000) )
  226. {
  227. case WAIT_ABANDONED:
  228. case WAIT_OBJECT_0:
  229. {
  230. BOOL bThrottle = FALSE;
  231. BOOL bFull = FALSE;
  232. BOOL bDelta = FALSE;
  233. BOOL bReverse = FALSE;
  234. BOOL bClear = FALSE;
  235. /*
  236. {
  237. char pBuff[64];
  238. sprintf(pBuff,"(ADAP) cmdline: %s\n",szCmdLine);
  239. OutputDebugStringA(szCmdLine);
  240. }
  241. */
  242. if (szCmdLine)
  243. {
  244. while (*szCmdLine)
  245. {
  246. while(*szCmdLine && isspace((UCHAR)*szCmdLine)){
  247. szCmdLine++;
  248. };
  249. if (*szCmdLine == '-' || *szCmdLine == '/')
  250. {
  251. szCmdLine++;
  252. if (toupper((UCHAR)*szCmdLine) == 'T'){
  253. bThrottle = TRUE;
  254. } else if (toupper((UCHAR)*szCmdLine) == 'R') {
  255. bReverse = TRUE;
  256. } else if (toupper((UCHAR)*szCmdLine) == 'F') {
  257. bFull = TRUE;
  258. } else if (toupper((UCHAR)*szCmdLine) == 'D') {
  259. bDelta = TRUE;
  260. } else if (toupper((UCHAR)*szCmdLine) == 'C') {
  261. bClear = TRUE;
  262. }
  263. }
  264. // move to the next white space
  265. while(*szCmdLine && !isspace(*szCmdLine)){
  266. szCmdLine++;
  267. }
  268. }
  269. }
  270. if (bClear) // ClearADAP and/or ReverseAdap
  271. {
  272. DoClearADAP();
  273. if (bReverse)
  274. DoReverseAdapterMaintenance( bThrottle );
  275. }
  276. else
  277. {
  278. if (!bFull && !bDelta && !bReverse)
  279. {
  280. // no options, use Delta NO-THROTTLE
  281. DoResyncPerf(TRUE,FALSE);
  282. }
  283. else
  284. {
  285. if (bFull) {
  286. DoResyncPerf(FALSE,bThrottle);
  287. }
  288. if (bDelta && !bFull) {
  289. DoResyncPerf(TRUE,bThrottle);
  290. }
  291. if (bReverse)
  292. DoReverseAdapterMaintenance( bThrottle );
  293. }
  294. }
  295. ReleaseMutex( hMutex );
  296. }break;
  297. }
  298. CoUninitialize();
  299. long l;
  300. ReleaseSemaphore(hSemaphore, 1, &l);
  301. }
  302. catch(...)
  303. {
  304. // <Gasp> We have been betrayed... try to write something to the error log
  305. // =======================================================================
  306. CriticalFailADAPTrace( "An unhandled exception has been thrown in the main thread." );
  307. }
  308. return 0;
  309. }
  310. ////////////////////////////////////////////////////////////////////////////////
  311. //
  312. // CPerfLibList
  313. //
  314. ////////////////////////////////////////////////////////////////////////////////
  315. HRESULT CPerfLibList::AddPerfLib( WCHAR* wszPerfLib )
  316. {
  317. HRESULT hr = WBEM_S_NO_ERROR;
  318. try
  319. {
  320. EnterCriticalSection( &m_csPerfLibList );
  321. {
  322. WCHAR* wszNew = NULL;
  323. // Compute the size of the new buffer
  324. // ==================================
  325. DWORD dwListSize = 0;
  326. if ( NULL != m_wszPerfLibList )
  327. {
  328. dwListSize += wcslen( m_wszPerfLibList );
  329. dwListSize += wcslen( ADAP_EVENT_MESSAGE_DELIM );
  330. }
  331. if ( NULL != wszPerfLib )
  332. {
  333. dwListSize += wcslen( wszPerfLib );
  334. }
  335. // Create the new buffer, and initialize the content
  336. // =================================================
  337. wszNew = new WCHAR[dwListSize + 1];
  338. // Copy the old buffer if required
  339. // ===============================
  340. if ( NULL != m_wszPerfLibList )
  341. {
  342. swprintf( wszNew, L"%s%s%s", m_wszPerfLibList, ADAP_EVENT_MESSAGE_DELIM, wszPerfLib );
  343. delete [] m_wszPerfLibList;
  344. }
  345. else
  346. {
  347. swprintf( wszNew, L"%s", wszPerfLib );
  348. }
  349. // And assign it to the static member
  350. // ==================================
  351. m_wszPerfLibList = wszNew;
  352. }
  353. LeaveCriticalSection( &m_csPerfLibList );
  354. }
  355. catch( unsigned int n )
  356. {
  357. // Handle the case where EnterCriticalSection() has throw an exception
  358. // ===================================================================
  359. if ( n == STATUS_INVALID_HANDLE )
  360. hr = WBEM_E_FAILED;
  361. else
  362. throw;
  363. }
  364. catch(...)
  365. {
  366. LeaveCriticalSection( &m_csPerfLibList );
  367. hr = WBEM_E_FAILED;
  368. }
  369. return hr;
  370. }
  371. HRESULT CPerfLibList::HandleFailure()
  372. {
  373. HRESULT hr = WBEM_S_NO_ERROR;
  374. try
  375. {
  376. char szMessage[ADAP_EVENT_MESSAGE_LENGTH];
  377. EnterCriticalSection( &m_csPerfLibList );
  378. {
  379. DWORD dwMessageLen = strlen( ADAP_EVENT_MESSAGE_PREFIX );
  380. if ( NULL != m_wszPerfLibList )
  381. {
  382. dwMessageLen += wcslen( m_wszPerfLibList );
  383. }
  384. if ( ADAP_EVENT_MESSAGE_LENGTH > dwMessageLen )
  385. {
  386. sprintf( szMessage, "%s%S\n", ADAP_EVENT_MESSAGE_PREFIX, (NULL != m_wszPerfLibList) ? m_wszPerfLibList : L"<NULL>" );
  387. }
  388. }
  389. LeaveCriticalSection( &m_csPerfLibList );
  390. CriticalFailADAPTrace( szMessage );
  391. }
  392. catch( unsigned int n )
  393. {
  394. // Handle the case where EnterCriticalSection() has throw an exception
  395. // ===================================================================
  396. if ( n == STATUS_INVALID_HANDLE )
  397. hr = WBEM_E_FAILED;
  398. else
  399. throw;
  400. }
  401. catch(...)
  402. {
  403. LeaveCriticalSection( &m_csPerfLibList );
  404. hr = WBEM_E_FAILED;
  405. }
  406. return hr;
  407. }
  408. ////////////////////////////////////////////////////////////////////////////////
  409. //
  410. // Static Members
  411. //
  412. ////////////////////////////////////////////////////////////////////////////////
  413. LONG CAdapRegPerf::AdapUnhandledExceptionFilter( LPEXCEPTION_POINTERS lpexpExceptionInfo )
  414. {
  415. // TODO: language specification
  416. g_PerfLibList.HandleFailure();
  417. return EXCEPTION_CONTINUE_SEARCH;
  418. }
  419. ////////////////////////////////////////////////////////////////////////////////
  420. //
  421. // CAdapRegPerf
  422. //
  423. ////////////////////////////////////////////////////////////////////////////////
  424. CAdapRegPerf::CAdapRegPerf(BOOL bFull)
  425. : m_pLocaleCache( NULL ),
  426. m_fQuit( FALSE ),
  427. m_dwPID( 0 ),
  428. m_pADAPStatus( NULL ),
  429. m_pRootDefault( NULL ),
  430. m_hRegChangeEvent( NULL ),
  431. m_hPerflibKey( NULL ),
  432. m_pKnownSvcs(NULL),
  433. m_bFull(bFull)
  434. {
  435. for ( DWORD dwType = 0; dwType < WMI_ADAP_NUM_TYPES; dwType++ )
  436. m_apMasterClassList[dwType] = NULL;
  437. }
  438. CAdapRegPerf::~CAdapRegPerf()
  439. {
  440. // Status: COMPLETE
  441. // ================
  442. SetADAPStatus( eADAPStatusFinished);
  443. //
  444. // Add TimeStamp to registry if FULL
  445. //
  446. if (m_bFull)
  447. {
  448. FILETIME FileTime;
  449. GetSystemTimeAsFileTime(&FileTime);
  450. LONG lRet;
  451. HKEY hKey;
  452. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  453. L"Software\\Microsoft\\WBEM\\CIMOM",
  454. NULL,
  455. KEY_WRITE,
  456. &hKey);
  457. if (ERROR_SUCCESS == lRet)
  458. {
  459. RegSetValueEx(hKey,
  460. ADAP_TIMESTAMP_FULL,
  461. NULL,
  462. REG_BINARY,
  463. (BYTE*)&FileTime,
  464. sizeof(FILETIME));
  465. RegCloseKey(hKey);
  466. }
  467. }
  468. if (m_pKnownSvcs)
  469. {
  470. m_pKnownSvcs->Save();
  471. m_pKnownSvcs->Release();
  472. }
  473. // Cleanup
  474. // =======
  475. for ( DWORD dwType = 0; dwType < WMI_ADAP_NUM_TYPES; dwType++ )
  476. {
  477. if ( NULL != m_apMasterClassList[dwType] )
  478. {
  479. m_apMasterClassList[dwType]->Release();
  480. }
  481. }
  482. if ( NULL != m_pLocaleCache )
  483. {
  484. m_pLocaleCache->Release();
  485. }
  486. if ( NULL != m_pRootDefault )
  487. {
  488. m_pRootDefault->Release();
  489. }
  490. if ( NULL != m_pADAPStatus )
  491. {
  492. m_pADAPStatus->Release();
  493. }
  494. if ( NULL != m_hPerflibKey )
  495. {
  496. RegCloseKey( m_hPerflibKey );
  497. }
  498. if ( NULL != m_hRegChangeEvent )
  499. {
  500. CloseHandle( m_hRegChangeEvent );
  501. }
  502. SetEvent( m_hTerminationEvent );
  503. }
  504. HRESULT CAdapRegPerf::Initialize(BOOL bDelta, BOOL bThrottle)
  505. ///////////////////////////////////////////////////////////////////////////////
  506. //
  507. // Initialize is responsible for setting up the dredging environment. The
  508. // unhandled exception filter is set to handle any exceptions throw and not
  509. // handled by perforance libraries. The termination event is a signal used
  510. // to identify when the process is being abnormally terminated. The
  511. // GoGershwin thread is suitably named since it is something to watch over
  512. // over the main process. The locale cache is a cache of all locales
  513. // available in the performance domain (enumeration of the names' database
  514. // subkeys). The master class lists for both the cooked and the raw classes
  515. // represent the state of the performance objects in WMI.
  516. //
  517. // Parameters:
  518. // none
  519. //
  520. ///////////////////////////////////////////////////////////////////////////////
  521. {
  522. HRESULT hr = WBEM_NO_ERROR;
  523. // Initialize the root\default pointer. This will be used to track our status
  524. // ==========================================================================
  525. GetADAPStatusObject();
  526. // Set the filter for handling unhandled exceptions thrown in threads generated by the perflibs
  527. // ============================================================================================
  528. SetUnhandledExceptionFilter( CAdapRegPerf::AdapUnhandledExceptionFilter );
  529. // ADAP termination event
  530. // ======================
  531. m_hTerminationEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  532. if ( NULL == m_hTerminationEvent )
  533. {
  534. hr = WBEM_E_FAILED;
  535. }
  536. // Open the registry key to be monitored
  537. // =====================================
  538. if ( SUCCEEDED( hr ) )
  539. {
  540. if ( ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"), 0, KEY_NOTIFY, &m_hPerflibKey ) )
  541. {
  542. hr = WBEM_E_FAILED;
  543. }
  544. }
  545. // Create the registry change event
  546. // ================================
  547. if ( SUCCEEDED( hr ) )
  548. {
  549. m_hRegChangeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  550. if ( NULL == m_hRegChangeEvent )
  551. {
  552. hr = WBEM_E_FAILED;
  553. }
  554. }
  555. // Create the names' database change notification
  556. // ==============================================
  557. // Note that we are only looking for subkeys being added or deleted. We do
  558. // not want to monitor the registry values since the status and signature
  559. // values may be changing throughout the course of the dredge, and we do
  560. // not want to cause a re-cache unless a performance library is added
  561. // (i.e. a performance subkey is added
  562. if ( SUCCEEDED( hr ) )
  563. {
  564. if ( ERROR_SUCCESS != RegNotifyChangeKeyValue( m_hPerflibKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, m_hRegChangeEvent, TRUE ) )
  565. {
  566. hr = WBEM_E_FAILED;
  567. }
  568. }
  569. // Get the WinMgmt Service PID
  570. // ===========================
  571. if ( SUCCEEDED( hr ) )
  572. {
  573. m_dwPID = GetExecPid();
  574. }
  575. // Create the "Someone to watch over me" thread
  576. // ============================================
  577. if ( SUCCEEDED( hr ) )
  578. {
  579. UINT nThreadID = 0;
  580. m_hSyncThread = ( HANDLE ) _beginthreadex( NULL, 0, CAdapRegPerf::GoGershwin, (void*) this, 0, &nThreadID );
  581. DEBUGTRACE ( ( LOG_WMIADAP, "The Monitor thread ID is 0x%x\n", nThreadID ) );
  582. if ( (HANDLE)-1 == m_hSyncThread )
  583. {
  584. hr = WBEM_E_FAILED;
  585. }
  586. }
  587. // Set up the locale cache
  588. // =======================
  589. if ( SUCCEEDED( hr ) )
  590. {
  591. m_pLocaleCache = new CLocaleCache( );
  592. if ( NULL == m_pLocaleCache )
  593. {
  594. hr = WBEM_E_OUT_OF_MEMORY;
  595. }
  596. else
  597. {
  598. hr = m_pLocaleCache->Initialize();
  599. }
  600. }
  601. //
  602. //
  603. m_pKnownSvcs = new CKnownSvcs();
  604. if (m_pKnownSvcs)
  605. m_pKnownSvcs->Load();
  606. // Set up the master class lists for the raw classes
  607. // =================================================
  608. if ( SUCCEEDED( hr ) )
  609. {
  610. m_apMasterClassList[WMI_ADAP_RAW_CLASS] = new CMasterClassList( m_pLocaleCache, m_pKnownSvcs );
  611. if ( NULL != m_apMasterClassList[WMI_ADAP_RAW_CLASS] )
  612. {
  613. hr = m_apMasterClassList[WMI_ADAP_RAW_CLASS]->BuildList( ADAP_PERF_RAW_BASE_CLASS, bDelta, bThrottle );
  614. }
  615. else
  616. {
  617. hr = WBEM_E_OUT_OF_MEMORY;
  618. }
  619. }
  620. // Set up the master class lists for the cooked classes
  621. // ====================================================
  622. if ( SUCCEEDED( hr ) )
  623. {
  624. m_apMasterClassList[WMI_ADAP_COOKED_CLASS] = new CMasterClassList( m_pLocaleCache, m_pKnownSvcs );
  625. if ( NULL != m_apMasterClassList[WMI_ADAP_COOKED_CLASS] )
  626. {
  627. m_apMasterClassList[WMI_ADAP_COOKED_CLASS]->BuildList( ADAP_PERF_COOKED_BASE_CLASS, bDelta, bThrottle );
  628. }
  629. else
  630. {
  631. hr = WBEM_E_OUT_OF_MEMORY;
  632. }
  633. }
  634. #ifdef _DUMP_LIST
  635. m_apMasterClassList[WMI_ADAP_RAW_CLASS]->Dump();
  636. m_apMasterClassList[WMI_ADAP_COOKED_CLASS]->Dump();
  637. #endif
  638. return hr;
  639. }
  640. HRESULT CAdapRegPerf::Dredge( BOOL bDelta, BOOL bThrottle )
  641. ///////////////////////////////////////////////////////////////////////////////
  642. //
  643. // This is the entry point method which dredges the registry for performance
  644. // counters and registers the classes in WMI. This method enumerates all of
  645. // the service keys looking for 'Performance' subkeys which indicate
  646. // performance libraries. If a library is discovered, then it is sent to
  647. // the ProcessLibrary method for, you guessed it, processing.
  648. //
  649. // Parameters:
  650. // none
  651. //
  652. ///////////////////////////////////////////////////////////////////////////////
  653. {
  654. HRESULT hr = WBEM_S_NO_ERROR;
  655. WString wstrServiceKey,
  656. wstrPerformanceKey;
  657. if ( SUCCEEDED( hr ) )
  658. {
  659. // Status: PROCESSING
  660. // ==================
  661. SetADAPStatus( eADAPStatusProcessLibs);
  662. // Open the services key
  663. // =====================
  664. long lError = Open( HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services" );
  665. if ( CNTRegistry::no_error == lError )
  666. {
  667. // Iterate through the services list
  668. // =================================
  669. DWORD dwIndex = 0;
  670. DWORD dwBuffSize = 0;
  671. WCHAR* pwcsServiceName = NULL;
  672. while ( ( CNTRegistry::no_error == lError ) && ( !m_fQuit ) )
  673. {
  674. // Reset the processing status
  675. // ===========================
  676. hr = WBEM_NO_ERROR;
  677. if ( WAIT_OBJECT_0 == WaitForSingleObject( m_hRegChangeEvent, 0 ) )
  678. {
  679. m_pLocaleCache->Reset();
  680. dwIndex = 0;
  681. // Reset the event and reset the change notification
  682. ResetEvent( m_hRegChangeEvent );
  683. RegNotifyChangeKeyValue( m_hPerflibKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, m_hRegChangeEvent, TRUE );
  684. }
  685. // For each service name, we will check for a performance
  686. // key and if it exists, we will process the library
  687. // ======================================================
  688. lError = Enum( dwIndex, &pwcsServiceName , dwBuffSize );
  689. if (bThrottle)
  690. {
  691. HRESULT hrThr = Throttle(THROTTLE_USER|THROTTLE_IO,
  692. ADAP_IDLE_USER,
  693. ADAP_IDLE_IO,
  694. ADAP_LOOP_SLEEP,
  695. ADAP_MAX_WAIT);
  696. if (THROTTLE_FORCE_EXIT == hrThr)
  697. {
  698. //OutputDebugStringA("(ADAP) Unthrottle command received\n");
  699. bThrottle = FALSE;
  700. UNICODE_STRING BaseUnicodeCommandLine = NtCurrentPeb()->ProcessParameters->CommandLine;
  701. WCHAR * pT = wcschr(BaseUnicodeCommandLine.Buffer,L't');
  702. if (0 == pT)
  703. pT = wcschr(BaseUnicodeCommandLine.Buffer,L'T');
  704. if (pT)
  705. {
  706. *pT = L' ';
  707. pT--;
  708. *pT = L' ';
  709. }
  710. }
  711. }
  712. if ( CNTRegistry::no_error == lError )
  713. {
  714. try
  715. {
  716. // Create the perfomance key path
  717. // ==============================
  718. wstrServiceKey = L"SYSTEM\\CurrentControlSet\\Services\\";
  719. wstrServiceKey += pwcsServiceName;
  720. wstrPerformanceKey = wstrServiceKey;
  721. wstrPerformanceKey += L"\\Performance";
  722. }
  723. catch( ... )
  724. {
  725. hr = WBEM_E_OUT_OF_MEMORY;
  726. }
  727. if ( SUCCEEDED( hr ) )
  728. {
  729. CNTRegistry reg;
  730. // Atempt to open the performance registry key for the service
  731. // ===========================================================
  732. long lPerfError = reg.Open( HKEY_LOCAL_MACHINE, wstrPerformanceKey );
  733. if ( CNTRegistry::no_error == lPerfError )
  734. {
  735. // If we can open it, then we have found a perflib! Process it
  736. // unless it is the reverse provider perflib
  737. // =============================================================
  738. if ( 0 != _wcsicmp( pwcsServiceName, WMI_ADAP_REVERSE_PERFLIB ) )
  739. {
  740. hr = ProcessLibrary( pwcsServiceName, bDelta );
  741. }
  742. }
  743. else if ( CNTRegistry::access_denied == lPerfError )
  744. {
  745. ServiceRec * pSvcRec = NULL;
  746. if (0 == m_pKnownSvcs->Get(pwcsServiceName,&pSvcRec))
  747. {
  748. if (!pSvcRec->IsELCalled())
  749. {
  750. CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
  751. WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
  752. (LPCWSTR)wstrPerformanceKey, L"Access Denied" );
  753. pSvcRec->SetELCalled();
  754. }
  755. }
  756. }
  757. else
  758. {
  759. // Otherwise, it is not a perflib service
  760. // ======================================
  761. }
  762. }
  763. }
  764. else if ( CNTRegistry::no_more_items != lError )
  765. {
  766. if ( CNTRegistry::out_of_memory == lError )
  767. {
  768. hr = WBEM_E_OUT_OF_MEMORY;
  769. }
  770. else
  771. {
  772. hr = WBEM_E_FAILED;
  773. }
  774. }
  775. dwIndex++;
  776. }
  777. // Cleanup the service name buffer
  778. // ===============================
  779. if ( NULL != pwcsServiceName )
  780. {
  781. delete [] pwcsServiceName;
  782. pwcsServiceName = NULL;
  783. }
  784. }
  785. else if ( CNTRegistry::access_denied == lError )
  786. {
  787. CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE, L"SYSTEM\\CurrentControlSet\\Services\\", L"Access Denied" );
  788. hr = WBEM_E_FAILED;
  789. }
  790. else
  791. {
  792. hr = WBEM_E_FAILED;
  793. }
  794. // Now that we have a master class list that contains updated
  795. // data from all of the perflibs, commit any changes to WMI
  796. // ==========================================================
  797. if ( SUCCEEDED ( hr ) && ( !m_fQuit ) )
  798. {
  799. // Status: COMMIT
  800. // ==============
  801. SetADAPStatus( eADAPStatusCommit );
  802. for ( DWORD dwType = 0; dwType < WMI_ADAP_NUM_TYPES; dwType++ )
  803. {
  804. m_apMasterClassList[dwType]->Commit(bThrottle);
  805. }
  806. }
  807. }
  808. if ( SUCCEEDED( hr ) )
  809. {
  810. DEBUGTRACE( ( LOG_WMIADAP, "CAdapRegPerf::Dredge() for %S succeeded.\n", (WCHAR *)wstrServiceKey ) );
  811. }
  812. else
  813. {
  814. ERRORTRACE( ( LOG_WMIADAP, "CAdapRegPerf::Dredge() failed: %X.\n", hr ) );
  815. }
  816. return hr;
  817. }
  818. HRESULT CAdapRegPerf::Clean()
  819. ////////////////////////////////////////////////////////////////////////////////
  820. //
  821. // This method enumerates all of the keys from the
  822. // HLM\System\CurrentControlSet\Services and searches for a performance subkey.
  823. // If a performance subkey is discovered, then any information that was placed
  824. // in the key by ADAP is deleted.
  825. //
  826. // Parameters:
  827. // none
  828. //
  829. ////////////////////////////////////////////////////////////////////////////////
  830. {
  831. HRESULT hr = WBEM_S_NO_ERROR;
  832. WString wstrServiceKey, // The path to the service key
  833. wstrPerformanceKey; // The path to the performance subkey
  834. CNTRegistry regOuter; // The registry object for the services enumeration
  835. // Open the services key
  836. // =====================
  837. long lError = regOuter.Open( HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services" );
  838. if ( CNTRegistry::no_error == lError )
  839. {
  840. // Iterate through the services list
  841. // =================================
  842. DWORD dwIndex = 0;
  843. DWORD dwBuffSize = 0;
  844. WCHAR* pwcsServiceName = NULL;
  845. while ( CNTRegistry::no_error == lError )
  846. {
  847. // Reset the processing status
  848. // ===========================
  849. hr = WBEM_NO_ERROR;
  850. // For each service name, we will check for a performance
  851. // key and if it exists, we will process the library
  852. // ======================================================
  853. lError = regOuter.Enum( dwIndex, &pwcsServiceName , dwBuffSize );
  854. if ( CNTRegistry::no_error == lError )
  855. {
  856. try
  857. {
  858. // Create the perfomance key path
  859. // ==============================
  860. wstrServiceKey = L"SYSTEM\\CurrentControlSet\\Services\\";
  861. wstrServiceKey += pwcsServiceName;
  862. wstrPerformanceKey = wstrServiceKey;
  863. wstrPerformanceKey += L"\\Performance";
  864. }
  865. catch( ... )
  866. {
  867. hr = WBEM_E_OUT_OF_MEMORY;
  868. }
  869. if ( SUCCEEDED( hr ) )
  870. {
  871. CNTRegistry regInner; // The registry object for the performance subkey
  872. // Atempt to open the performance registry key for the service
  873. // ===========================================================
  874. long lPerfError = regInner.Open( HKEY_LOCAL_MACHINE, wstrPerformanceKey );
  875. if ( CNTRegistry::no_error == lPerfError )
  876. {
  877. // If we can open it, then we have found a perflib! Clean it!
  878. // =============================================================
  879. regInner.DeleteValue( ADAP_PERFLIB_STATUS_KEY );
  880. regInner.DeleteValue( ADAP_PERFLIB_SIGNATURE );
  881. regInner.DeleteValue( ADAP_PERFLIB_SIZE );
  882. regInner.DeleteValue( ADAP_PERFLIB_TIME );
  883. }
  884. else if ( CNTRegistry::access_denied == lPerfError )
  885. {
  886. CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
  887. WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
  888. (LPCWSTR)wstrPerformanceKey, L"Access Denied" );
  889. }
  890. else
  891. {
  892. // Otherwise, it is not a perflib service
  893. // ======================================
  894. }
  895. }
  896. }
  897. else if ( CNTRegistry::no_more_items != lError )
  898. {
  899. if ( CNTRegistry::out_of_memory == lError )
  900. {
  901. hr = WBEM_E_OUT_OF_MEMORY;
  902. }
  903. else
  904. {
  905. hr = WBEM_E_FAILED;
  906. }
  907. }
  908. dwIndex++;
  909. }
  910. // Cleanup the service name buffer
  911. // ===============================
  912. if ( NULL != pwcsServiceName )
  913. {
  914. delete [] pwcsServiceName;
  915. pwcsServiceName = NULL;
  916. }
  917. }
  918. else if ( CNTRegistry::access_denied == lError )
  919. {
  920. CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE, L"SYSTEM\\CurrentControlSet\\Services\\", L"Access Denied" );
  921. hr = WBEM_E_FAILED;
  922. }
  923. else
  924. {
  925. hr = WBEM_E_FAILED;
  926. }
  927. if ( SUCCEEDED( hr ) )
  928. {
  929. DEBUGTRACE( ( LOG_WMIADAP, "CAdapRegPerf::Clean() succeeded.\n" ) );
  930. }
  931. else
  932. {
  933. ERRORTRACE( ( LOG_WMIADAP, "CAdapRegPerf::Clean() failed: %X.\n", hr ) );
  934. }
  935. return hr;
  936. }
  937. HRESULT CAdapRegPerf::ProcessLibrary( WCHAR* pwcsServiceName, BOOL bDelta )
  938. ///////////////////////////////////////////////////////////////////////////////
  939. //
  940. // Once a performance library has been discovered, then it's schema must be
  941. // retrieved and the performance library's class list compared to what is
  942. // already in the WMI repository. The comparison is achieved in the "Merge"
  943. // method of the master class list which extracts any classes from the perf
  944. // lib's class list that are not already in the master class list. The
  945. // comparison occurs for both the raw and the cooked classes.
  946. //
  947. // Parameters:
  948. // pwcsServiceName - The name of the service to be processed
  949. //
  950. ///////////////////////////////////////////////////////////////////////////////
  951. {
  952. HRESULT hr = WBEM_NO_ERROR;
  953. try
  954. {
  955. // Add the name of the performance library to the perflib list
  956. // ===========================================================
  957. // The list is used for book keeping purposses to track processing
  958. // in the event of a perflib failure
  959. g_PerfLibList.AddPerfLib( pwcsServiceName );
  960. // Construct and initialize the schema for the perflib
  961. // ===================================================
  962. DWORD LoadStatus = EX_STATUS_UNLOADED;
  963. CPerfLibSchema Schema( pwcsServiceName, m_pLocaleCache );
  964. hr = Schema.Initialize( bDelta, &LoadStatus );
  965. DEBUGTRACE(( LOG_WMIADAP,"CPerfLibSchema::Initialize for %S hr %08x\n",pwcsServiceName,hr));
  966. if ( !bDelta || ( bDelta && ( hr != WBEM_S_ALREADY_EXISTS ) ) )
  967. {
  968. // Update raw and cooked classes
  969. // =============================
  970. for ( DWORD dwType = 0; ( dwType < WMI_ADAP_NUM_TYPES ) && SUCCEEDED( hr ); dwType++ )
  971. {
  972. // Get the class list for classes from the perflib's schema
  973. // ========================================================
  974. CClassList* pClassList = NULL;
  975. hr = Schema.GetClassList( dwType, &pClassList );
  976. CAdapReleaseMe rmClassList( pClassList );
  977. DEBUGTRACE(( LOG_WMIADAP,"GetClassList for %S hr %08x\n",pwcsServiceName,hr));
  978. if ( SUCCEEDED( hr ) )
  979. {
  980. // Merge the raw classes obtained from the perflib into the master class list
  981. // ==========================================================================
  982. hr = m_apMasterClassList[dwType]->Merge( pClassList, bDelta );
  983. DEBUGTRACE(( LOG_WMIADAP,"m_apMasterClassList[%d]->Merge for %S hr %08x\n",dwType,pwcsServiceName,hr));
  984. }
  985. //if (bDelta && FAILED(hr)){
  986. // // the class was not in the repository if we are here
  987. // LoadStatus = EX_STATUS_UNLOADED;
  988. //}
  989. }
  990. };
  991. if (FAILED(hr) && (LoadStatus != EX_STATUS_LOADABLE))
  992. {
  993. for ( DWORD dwType = 0; ( dwType < WMI_ADAP_NUM_TYPES ) ; dwType++ )
  994. {
  995. DEBUGTRACE((LOG_WMIADAP,"ProcessLibrary ForceStatus for %S hr = %08x\n",pwcsServiceName,hr));
  996. DWORD NewStatus = ADAP_OBJECT_IS_DELETED;
  997. if (LoadStatus == EX_STATUS_UNLOADED)
  998. {
  999. NewStatus |= ADAP_OBJECT_IS_TO_BE_CLEARED;
  1000. }
  1001. m_apMasterClassList[dwType]->ForceStatus(pwcsServiceName,TRUE,NewStatus);
  1002. }
  1003. }
  1004. }
  1005. catch(...)
  1006. {
  1007. hr = WBEM_E_OUT_OF_MEMORY;
  1008. }
  1009. return hr;
  1010. }
  1011. unsigned int CAdapRegPerf::GoGershwin( void* pParam )
  1012. ///////////////////////////////////////////////////////////////////////////////
  1013. //
  1014. // The monitoring thread entry point
  1015. //
  1016. ///////////////////////////////////////////////////////////////////////////////
  1017. {
  1018. HRESULT hr = WBEM_S_NO_ERROR;
  1019. try
  1020. {
  1021. CAdapRegPerf* pThis = (CAdapRegPerf*)pParam;
  1022. HANDLE ahHandles[2];
  1023. // If we don't have an initialized PID, then find one from WMI
  1024. // ===========================================================
  1025. if ( 0 == pThis->m_dwPID )
  1026. {
  1027. pThis->m_dwPID = GetExecPid();
  1028. }
  1029. // Get the process handle and wait for a signal
  1030. // ============================================
  1031. if ( SUCCEEDED( hr ) && ( 0 != pThis->m_dwPID ) )
  1032. {
  1033. ahHandles[0] = OpenProcess( SYNCHRONIZE, FALSE, pThis->m_dwPID );
  1034. CCloseMe cmProcess( ahHandles[0] );
  1035. ahHandles[1] = pThis->m_hTerminationEvent;
  1036. DWORD dwRet = WaitForMultipleObjects( 2, ahHandles, FALSE, INFINITE );
  1037. switch ( dwRet )
  1038. {
  1039. case WAIT_FAILED: // Something is wierd
  1040. case WAIT_OBJECT_0: // The service process
  1041. {
  1042. pThis->m_fQuit = TRUE; // Set the termination flag
  1043. } break;
  1044. case ( WAIT_OBJECT_0 + 1 ): // The completion event
  1045. {
  1046. // continue
  1047. }break;
  1048. }
  1049. }
  1050. }
  1051. catch(...)
  1052. {
  1053. // <Gasp> We have been betrayed... try to write something to the error log
  1054. // =======================================================================
  1055. CriticalFailADAPTrace( "An unhandled exception has been thrown in the WMI monitoring thread." );
  1056. }
  1057. return 0;
  1058. }
  1059. HRESULT CAdapRegPerf::GetADAPStatusObject( void )
  1060. {
  1061. IWbemLocator* pLocator = NULL;
  1062. HRESULT hr = CoCreateInstance( CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator,
  1063. (void**) &pLocator );
  1064. CReleaseMe rm( pLocator );
  1065. if ( SUCCEEDED( hr ) )
  1066. {
  1067. BSTR bstrNameSpace = SysAllocString( L"root\\default" );
  1068. BSTR bstrInstancePath = SysAllocString( L"__ADAPStatus=@" );
  1069. CSysFreeMe sfm1( bstrNameSpace );
  1070. CSysFreeMe sfm2( bstrInstancePath );
  1071. if ( NULL != bstrNameSpace && NULL != bstrInstancePath )
  1072. {
  1073. // Connect to Root\default and get hold of the status object
  1074. hr = pLocator->ConnectServer( bstrNameSpace, // NameSpace Name
  1075. NULL, // UserName
  1076. NULL, // Password
  1077. NULL, // Locale
  1078. 0L, // Security Flags
  1079. NULL, // Authority
  1080. NULL, // Wbem Context
  1081. &m_pRootDefault // Namespace
  1082. );
  1083. if ( SUCCEEDED( hr ) )
  1084. {
  1085. // Set Interface security
  1086. hr = WbemSetProxyBlanket( m_pRootDefault, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
  1087. RPC_C_AUTHN_LEVEL_PKT,RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
  1088. if ( SUCCEEDED( hr ) )
  1089. {
  1090. hr = m_pRootDefault->GetObject( bstrInstancePath, 0L, NULL, &m_pADAPStatus, NULL );
  1091. if ( SUCCEEDED( hr ) )
  1092. {
  1093. SetADAPStatus( eADAPStatusRunning );
  1094. }
  1095. }
  1096. }
  1097. }
  1098. else
  1099. {
  1100. hr = WBEM_E_OUT_OF_MEMORY;
  1101. }
  1102. } // IF got locator
  1103. return hr;
  1104. }
  1105. // Gets the time in the popular DMTF format
  1106. void CAdapRegPerf::GetTime( LPWSTR Buff )
  1107. {
  1108. SYSTEMTIME st;
  1109. int Bias=0;
  1110. char cOffsetSign = '+';
  1111. GetLocalTime( &st );
  1112. TIME_ZONE_INFORMATION ZoneInformation;
  1113. DWORD dwRet = GetTimeZoneInformation(&ZoneInformation);
  1114. if(dwRet != TIME_ZONE_ID_UNKNOWN)
  1115. Bias = -ZoneInformation.Bias;
  1116. if(Bias < 0)
  1117. {
  1118. cOffsetSign = '-';
  1119. Bias = -Bias;
  1120. }
  1121. swprintf(Buff, L"%4d%02d%02d%02d%02d%02d.%06d%c%03d",
  1122. st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute,
  1123. st.wSecond, st.wMilliseconds*1000, cOffsetSign, Bias);
  1124. }
  1125. // Sets the status back in WMI
  1126. void CAdapRegPerf::SetADAPStatus( eADAPStatus status )
  1127. {
  1128. // Make sure we've got both our pointers
  1129. if ( NULL != m_pRootDefault && NULL != m_pADAPStatus )
  1130. {
  1131. // We only need 25 characters for this
  1132. WCHAR wcsTime[32];
  1133. _variant_t var;
  1134. // legacy fastprox behavior
  1135. WCHAR pNum[16];
  1136. wsprintfW(pNum,L"%u",status);
  1137. var = pNum;
  1138. HRESULT hr = m_pADAPStatus->Put( L"Status", 0L, &var, 0 );//CIM_UINT32 );
  1139. if ( SUCCEEDED( hr ) )
  1140. {
  1141. // Set the time property if necessary
  1142. if ( status == eADAPStatusRunning || status == eADAPStatusFinished )
  1143. {
  1144. GetTime( wcsTime );
  1145. // This can fail
  1146. try
  1147. {
  1148. var = wcsTime;
  1149. }
  1150. catch(...)
  1151. {
  1152. hr = WBEM_E_OUT_OF_MEMORY;
  1153. }
  1154. if ( SUCCEEDED( hr ) )
  1155. {
  1156. hr = ( status == eADAPStatusRunning ?
  1157. m_pADAPStatus->Put( L"LastStartTime", 0L, &var, CIM_DATETIME ) :
  1158. m_pADAPStatus->Put( L"LastStopTime", 0L, &var, CIM_DATETIME ) );
  1159. }
  1160. }
  1161. if ( SUCCEEDED( hr ) )
  1162. {
  1163. hr = m_pRootDefault->PutInstance( m_pADAPStatus, 0L, NULL, NULL );
  1164. }
  1165. } // Set the Status property
  1166. } // Make sure we've got both pointers
  1167. }