home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / perfmon / perfdata.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-19  |  69.0 KB  |  2,468 lines

  1. //==========================================================================//
  2. //                                  Includes                                //
  3. //==========================================================================//
  4.  
  5.  
  6. #include <string.h>     // strupr
  7. #include <stdio.h>   // for sprintf.
  8. #include "perfmon.h"
  9. #include "utils.h"
  10.  
  11. #include "pmemory.h"        // for MemoryXXX (mallloc-type) routines
  12. #include "playback.h"   // for PlayingBackLog
  13. #include "perfdata.h"   // external declarations for this file
  14. #include "system.h"     // for DeleteUnusedSystems
  15. #include "line.h"       // for LineFind???()
  16. #include "perfmops.h"   // for AppendObjectToValueList()
  17.  
  18. //==========================================================================//
  19. //                                  Constants                               //
  20. //==========================================================================//
  21.  
  22. TCHAR NamesKey[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
  23. TCHAR Counters[] = L"Counters";
  24. TCHAR Help[] = L"Help";
  25. TCHAR LastHelp[] = L"Last Help";
  26. TCHAR LastCounter[] = L"Last Counter";
  27. TCHAR SysVersion[] = L"Version";
  28. TCHAR CounterNameStr[] = L"Counter ";
  29. TCHAR ExplainNameStr[] = L"Explain ";
  30.  
  31. #define szPerfSubkey      (NULL)
  32. TCHAR   NULL_NAME[] = L" ";
  33. #define RESERVED    0L
  34.  
  35. TCHAR          DefaultLangId[4] ;
  36. TCHAR          EnglishLangId[4] ;
  37.  
  38. static   HANDLE            *lpHandles ;
  39. static   int               NumberOfHandles = 0 ;
  40.  
  41. //==========================================================================//
  42. //                                   Macros                                 //
  43. //==========================================================================//
  44.  
  45.  
  46.  
  47. //==========================================================================//
  48. //                                Local Data                                //
  49. //==========================================================================//
  50.  
  51.  
  52. // When the conversion of this code is complete, this will be the *only*
  53. // allocated copy of the performance data.  It will monotonically grow
  54. // to hold the largest of the system's performance data.
  55.  
  56. // PPERFDATA      pGlobalPerfData ;
  57.  
  58. //==========================================================================//
  59. //                              Local Functions                             //
  60. //==========================================================================//
  61.  
  62. NTSTATUS  AddNamesToArray (LPTSTR pNames,
  63.    DWORD    dwLastID,
  64.    LPWSTR   *lpCounterId) ;
  65.  
  66. //======================================//
  67. // Object Accessors                     //
  68. //======================================//
  69.  
  70.  
  71. void ObjectName (PPERFSYSTEM pSystem,
  72.                  PPERFOBJECT pObject, 
  73.                  LPTSTR lpszName, 
  74.                  int iLen)
  75.    {  // ObjectName
  76.    strclr (lpszName) ;
  77.    QueryPerformanceName (pSystem, 
  78.                          pObject->ObjectNameTitleIndex, 
  79.                          0, iLen, lpszName, FALSE) ;
  80.    }  // ObjectName
  81.  
  82.  
  83.  
  84. //======================================//
  85. // Counter Accessors                    //
  86. //======================================//
  87.  
  88.  
  89. PERF_INSTANCE_DEFINITION *
  90. FirstInstance(
  91.     PERF_OBJECT_TYPE *pObjectDef)
  92. {
  93.     return (PERF_INSTANCE_DEFINITION *)
  94.                ((PCHAR) pObjectDef + pObjectDef->DefinitionLength);
  95. }
  96.  
  97.  
  98. PERF_INSTANCE_DEFINITION *
  99. NextInstance(
  100.     PERF_INSTANCE_DEFINITION *pInstDef)
  101. {
  102.     PERF_COUNTER_BLOCK *pCounterBlock;
  103.  
  104.     pCounterBlock = (PERF_COUNTER_BLOCK *)
  105.                         ((PCHAR) pInstDef + pInstDef->ByteLength);
  106.  
  107.     return (PERF_INSTANCE_DEFINITION *)
  108.                ((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
  109. }
  110.  
  111.  
  112.  
  113.  
  114. LPTSTR
  115. GetInstanceName(
  116. PPERFINSTANCEDEF  pInstDef)
  117. {
  118.     return (LPTSTR) ((PCHAR) pInstDef + pInstDef->NameOffset);
  119. }
  120.  
  121.  
  122. void
  123. GetInstanceNameStr (PPERFINSTANCEDEF pInstance,
  124.                     LPTSTR lpszInstance)
  125.    {
  126.    LPSTR pSource;
  127.  
  128.    pSource = (LPSTR) GetInstanceName(pInstance) ;
  129.  
  130.    if (pSource[1] == '\0' && pSource[2] != '\0')
  131.       {
  132.       // Must be Unicode
  133.       wcsncpy (lpszInstance,
  134.                (LPTSTR)pSource,
  135.                pInstance->NameLength);
  136.       }
  137.    else
  138.       {
  139.       // Must be ANSI (or a single Unicode character)
  140.       mbstowcs (lpszInstance,
  141.                 pSource,
  142.                 pInstance->NameLength);
  143.       }
  144.  
  145.    }
  146.  
  147. void
  148. GetPerfComputerName(PPERFDATA pPerfData,
  149.                     LPTSTR lpszComputerName)
  150.    {
  151.    lstrcpy(lpszComputerName, szComputerPrefix) ;
  152.    if (pPerfData)
  153.       {
  154.       wcsncpy (&lpszComputerName[2],
  155.                (LPWSTR)((PBYTE) pPerfData + pPerfData->SystemNameOffset),
  156.                pPerfData->SystemNameLength/sizeof(WCHAR)) ;
  157.       }
  158.    else
  159.       {
  160.       lpszComputerName[0] = TEXT('\0') ;
  161.       }
  162.    }
  163.  
  164.  
  165. //==========================================================================//
  166. //                             Exported Functions                           //
  167. //==========================================================================//
  168.  
  169.  
  170. int CounterIndex (PPERFCOUNTERDEF pCounterToFind,
  171.                   PPERFOBJECT pObject)
  172. /*
  173.    Effect:        Return the index ("counter number") of pCounterToFind
  174.                   within pObject. If the counter doesnt belong to pObject,
  175.                   return -1.
  176. */
  177.    {  // CounterIndex
  178.    PPERFCOUNTERDEF   pCounter ;
  179.    UINT              iCounter ;
  180.  
  181.    for (iCounter = 0, pCounter = FirstCounter (pObject) ;
  182.         iCounter < pObject->NumCounters ;
  183.         iCounter++, pCounter = NextCounter (pCounter))
  184.       {  // for
  185.       if (pCounter->CounterNameTitleIndex == 
  186.           pCounterToFind->CounterNameTitleIndex)
  187.          return (iCounter) ;
  188.       }  // for
  189.  
  190.    return (-1) ;
  191.    }  // CounterIndex
  192.  
  193.  
  194. HKEY
  195. OpenSystemPerfData (
  196.     IN LPCTSTR lpszSystem
  197. )
  198. {  // OpenSystemPerfData
  199.  
  200.     HKEY    hKey = NULL;
  201.     LONG    lStatus;
  202.  
  203.  
  204.     lStatus = ERROR_CANTOPEN;   // default error if none is returned
  205.  
  206.     if (IsLocalComputer(lpszSystem) || PlayingBackLog()) {
  207.         bCloseLocalMachine = TRUE ;
  208.         SetLastError (ERROR_SUCCESS);
  209.         return HKEY_PERFORMANCE_DATA;
  210.     } else if (lstrlen (lpszSystem) < MAX_COMPUTERNAME_LENGTH+3) {
  211.         // Must be a remote system
  212.         try {
  213.             lStatus = RegConnectRegistry (
  214.                 (LPTSTR)lpszSystem,
  215.                 HKEY_PERFORMANCE_DATA,
  216.                 &hKey);
  217.         } finally {
  218.             if (lStatus != ERROR_SUCCESS) {
  219.                 SetLastError (lStatus);
  220.                 hKey = NULL;
  221.             }
  222.         }
  223.     }
  224.     return (hKey);
  225.  
  226. }  // OpenSystemPerfData
  227.  
  228. LPWSTR
  229. *AddNewName(
  230.     HKEY    hKeyNames,
  231.     PCOUNTERTEXT  pCounterInfo,
  232.     LPWSTR  CounterBuffer,
  233.     LPWSTR  HelpBuffer,
  234.     DWORD   dwLastId,
  235.     DWORD   dwCounterSize,
  236.     DWORD   dwHelpSize,
  237.     LANGID  LangIdUsed
  238.    )
  239. {
  240.     LPWSTR  *lpReturnValue;
  241.     LPWSTR  *lpCounterId;
  242.     LPWSTR  lpCounterNames;
  243.     LPWSTR  lpHelpText;
  244.     DWORD   dwArraySize;
  245.     DWORD   dwBufferSize;
  246.     DWORD   dwValueType;
  247.     LONG    lWin32Status;
  248.     NTSTATUS    Status;
  249.     DWORD   dwLastError;
  250.  
  251.     dwArraySize = (dwLastId + 1 ) * sizeof(LPWSTR);
  252.     lpReturnValue = MemoryAllocate (dwArraySize + dwCounterSize + dwHelpSize);
  253.  
  254.     if (!lpReturnValue) goto ERROR_EXIT;
  255.  
  256.     // initialize pointers into buffer
  257.  
  258.     lpCounterId = lpReturnValue;
  259.     lpCounterNames = (LPWSTR)((LPBYTE)lpCounterId + dwArraySize);
  260.     lpHelpText = (LPWSTR)((LPBYTE)lpCounterNames + dwCounterSize);
  261.  
  262.     // read counters into memory
  263.  
  264.     dwBufferSize = dwCounterSize;
  265.     lWin32Status = RegQueryValueEx (
  266.         hKeyNames,
  267.         CounterBuffer,
  268.         RESERVED,
  269.         &dwValueType,
  270.         (LPVOID)lpCounterNames,
  271.         &dwBufferSize);
  272.  
  273.     if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT;
  274.  
  275.     if (bExplainTextButtonHit) {
  276.         dwBufferSize = dwHelpSize;
  277.         lWin32Status = RegQueryValueEx (
  278.             hKeyNames,
  279.             HelpBuffer,
  280.             RESERVED,
  281.             &dwValueType,
  282.             (LPVOID)lpHelpText,
  283.             &dwBufferSize);
  284.                             
  285.     if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT;
  286.     }
  287.  
  288.     // load counter array items
  289.     Status = AddNamesToArray (lpCounterNames, dwLastId, lpCounterId);
  290.     if (Status != ERROR_SUCCESS) goto ERROR_EXIT;
  291.  
  292.     if (bExplainTextButtonHit) {
  293.         Status = AddNamesToArray (lpHelpText, dwLastId, lpCounterId);
  294.     }
  295.  
  296.     if (Status != ERROR_SUCCESS) goto ERROR_EXIT;
  297.  
  298.     if (pCounterInfo) {
  299.         pCounterInfo->dwLastId = dwLastId;
  300.         pCounterInfo->dwLangId = LangIdUsed;
  301.         pCounterInfo->dwHelpSize = dwHelpSize;
  302.         pCounterInfo->dwCounterSize = dwCounterSize;
  303.     }
  304.  
  305.     return lpReturnValue;
  306.  
  307. ERROR_EXIT:
  308.     if (lWin32Status != ERROR_SUCCESS) {
  309.         dwLastError = GetLastError();
  310.     }
  311.  
  312.     if (lpReturnValue) {
  313.         MemoryFree ((LPVOID)lpReturnValue);
  314.     }
  315.     
  316.     return NULL;
  317. }
  318.  
  319.  
  320. LPWSTR
  321. *BuildNewNameTable(
  322.     PPERFSYSTEM   pSystem,
  323.     LPWSTR        lpszLangId,     // unicode value of Language subkey
  324.     PCOUNTERTEXT  pCounterInfo,
  325.     LANGID        iLangId,         // lang ID of the lpszLangId
  326.     DWORD         dwLastId
  327. )
  328. /*++
  329.    
  330. BuildNewNameTable
  331.  
  332. Arguments:
  333.  
  334.     lpszLangId
  335.             The unicode id of the language to look up. (English is 0x409)
  336.  
  337. Return Value:
  338.      
  339.     pointer to an allocated table. (the caller must free it when finished!)
  340.     the table is an array of pointers to zero terminated strings. NULL is
  341.     returned if an error occured.
  342.  
  343. --*/
  344. {
  345.     LONG    lWin32Status;
  346.     DWORD   dwValueType;
  347.     DWORD   dwLastError;
  348.     DWORD   dwBufferSize;
  349.     DWORD   dwCounterSize;
  350.     DWORD   dwHelpSize;
  351.     HKEY    hKeyNames;
  352.     TCHAR   CounterBuffer [MiscTextLen] ;
  353.     TCHAR   ExplainBuffer [MiscTextLen] ;
  354.     TCHAR   subLangId [ShortTextLen] ;
  355.     LANGID  LangIdUsed = iLangId;
  356.  
  357.  
  358.     //initialize local variables
  359.     hKeyNames = pSystem->sysDataKey;
  360.  
  361.  
  362.     // check for null arguments and insert defaults if necessary
  363.     if (!lpszLangId) {
  364.         lpszLangId = DefaultLangId;
  365.         LangIdUsed = iLanguage ;
  366.     }
  367.  
  368.     // get size of counter names and add that to the arrays
  369.     lstrcpy (CounterBuffer, CounterNameStr);
  370.     lstrcat (CounterBuffer, lpszLangId);
  371.  
  372.     lstrcpy (ExplainBuffer, ExplainNameStr);
  373.     lstrcat (ExplainBuffer, lpszLangId);
  374.  
  375.     dwBufferSize = 0;
  376.     lWin32Status = RegQueryValueEx (
  377.         hKeyNames,
  378.         CounterBuffer,
  379.         RESERVED,
  380.         &dwValueType,
  381.         NULL,
  382.         &dwBufferSize);
  383.  
  384.     if (lWin32Status != ERROR_SUCCESS) {
  385.         // try take out the country ID
  386.         LangIdUsed = MAKELANGID (LangIdUsed & 0x0ff, LANG_NEUTRAL);
  387.         TSPRINTF (subLangId, TEXT("%03x"), LangIdUsed);
  388.         lstrcpy (CounterBuffer, CounterNameStr);
  389.         lstrcat (CounterBuffer, subLangId);
  390.  
  391.         lstrcpy (ExplainBuffer, ExplainNameStr);
  392.         lstrcpy (ExplainBuffer, subLangId);
  393.  
  394.         dwBufferSize = 0;
  395.         lWin32Status = RegQueryValueEx (
  396.             hKeyNames,
  397.             CounterBuffer,
  398.             RESERVED,
  399.             &dwValueType,
  400.             NULL,
  401.             &dwBufferSize);
  402.     }
  403.  
  404.     if (lWin32Status != ERROR_SUCCESS) {
  405.         // try the EnglishLangId 
  406.         if (!strsame(EnglishLangId, subLangId)) {
  407.  
  408.             lstrcpy (CounterBuffer, CounterNameStr);
  409.             lstrcat (CounterBuffer, EnglishLangId);
  410.  
  411.             lstrcpy (ExplainBuffer, ExplainNameStr);
  412.             lstrcpy (ExplainBuffer, EnglishLangId);
  413.  
  414.             LangIdUsed = iEnglishLanguage ;
  415.  
  416.             dwBufferSize = 0;
  417.             lWin32Status = RegQueryValueEx (
  418.                 hKeyNames,
  419.                 CounterBuffer,
  420.                 RESERVED,
  421.                 &dwValueType,
  422.                 NULL,
  423.                 &dwBufferSize);
  424.         }
  425.     }
  426.  
  427.     // Fail, too bad...
  428.     if (lWin32Status != ERROR_SUCCESS) {
  429.         goto BNT_BAILOUT;
  430.     }
  431.  
  432.     dwCounterSize = dwBufferSize;
  433.  
  434.     // If ExplainText is needed, then
  435.     // get size of help text and add that to the arrays
  436.     
  437.     if (bExplainTextButtonHit) {
  438.         dwBufferSize = 0;
  439.         lWin32Status = RegQueryValueEx (
  440.               hKeyNames,
  441.               ExplainBuffer,
  442.               RESERVED,
  443.               &dwValueType,
  444.               NULL,
  445.               &dwBufferSize);
  446.  
  447.         if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  448.    
  449.         dwHelpSize = dwBufferSize;
  450.      } else {
  451.         dwHelpSize = 0;
  452.      }
  453.  
  454.     return (AddNewName(
  455.         hKeyNames,
  456.         pCounterInfo,
  457.         CounterBuffer,
  458.         ExplainBuffer,
  459.         dwLastId,
  460.         dwCounterSize,
  461.         dwHelpSize,
  462.         LangIdUsed));
  463.  
  464.  
  465. BNT_BAILOUT:
  466.     if (lWin32Status != ERROR_SUCCESS) {
  467.         dwLastError = GetLastError();
  468.     }
  469.  
  470.     return NULL;
  471. }
  472.  
  473.  
  474. LPWSTR
  475. *BuildOldNameTable(
  476.     HKEY          hKeyRegistry,   // handle to registry db with counter names
  477.     LPWSTR        lpszLangId,     // unicode value of Language subkey
  478.     PCOUNTERTEXT  pCounterInfo,
  479.     LANGID        iLangId,         // lang ID of the lpszLangId
  480.     DWORD         dwLastId
  481. )
  482. /*++
  483.    
  484. BuildOldNameTable
  485.  
  486. Arguments:
  487.  
  488.     hKeyRegistry
  489.             Handle to an open registry (this can be local or remote.) and
  490.             is the value returned by RegConnectRegistry or a default key.
  491.  
  492.     lpszLangId
  493.             The unicode id of the language to look up. (English is 0x409)
  494.  
  495. Return Value:
  496.      
  497.     pointer to an allocated table. (the caller must free it when finished!)
  498.     the table is an array of pointers to zero terminated strings. NULL is
  499.     returned if an error occured.
  500.  
  501. --*/
  502. {
  503.     LPWSTR  *lpReturnValue = NULL;
  504.  
  505.     LONG    lWin32Status;
  506.     DWORD   dwValueType;
  507.     DWORD   dwLastError;
  508.     DWORD   dwBufferSize;
  509.     DWORD   dwCounterSize;
  510.     DWORD   dwHelpSize;
  511.     HKEY    hKeyNames;
  512.     TCHAR   tempBuffer [MiscTextLen] ;
  513.     TCHAR   subLangId [ShortTextLen] ;
  514.     LPWSTR  lpValueNameString;
  515.     LANGID  LangIdUsed = iLangId;
  516.     TCHAR   Slash[2];
  517.  
  518.     //initialize local variables
  519.     hKeyNames = NULL;
  520.     Slash[0] = L'\\';
  521.     Slash[1] = L'\0';
  522.  
  523.     // check for null arguments and insert defaults if necessary
  524.     if (!lpszLangId) {
  525.         lpszLangId = DefaultLangId;
  526.         LangIdUsed = iLanguage ;
  527.     }
  528.  
  529.     // get size of string buffer
  530.     lpValueNameString = tempBuffer ;
  531.  
  532.     lstrcpy (lpValueNameString, NamesKey);
  533.     lstrcat (lpValueNameString, Slash);
  534.     lstrcat (lpValueNameString, lpszLangId);
  535.  
  536.     lWin32Status = RegOpenKeyEx (
  537.         hKeyRegistry,
  538.         lpValueNameString,
  539.         RESERVED,
  540.         KEY_READ,
  541.         &hKeyNames);
  542.  
  543.     if (lWin32Status != ERROR_SUCCESS) {
  544.         // try take out the country ID
  545.         LangIdUsed = MAKELANGID (LangIdUsed & 0x0ff, LANG_NEUTRAL);
  546.         TSPRINTF (subLangId, TEXT("%03x"), LangIdUsed);
  547.         lstrcpy (lpValueNameString, NamesKey);
  548.         lstrcat (lpValueNameString, Slash);
  549.         lstrcat (lpValueNameString, subLangId);
  550.  
  551.         lWin32Status = RegOpenKeyEx (
  552.                 hKeyRegistry,
  553.                 lpValueNameString,
  554.                 RESERVED,
  555.                 KEY_READ,
  556.                 &hKeyNames);
  557.     }
  558.  
  559.     if (lWin32Status != ERROR_SUCCESS) {
  560.         // try the EnglishLangId 
  561.         if (!strsame(EnglishLangId, subLangId)) {
  562.  
  563.             lstrcpy (lpValueNameString, NamesKey);
  564.             lstrcat (lpValueNameString, Slash);
  565.             lstrcat (lpValueNameString, EnglishLangId);
  566.  
  567.             LangIdUsed = iEnglishLanguage ;
  568.  
  569.             lWin32Status = RegOpenKeyEx (
  570.                 hKeyRegistry,
  571.                 lpValueNameString,
  572.                 RESERVED,
  573.                 KEY_READ,
  574.                 &hKeyNames);
  575.         }
  576.     }
  577.  
  578.     // Fail, too bad...
  579.     if (lWin32Status != ERROR_SUCCESS) {
  580.         goto BNT_BAILOUT;
  581.     }
  582.  
  583.     // get size of counter names and add that to the arrays
  584.     
  585.  
  586.     dwBufferSize = 0;
  587.     lWin32Status = RegQueryValueEx (
  588.         hKeyNames,
  589.         Counters,
  590.         RESERVED,
  591.         &dwValueType,
  592.         NULL,
  593.         &dwBufferSize);
  594.  
  595.     if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  596.  
  597.     dwCounterSize = dwBufferSize;
  598.  
  599.     // If ExplainText is needed, then
  600.     // get size of help text and add that to the arrays
  601.     
  602.     if (bExplainTextButtonHit) {
  603.         dwBufferSize = 0;
  604.         lWin32Status = RegQueryValueEx (
  605.               hKeyNames,
  606.               Help,
  607.               RESERVED,
  608.               &dwValueType,
  609.               NULL,
  610.               &dwBufferSize);
  611.  
  612.         if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  613.    
  614.         dwHelpSize = dwBufferSize;
  615.      } else {
  616.         dwHelpSize = 0;
  617.      }
  618.  
  619.     lpReturnValue = AddNewName(
  620.         hKeyNames,
  621.         pCounterInfo,
  622.         Counters,
  623.         Help,
  624.         dwLastId,
  625.         dwCounterSize,
  626.         dwHelpSize,
  627.         LangIdUsed);
  628.  
  629.     RegCloseKey (hKeyNames);
  630.  
  631.     return lpReturnValue;
  632.  
  633. BNT_BAILOUT:
  634.     if (lWin32Status != ERROR_SUCCESS) {
  635.         dwLastError = GetLastError();
  636.     }
  637.  
  638.     if (lpReturnValue) {
  639.         MemoryFree ((LPVOID)lpReturnValue);
  640.     }
  641.     
  642.     if (hKeyNames) RegCloseKey (hKeyNames);
  643.  
  644.     return NULL;
  645. }
  646.  
  647.  
  648. LPWSTR
  649. *BuildNameTable(
  650.     PPERFSYSTEM   pSysInfo,
  651.     HKEY          hKeyRegistry,   // handle to registry db with counter names
  652.     LPWSTR        lpszLangId,     // unicode value of Language subkey
  653.     PCOUNTERTEXT  pCounterInfo,
  654.     LANGID        iLangId         // lang ID of the lpszLangId
  655. )
  656. /*++
  657.    
  658. BuildNameTable
  659.  
  660. Arguments:
  661.  
  662.     hKeyRegistry
  663.             Handle to an open registry (this can be local or remote.) and
  664.             is the value returned by RegConnectRegistry or a default key.
  665.  
  666.     lpszLangId
  667.             The unicode id of the language to look up. (English is 0x409)
  668.  
  669. Return Value:
  670.      
  671.     pointer to an allocated table. (the caller must free it when finished!)
  672.     the table is an array of pointers to zero terminated strings. NULL is
  673.     returned if an error occured.
  674.  
  675. --*/
  676. {
  677.  
  678.     LPWSTR  *lpReturnValue;
  679.     LONG    lWin32Status;
  680.     DWORD   dwLastError;
  681.     DWORD   dwValueType;
  682.     DWORD   dwLastHelp;
  683.     DWORD   dwLastCounter;
  684.     DWORD   dwLastId;
  685.     DWORD   dwBufferSize;
  686.     HKEY    hKeyValue;
  687.     DWORD   dwSystemVersion;
  688.  
  689.  
  690.     //initialize local variables
  691.     lpReturnValue = NULL;
  692.     hKeyValue = NULL;
  693.  
  694.  
  695.     // open registry to get number of items for computing array size
  696.  
  697.     lWin32Status = RegOpenKeyEx (
  698.         hKeyRegistry,
  699.         NamesKey,
  700.         RESERVED,
  701.         KEY_READ,
  702.         &hKeyValue);
  703.     
  704.     if (lWin32Status != ERROR_SUCCESS) {
  705.         goto BNT_BAILOUT;
  706.     }
  707.  
  708.     // get number of items
  709.     
  710.     dwBufferSize = sizeof (dwLastHelp);
  711.     lWin32Status = RegQueryValueEx (
  712.         hKeyValue,
  713.         LastHelp,
  714.         RESERVED,
  715.         &dwValueType,
  716.         (LPBYTE)&dwLastHelp,
  717.         &dwBufferSize);
  718.  
  719.     if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  720.         goto BNT_BAILOUT;
  721.     }
  722.  
  723.     dwBufferSize = sizeof (dwLastCounter);
  724.     lWin32Status = RegQueryValueEx (
  725.         hKeyValue,
  726.         LastCounter,
  727.         RESERVED,
  728.         &dwValueType,
  729.         (LPBYTE)&dwLastCounter,
  730.         &dwBufferSize);
  731.  
  732.     if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  733.         goto BNT_BAILOUT;
  734.     }
  735.  
  736.     if (dwLastCounter >= dwLastHelp) {
  737.         dwLastId = dwLastCounter;
  738.     } else {
  739.         dwLastId = dwLastHelp;
  740.     }
  741.    
  742.     // get system version
  743.     dwBufferSize = sizeof (dwSystemVersion);
  744.     lWin32Status = RegQueryValueEx (
  745.         hKeyValue,
  746.         SysVersion,
  747.         RESERVED,
  748.         &dwValueType,
  749.         (LPBYTE)&dwSystemVersion,
  750.         &dwBufferSize);
  751.  
  752.     if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  753.         pSysInfo->SysVersion = 0x10000; 
  754.     } else {
  755.         pSysInfo->SysVersion = dwSystemVersion;
  756.     }
  757.  
  758.     if (pSysInfo->SysVersion <= 0x10000) {
  759.         lpReturnValue = BuildOldNameTable (
  760.             hKeyRegistry,
  761.             lpszLangId,
  762.             pCounterInfo,
  763.             iLangId,
  764.             dwLastId) ;
  765.     } else {
  766.         lpReturnValue = BuildNewNameTable (
  767.             pSysInfo,
  768.             lpszLangId,
  769.             pCounterInfo,
  770.             iLangId,
  771.             dwLastId) ;
  772.     }
  773.  
  774.     RegCloseKey (hKeyValue);
  775.     return lpReturnValue;
  776.  
  777. BNT_BAILOUT:
  778.     if (lWin32Status != ERROR_SUCCESS) {
  779.         dwLastError = GetLastError();
  780.     }
  781.     if (hKeyValue) RegCloseKey (hKeyValue);
  782.     return NULL;
  783. }
  784.  
  785. DWORD GetSystemKey (PPERFSYSTEM pSysInfo, HKEY *phKeyMachine)
  786. {
  787.     DWORD   dwStatus;
  788.  
  789.    // connect to system registry
  790.  
  791.     if (IsLocalComputer(pSysInfo->sysName) ||
  792.        (PlayingBackLog() && PlaybackLog.pBaseCounterNames)) {
  793.         *phKeyMachine = HKEY_LOCAL_MACHINE;
  794.     } else if (lstrlen(pSysInfo->sysName) < MAX_COMPUTERNAME_LENGTH+3) {
  795.         try {
  796.             dwStatus = RegConnectRegistry (
  797.                 pSysInfo->sysName,
  798.                 HKEY_LOCAL_MACHINE,
  799.                 phKeyMachine);
  800.  
  801.             if (dwStatus != ERROR_SUCCESS) {
  802.                 if (PlayingBackLog()) {
  803.                     // If remote machine is not on and we are
  804.                     // playing back log, then, use the counters from
  805.                     // local machine.
  806.                     *phKeyMachine = HKEY_LOCAL_MACHINE;
  807.                 } else {
  808.                     return dwStatus;
  809.                 }
  810.             }
  811.         } finally {
  812.             ; // nothing
  813.         }
  814.     }
  815.     return 0;
  816. }
  817.  
  818.  
  819. DWORD GetSystemNames(PPERFSYSTEM pSysInfo)
  820. {
  821.     HKEY    hKeyMachine = 0;
  822.     DWORD   dwStatus;
  823.  
  824.     if (dwStatus = GetSystemKey (pSysInfo, &hKeyMachine)) {
  825.          return dwStatus;
  826.     }
  827.  
  828.     // if here, then hKeyMachine is an open key to the system's 
  829.     //  HKEY_LOCAL_MACHINE registry database
  830.  
  831.     // only one language is supported by this approach.
  832.     // multiple language support would:
  833.     //  1.  enumerate language keys 
  834.     //       and for each key:
  835.     //  2.  allocate memory for structures
  836.     //  3.  call BuildNameTable for each lang key.
  837.  
  838.     pSysInfo->CounterInfo.pNextTable = NULL;
  839.     pSysInfo->CounterInfo.dwLangId = iLanguage ;   // default Lang ID
  840.  
  841.     if (PlayingBackLog() && PlaybackLog.pBaseCounterNames) {
  842.         pSysInfo->CounterInfo.TextString = LogBuildNameTable (pSysInfo) ; 
  843.     } else {
  844.         pSysInfo->CounterInfo.TextString = BuildNameTable (
  845.               pSysInfo,
  846.               hKeyMachine,
  847.               NULL,                               // use default
  848.               &pSysInfo->CounterInfo,
  849.               0);
  850.     }
  851.  
  852.     if (hKeyMachine && hKeyMachine != HKEY_LOCAL_MACHINE) {
  853.         RegCloseKey (hKeyMachine) ;
  854.     }
  855.  
  856.     if (pSysInfo->CounterInfo.TextString == NULL) {
  857.         return GetLastError();
  858.     } else {
  859.         return ERROR_SUCCESS;
  860.     }
  861. }
  862.  
  863. BOOL  GetHelpText(
  864.     PPERFSYSTEM pSysInfo
  865.     )
  866. {
  867.     LPWSTR  *lpCounterId;
  868.     LPWSTR  lpHelpText;
  869.     LONG    lWin32Status;
  870.     DWORD   dwValueType;
  871.     DWORD   dwArraySize;
  872.     DWORD   dwBufferSize;
  873.     DWORD   dwCounterSize;
  874.     DWORD   dwHelpSize;
  875.     NTSTATUS    Status;
  876.     DWORD   dwLastId;
  877.     TCHAR   Slash[2];
  878.      
  879.     HKEY    hKeyNames;
  880.     
  881.     TCHAR   SysLangId [ShortTextLen] ;
  882.     TCHAR   ValueNameString [MiscTextLen] ;
  883.     HKEY    hKeyMachine = 0;
  884.     DWORD   dwStatus;
  885.  
  886.     SetHourglassCursor() ;
  887.  
  888.     //initialize local variables
  889.     lpHelpText = NULL;
  890.     hKeyNames = hKeyMachine = NULL;
  891.     Slash[0] = L'\\';
  892.     Slash[1] = L'\0';
  893.  
  894.     dwBufferSize = 0;
  895.  
  896.     TSPRINTF (SysLangId, TEXT("%03x"), pSysInfo->CounterInfo.dwLangId) ;
  897.  
  898.     if (pSysInfo->SysVersion <= 0x10000) {
  899.         // old version, get help from registry
  900.         if (dwStatus = GetSystemKey (pSysInfo, &hKeyMachine)) {
  901.             goto ERROR_EXIT;
  902.         }
  903.     
  904.         lstrcpy (ValueNameString, NamesKey);
  905.         lstrcat (ValueNameString, Slash);
  906.         lstrcat (ValueNameString, SysLangId);
  907.  
  908.         lWin32Status = RegOpenKeyEx (
  909.                   hKeyMachine,
  910.                   ValueNameString,
  911.                   RESERVED,
  912.                   KEY_READ,
  913.                   &hKeyNames);
  914.  
  915.        if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT;
  916.     } else {
  917.         // new system version, get it from the HKEY_PERFORMANCE
  918.         hKeyNames = pSysInfo->sysDataKey;
  919.         lstrcpy (ValueNameString, ExplainNameStr);
  920.         lstrcat (ValueNameString, SysLangId);
  921.     }
  922.  
  923.     dwHelpSize = 0;
  924.     lWin32Status = RegQueryValueEx (
  925.               hKeyNames,
  926.               pSysInfo->SysVersion <= 0x010000 ? Help : ValueNameString,
  927.               RESERVED,
  928.               &dwValueType,
  929.               NULL,
  930.               &dwHelpSize);
  931.  
  932.     if (lWin32Status != ERROR_SUCCESS || dwHelpSize == 0) goto ERROR_EXIT;
  933.  
  934.     dwLastId = pSysInfo->CounterInfo.dwLastId;
  935.     dwArraySize = (dwLastId + 1) * sizeof (LPWSTR);
  936.     dwCounterSize = pSysInfo->CounterInfo.dwCounterSize;
  937.  
  938.     // allocate another memory to get the help text
  939.     lpHelpText = MemoryAllocate (dwHelpSize);
  940.     if (!lpHelpText) goto ERROR_EXIT;
  941.  
  942.     dwBufferSize = dwHelpSize;
  943.     lWin32Status = RegQueryValueEx (
  944.         hKeyNames,
  945.         pSysInfo->SysVersion <= 0x010000 ? Help : ValueNameString,
  946.         RESERVED,
  947.         &dwValueType,
  948.         (LPVOID)lpHelpText,
  949.         &dwBufferSize);
  950.                             
  951.     if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT;
  952.  
  953.     // setup the help text pointers
  954.     lpCounterId = pSysInfo->CounterInfo.TextString;
  955.     Status = AddNamesToArray (lpHelpText, dwLastId, lpCounterId) ;
  956.     if (Status != ERROR_SUCCESS) goto ERROR_EXIT;
  957.  
  958.     pSysInfo->CounterInfo.dwHelpSize = dwHelpSize;
  959.  
  960.     if (pSysInfo->SysVersion <= 0x010000)
  961.         RegCloseKey (hKeyNames);
  962.  
  963.     if (hKeyMachine && hKeyMachine != HKEY_LOCAL_MACHINE) {
  964.         RegCloseKey (hKeyMachine) ;
  965.     }
  966.  
  967.     pSysInfo->CounterInfo.HelpTextString = lpHelpText;
  968.  
  969.     SetArrowCursor() ;
  970.  
  971.     return TRUE;
  972.  
  973. ERROR_EXIT:
  974.  
  975.     SetArrowCursor() ;
  976.  
  977.     if (lpHelpText) {
  978.         MemoryFree ((LPVOID)lpHelpText);
  979.     }
  980.     
  981.     if (hKeyNames) {
  982.         RegCloseKey (hKeyNames);
  983.     }
  984.     if (hKeyMachine && hKeyMachine != HKEY_LOCAL_MACHINE) {
  985.         RegCloseKey (hKeyMachine) ;
  986.     }
  987.  
  988.     return FALSE;
  989. }
  990.  
  991. //
  992. //  QueryPerformanceName -    Get a title, given an index
  993. //
  994. //    Inputs:
  995. //
  996. //          pSysInfo        -   Pointer to sysinfo struct for the
  997. //                              system in question
  998. //
  999. //        dwTitleIndex    -    Index of Title entry
  1000. //
  1001. //          LangID          -   language in which title should be displayed
  1002. //
  1003. //        cbTitle        -    # of char in the lpTitle buffer
  1004. //
  1005. //        lpTitle        -    pointer to a buffer to receive the
  1006. //                              Title
  1007. //
  1008. //          Help            -   TRUE is help is desired, else counter or
  1009. //                              object is assumed
  1010. DWORD
  1011. QueryPerformanceName(
  1012.     PPERFSYSTEM pSysInfo,
  1013.     DWORD dwTitleIndex,
  1014.     LANGID LangID,
  1015.     DWORD cbTitle,
  1016.     LPTSTR lpTitle,
  1017.     BOOL Help
  1018.     )
  1019. {
  1020.     LPWSTR  lpTitleFound;
  1021.     NTSTATUS    Status;
  1022.     BOOL    bGetTextSuccess = TRUE ;
  1023.  
  1024.     DBG_UNREFERENCED_PARAMETER(LangID);
  1025.  
  1026.     if (Help && pSysInfo->CounterInfo.dwHelpSize == 0) {
  1027.         // we have not get the help text yet, go get it
  1028.         bGetTextSuccess = GetHelpText (pSysInfo);
  1029.     }
  1030.  
  1031.     if (!bGetTextSuccess) {
  1032.         Status = ERROR_INVALID_NAME;
  1033.         goto ErrorExit;
  1034.     }
  1035.  
  1036.     if ((dwTitleIndex > 0) && (dwTitleIndex <= pSysInfo->CounterInfo.dwLastId)) {
  1037.         // then title should be found in the array
  1038.         lpTitleFound = pSysInfo->CounterInfo.TextString[dwTitleIndex];
  1039.         if (!lpTitleFound) {
  1040.             // no entry for this index
  1041.             Status = ERROR_INVALID_NAME;
  1042.         }
  1043.         else if ((DWORD)lstrlen(lpTitleFound) < cbTitle) {
  1044.             lstrcpy (lpTitle, lpTitleFound);
  1045.             return (ERROR_SUCCESS);
  1046.         } else {
  1047.             Status = ERROR_MORE_DATA;
  1048.         }
  1049.     } else {
  1050.  
  1051.         Status = ERROR_INVALID_NAME;
  1052.     }
  1053.  
  1054. ErrorExit:
  1055.     // if here, then an error occured, so return a blank
  1056.  
  1057.     if ((DWORD)lstrlen (NULL_NAME) < cbTitle) {
  1058.         lstrcpy (lpTitle, NULL_NAME);
  1059.     }
  1060.  
  1061.     return Status;   // title not returned
  1062.  
  1063. }
  1064.  
  1065.  
  1066. LONG
  1067. GetSystemPerfData (
  1068.     IN HKEY hKeySystem,
  1069.     IN LPTSTR lpszValue,
  1070.     OUT PPERFDATA pPerfData, 
  1071.     OUT PDWORD pdwPerfDataLen
  1072. )
  1073.    {  // GetSystemPerfData
  1074.    LONG     lError ;
  1075.    DWORD    Type ;
  1076.  
  1077.    // have to pass in a Type to RegQueryValueEx(W) or else it
  1078.    // will crash
  1079.    lError = RegQueryValueEx (hKeySystem, lpszValue, NULL, &Type,
  1080.                             (LPSTR) pPerfData, pdwPerfDataLen) ;
  1081.    return (lError) ;
  1082.    }  // GetSystemPerfData
  1083.  
  1084.             
  1085. BOOL CloseSystemPerfData (HKEY hKeySystem)
  1086.    {  // CloseSystemPerfData
  1087.    return (TRUE) ;
  1088.    }  // CloseSystemPerfData
  1089.  
  1090.  
  1091.  
  1092. int CBLoadObjects (HWND hWndCB,
  1093.                    PPERFDATA pPerfData,
  1094.                    PPERFSYSTEM pSysInfo,
  1095.                    DWORD dwDetailLevel,
  1096.                    LPTSTR lpszDefaultObject,
  1097.                    BOOL bIncludeAll)
  1098. /*
  1099.    Effect:        Load into the combo box CB one item for each Object in
  1100.                   pPerfData. For each item, look up the object's name in
  1101.                   the registry strings associated with pSysInfo, and 
  1102.                   attach the object to the data field of the CB item.
  1103.  
  1104.                   Dont add those objects that are more detailed than
  1105.                   dwDetailLevel.      
  1106.  
  1107.                   Set the current selected CB item to the object named
  1108.                   lpszDefaultObject, or to the default object specified in 
  1109.                   pPerfData if lpszDefaultObject is NULL.
  1110. */
  1111.    {  // CBLoadObjects
  1112.    UINT           i ;
  1113.    int            iIndex ;
  1114.    PPERFOBJECT    pObject ;
  1115.    TCHAR          szObject [PerfObjectLen + 1] ;
  1116.    TCHAR          szDefaultObject [PerfObjectLen + 1] ;
  1117.  
  1118.    CBReset (hWndCB) ;
  1119.    strclr (szDefaultObject) ;
  1120.  
  1121.    pObject = FirstObject (pPerfData) ;
  1122.  
  1123.    for (i = 0, pObject = FirstObject (pPerfData) ;
  1124.         i < pPerfData->NumObjectTypes ;
  1125.         i++, pObject = NextObject (pObject))
  1126.       {  // for
  1127.       if (pObject->DetailLevel <= dwDetailLevel)
  1128.          {  // if
  1129.          strclr (szObject) ;
  1130.          QueryPerformanceName (pSysInfo, pObject->ObjectNameTitleIndex, 
  1131.                                0, PerfObjectLen, szObject, FALSE) ;
  1132.  
  1133.          // if szObject not empty, add it to the Combo-box
  1134.          if (!strsame(szObject, NULL_NAME))
  1135.             {
  1136.             iIndex = CBAdd (hWndCB, szObject) ;
  1137.             CBSetData (hWndCB, iIndex, (DWORD) pObject) ;
  1138.  
  1139.             if ((LONG)pObject->ObjectNameTitleIndex == pPerfData->DefaultObject)
  1140.                lstrcpy (szDefaultObject, szObject) ;
  1141.             } // if szObject not empty
  1142.          }  // if
  1143.       }  // for
  1144.  
  1145.  
  1146.    if (bIncludeAll)
  1147.       {
  1148.       StringLoad (IDS_ALLOBJECTS, szObject) ;
  1149.       CBInsert (hWndCB, 0, szObject) ;
  1150.       // assume "ALL" is default unless overridden
  1151.       lstrcpy (szDefaultObject, szObject) ;
  1152.       }
  1153.       
  1154.    if (lpszDefaultObject)
  1155.       lstrcpy (szDefaultObject, lpszDefaultObject) ;
  1156.  
  1157.    iIndex = CBFind (hWndCB, szDefaultObject) ;
  1158.    CBSetSelection (hWndCB, (iIndex != CB_ERR) ? iIndex : 0) ;
  1159.  
  1160.    return (i) ;
  1161.    }  // CBLoadObjects
  1162.          
  1163.  
  1164. int LBLoadObjects (HWND hWndLB,
  1165.                    PPERFDATA pPerfData,
  1166.                    PPERFSYSTEM pSysInfo,
  1167.                    DWORD dwDetailLevel,
  1168.                    LPTSTR lpszDefaultObject,
  1169.                    BOOL bIncludeAll)
  1170. /*
  1171.    Effect:        Load into the list box LB one item for each Object in
  1172.                   pPerfData. For each item, look up the object's name in
  1173.                   the registry strings associated with pSysInfo, and 
  1174.                   attach the object to the data field of the LB item.
  1175.  
  1176.                   Dont add those objects that are more detailed than
  1177.                   dwDetailLevel.      
  1178.  
  1179.                   Set the current selected LB item to the object named
  1180.                   lpszDefaultObject, or to the default object specified in 
  1181.                   pPerfData if lpszDefaultObject is NULL.
  1182. */
  1183.    {  // LBLoadObjects
  1184.    UINT           i ;
  1185.    int            iIndex ;
  1186.    PPERFOBJECT    pObject ;
  1187.    TCHAR          szObject [PerfObjectLen + 1] ;
  1188.    TCHAR          szDefaultObject [PerfObjectLen + 1] ;
  1189.  
  1190.    LBReset (hWndLB) ;
  1191.    strclr (szDefaultObject) ;
  1192.  
  1193.    pObject = FirstObject (pPerfData) ;
  1194.  
  1195.    for (i = 0, pObject = FirstObject (pPerfData) ;
  1196.         i < pPerfData->NumObjectTypes ;
  1197.         i++, pObject = NextObject (pObject))
  1198.       {  // for
  1199.       if (pObject->DetailLevel <= dwDetailLevel)
  1200.          {  // if
  1201.          strclr (szObject) ;
  1202.          QueryPerformanceName (pSysInfo, pObject->ObjectNameTitleIndex, 
  1203.                                0, PerfObjectLen, szObject, FALSE) ;
  1204.  
  1205.          // if szObject is not empty, add it to the listbox
  1206.          if (!strsame(szObject, NULL_NAME))
  1207.             {
  1208.             iIndex = LBAdd (hWndLB, szObject) ;
  1209.             LBSetData (hWndLB, iIndex, (DWORD) pObject) ;
  1210.  
  1211.             if ((LONG)pObject->ObjectNameTitleIndex == pPerfData->DefaultObject)
  1212.                lstrcpy (szDefaultObject, szObject) ;
  1213.             } // if szObject is not empty
  1214.          }
  1215.       }  // for
  1216.  
  1217.  
  1218.    if (bIncludeAll)
  1219.       {
  1220.       StringLoad (IDS_ALLOBJECTS, szObject) ;
  1221.       LBInsert (hWndLB, 0, szObject) ;
  1222.          LBSetData (hWndLB, iIndex, (DWORD) NULL) ;
  1223.       // assume "ALL" is default unless overridden
  1224.       lstrcpy (szDefaultObject, szObject) ;
  1225.       }
  1226.  
  1227.    if (lpszDefaultObject)
  1228.       lstrcpy (szDefaultObject, lpszDefaultObject) ;
  1229.       
  1230.    iIndex = LBFind (hWndLB, szDefaultObject) ;
  1231.    LBSetSelection (hWndLB, (iIndex != LB_ERR) ? iIndex : 0) ;
  1232.  
  1233.    return (i) ;
  1234.    }  // LBLoadObjects
  1235.          
  1236.  
  1237. /***************************************************************************\
  1238. * GetObjectDef()
  1239. *
  1240. * Entry: pointer to data block and the number of the object type
  1241. * Exit:  returns a pointer to the specified object type definition
  1242. *
  1243. \***************************************************************************/
  1244.  
  1245. PERF_OBJECT_TYPE *GetObjectDef(
  1246.     PERF_DATA_BLOCK *pDataBlock,
  1247.     DWORD NumObjectType)
  1248. {
  1249.     DWORD NumTypeDef;
  1250.  
  1251.     PERF_OBJECT_TYPE *pObjectDef;
  1252.  
  1253.     pObjectDef = FirstObject(pDataBlock);
  1254.  
  1255.     for ( NumTypeDef = 0;
  1256.       NumTypeDef < pDataBlock->NumObjectTypes;
  1257.       NumTypeDef++ ) {
  1258.  
  1259.     if ( NumTypeDef == NumObjectType ) {
  1260.  
  1261.         return pObjectDef;
  1262.     }
  1263.         pObjectDef = NextObject(pObjectDef);
  1264.     }
  1265.     return 0;
  1266. }
  1267.  
  1268. /***************************************************************************\
  1269. * GetObjectDefByTitleIndex()
  1270. *
  1271. * Entry: pointer to data block and the title index of the object type
  1272. * Exit:  returns a pointer to the specified object type definition
  1273. *
  1274. \***************************************************************************/
  1275.  
  1276. PERF_OBJECT_TYPE *GetObjectDefByTitleIndex(
  1277.     PERF_DATA_BLOCK *pDataBlock,
  1278.     DWORD ObjectTypeTitleIndex)
  1279. {
  1280.     DWORD NumTypeDef;
  1281.  
  1282.     PERF_OBJECT_TYPE *pObjectDef;
  1283.  
  1284.     pObjectDef = FirstObject(pDataBlock);
  1285.  
  1286.     for ( NumTypeDef = 0;
  1287.       NumTypeDef < pDataBlock->NumObjectTypes;
  1288.       NumTypeDef++ ) {
  1289.  
  1290.         if ( pObjectDef->ObjectNameTitleIndex == ObjectTypeTitleIndex ) {
  1291.  
  1292.         return pObjectDef;
  1293.     }
  1294.         pObjectDef = NextObject(pObjectDef);
  1295.     }
  1296.     return 0;
  1297. }
  1298.  
  1299. /***************************************************************************\
  1300. * GetObjectDefByName()
  1301. *
  1302. * Entry: pointer to data block and the name of the object type
  1303. * Exit:  returns a pointer to the specified object type definition
  1304. *
  1305. \***************************************************************************/
  1306.  
  1307. PERF_OBJECT_TYPE *GetObjectDefByName(
  1308.     PPERFSYSTEM pSystem,
  1309.     PERF_DATA_BLOCK *pDataBlock,
  1310.     LPTSTR pObjectName)
  1311. {
  1312.     DWORD NumTypeDef;
  1313.     TCHAR szObjectName [PerfObjectLen + 1] ;
  1314.  
  1315.     PERF_OBJECT_TYPE *pObjectDef;
  1316.  
  1317.     pObjectDef = FirstObject(pDataBlock);
  1318.     for ( NumTypeDef = 0;
  1319.       NumTypeDef < pDataBlock->NumObjectTypes;
  1320.       NumTypeDef++ ) {
  1321.  
  1322.         ObjectName (pSystem, pObjectDef, szObjectName, PerfObjectLen) ;
  1323.         if (strsame (szObjectName, pObjectName) ) {
  1324.  
  1325.         return pObjectDef;
  1326.     }
  1327.         pObjectDef = NextObject(pObjectDef);
  1328.     }
  1329.     return 0;
  1330. }
  1331.  
  1332. /***************************************************************************\
  1333. * GetObjectIdByName()
  1334. *
  1335. * Entry: pointer to data block and the name of the object type
  1336. * Exit:  returns the Object title index for the specified Object Name
  1337. *
  1338. \***************************************************************************/
  1339.  
  1340. DWORD GetObjectIdByName(
  1341.     PPERFSYSTEM pSystem,
  1342.     PERF_DATA_BLOCK *pDataBlock,
  1343.     LPTSTR pObjectName)
  1344. {
  1345.     DWORD NumTypeDef;
  1346.     TCHAR szObjectName [PerfObjectLen + 1] ;
  1347.  
  1348.     PERF_OBJECT_TYPE *pObjectDef;
  1349.  
  1350.     pObjectDef = FirstObject(pDataBlock);
  1351.     for ( NumTypeDef = 0;
  1352.       NumTypeDef < pDataBlock->NumObjectTypes;
  1353.       NumTypeDef++ ) {
  1354.  
  1355.         ObjectName (pSystem, pObjectDef, szObjectName, PerfObjectLen) ;
  1356.         if (strsame (szObjectName, pObjectName) ) {
  1357.  
  1358.         return pObjectDef->ObjectNameTitleIndex;
  1359.     }
  1360.         pObjectDef = NextObject(pObjectDef);
  1361.     }
  1362.     return 0;
  1363. }
  1364.  
  1365.  
  1366. /***************************************************************************\
  1367. * GetCounterDef()
  1368. *
  1369. * Entry: pointer to object type definition the number of the Counter
  1370. *     definition
  1371. * Exit:  returns a pointer to the specified Counter definition
  1372. *
  1373. \***************************************************************************/
  1374.  
  1375. PERF_COUNTER_DEFINITION *GetCounterDef(
  1376.     PERF_OBJECT_TYPE *pObjectDef,
  1377.     DWORD NumCounter)
  1378. {
  1379.     DWORD NumCtrDef;
  1380.  
  1381.     PERF_COUNTER_DEFINITION *pCounterDef;
  1382.  
  1383.     pCounterDef = FirstCounter(pObjectDef);
  1384.  
  1385.     for ( NumCtrDef = 0;
  1386.       NumCtrDef < pObjectDef->NumCounters;
  1387.       NumCtrDef++ ) {
  1388.  
  1389.     if ( NumCtrDef == NumCounter ) {
  1390.  
  1391.         return pCounterDef;
  1392.     }
  1393.         pCounterDef = NextCounter(pCounterDef);
  1394.     }
  1395.     return 0;
  1396. }
  1397.  
  1398. /***************************************************************************\
  1399. * GetCounterNumByTitleIndex()
  1400. *
  1401. * Entry: pointer to object type definition and the title index of
  1402. *        the name of the Counter definition
  1403. * Exit:  returns the number of the specified Counter definition
  1404. *
  1405. \***************************************************************************/
  1406.  
  1407. LONG GetCounterNumByTitleIndex(
  1408.     PERF_OBJECT_TYPE *pObjectDef,
  1409.     DWORD CounterTitleIndex)
  1410. {
  1411.     DWORD NumCtrDef;
  1412.  
  1413.     PERF_COUNTER_DEFINITION *pCounterDef;
  1414.  
  1415.     pCounterDef = FirstCounter(pObjectDef);
  1416.  
  1417.     for ( NumCtrDef = 0;
  1418.       NumCtrDef < pObjectDef->NumCounters;
  1419.       NumCtrDef++ ) {
  1420.  
  1421.         if ( pCounterDef->CounterNameTitleIndex == CounterTitleIndex ) {
  1422.  
  1423.         return NumCtrDef;
  1424.     }
  1425.         pCounterDef = NextCounter(pCounterDef);
  1426.     }
  1427.     return 0;
  1428. }
  1429.  
  1430. /***************************************************************************\
  1431. * GetCounterData()
  1432. *
  1433. * Entry: pointer to object definition and number of counter, must be
  1434. *     an object with no instances
  1435. * Exit:  returns a pointer to the data
  1436. *
  1437. \***************************************************************************/
  1438.  
  1439. PVOID GetCounterData(
  1440.     PERF_OBJECT_TYPE *pObjectDef,
  1441.     PERF_COUNTER_DEFINITION *pCounterDef)
  1442. {
  1443.  
  1444.     PERF_COUNTER_BLOCK *pCtrBlock;
  1445.  
  1446.     pCtrBlock = (PERF_COUNTER_BLOCK *)((PCHAR)pObjectDef +
  1447.                           pObjectDef->DefinitionLength);
  1448.  
  1449.     return (PVOID)((PCHAR)pCtrBlock + pCounterDef->CounterOffset);
  1450. }
  1451.  
  1452. /***************************************************************************\
  1453. * GetInstanceCounterData()
  1454. *
  1455. * Entry: pointer to object definition and number of counter, and a pointer
  1456. *        to the instance for which the data is to be retrieved
  1457. * Exit:  returns a pointer to the data
  1458. *
  1459. \***************************************************************************/
  1460.  
  1461. PVOID GetInstanceCounterData(
  1462.     PERF_OBJECT_TYPE *pObjectDef,
  1463.     PERF_INSTANCE_DEFINITION *pInstanceDef,
  1464.     PERF_COUNTER_DEFINITION *pCounterDef)
  1465. {
  1466.  
  1467.     PERF_COUNTER_BLOCK *pCtrBlock;
  1468.  
  1469.     pCtrBlock = (PERF_COUNTER_BLOCK *)((PCHAR)pInstanceDef +
  1470.                           pInstanceDef->ByteLength);
  1471.  
  1472.     return (PVOID)((PCHAR)pCtrBlock + pCounterDef->CounterOffset);
  1473. }
  1474.  
  1475. /***************************************************************************\
  1476. * GetNextInstance()
  1477. *
  1478. * Entry: pointer to instance definition
  1479. * Exit:  returns a pointer to the next instance definition.  If none,
  1480. *        points to byte past this instance
  1481. *
  1482. \***************************************************************************/
  1483.  
  1484. PERF_INSTANCE_DEFINITION *GetNextInstance(
  1485.     PERF_INSTANCE_DEFINITION *pInstDef)
  1486. {
  1487.     PERF_COUNTER_BLOCK *pCtrBlock;
  1488.  
  1489.     pCtrBlock = (PERF_COUNTER_BLOCK *)
  1490.                 ((PCHAR) pInstDef + pInstDef->ByteLength);
  1491.  
  1492.     return (PERF_INSTANCE_DEFINITION *)
  1493.            ((PCHAR) pCtrBlock + pCtrBlock->ByteLength);
  1494. }
  1495.  
  1496. /***************************************************************************\
  1497. * GetInstance()
  1498. *
  1499. * Entry: pointer to object type definition, the name of the instance,
  1500. *     the name of the parent object type, and the parent instance index.
  1501. *     The name of the parent object type is NULL if no parent.
  1502. * Exit:  returns a pointer to the specified instance definition
  1503. *
  1504. \***************************************************************************/
  1505.  
  1506. PERF_INSTANCE_DEFINITION *GetInstance(
  1507.     PERF_OBJECT_TYPE *pObjectDef,
  1508.     LONG InstanceNumber)
  1509. {
  1510.  
  1511.    PERF_INSTANCE_DEFINITION *pInstanceDef;
  1512.    LONG NumInstance;
  1513.  
  1514.    if (!pObjectDef)
  1515.       {
  1516.       return 0;
  1517.       }
  1518.  
  1519.    pInstanceDef = FirstInstance(pObjectDef);
  1520.    
  1521.    for ( NumInstance = 0;
  1522.       NumInstance < pObjectDef->NumInstances;
  1523.       NumInstance++ )
  1524.       {
  1525.        if ( InstanceNumber == NumInstance )
  1526.          {
  1527.          return pInstanceDef;
  1528.          }
  1529.       pInstanceDef = GetNextInstance(pInstanceDef);
  1530.       }
  1531.  
  1532.    return 0;
  1533. }
  1534.  
  1535. /***************************************************************************\
  1536. * GetInstanceByUniqueID()
  1537. *
  1538. * Entry: pointer to object type definition, and
  1539. *        the unique ID of the instance.
  1540. * Exit:  returns a pointer to the specified instance definition
  1541. *
  1542. \***************************************************************************/
  1543.  
  1544. PERF_INSTANCE_DEFINITION *GetInstanceByUniqueID(
  1545.     PERF_OBJECT_TYPE *pObjectDef,
  1546.     LONG UniqueID)
  1547. {
  1548.  
  1549.     PERF_INSTANCE_DEFINITION *pInstanceDef;
  1550.  
  1551.     LONG NumInstance;
  1552.  
  1553.     pInstanceDef = FirstInstance(pObjectDef);
  1554.  
  1555.     for ( NumInstance = 0;
  1556.       NumInstance < pObjectDef->NumInstances;
  1557.       NumInstance++ ) {
  1558.  
  1559.         if ( pInstanceDef->UniqueID == UniqueID ) {
  1560.  
  1561.         return pInstanceDef;
  1562.     }
  1563.         pInstanceDef = GetNextInstance(pInstanceDef);
  1564.     }
  1565.     return 0;
  1566. }
  1567.  
  1568.  
  1569. /***************************************************************************\
  1570. * GetInstanceByNameUsingParentTitleIndex()
  1571. *
  1572. * Entry: pointer to object type definition, the name of the instance,
  1573. *     and the name of the parent instance.
  1574. *     The name of the parent instance is NULL if no parent.
  1575. * Exit:  returns a pointer to the specified instance definition
  1576. *
  1577. \***************************************************************************/
  1578.  
  1579. PERF_INSTANCE_DEFINITION *GetInstanceByNameUsingParentTitleIndex(
  1580.     PERF_DATA_BLOCK *pDataBlock,
  1581.     PERF_OBJECT_TYPE *pObjectDef,
  1582.     LPTSTR pInstanceName,
  1583.     LPTSTR pParentName)
  1584. {
  1585.    BOOL fHaveParent;
  1586.    PERF_OBJECT_TYPE *pParentObj;
  1587.  
  1588.     PERF_INSTANCE_DEFINITION  *pParentInst,
  1589.                  *pInstanceDef;
  1590.  
  1591.    LONG   NumInstance;
  1592.    TCHAR  InstanceName[256];
  1593.    
  1594.  
  1595.    fHaveParent = FALSE;
  1596.    pInstanceDef = FirstInstance(pObjectDef);
  1597.  
  1598.    for ( NumInstance = 0;
  1599.       NumInstance < pObjectDef->NumInstances;
  1600.       NumInstance++ )
  1601.       {
  1602.  
  1603.       GetInstanceNameStr(pInstanceDef,InstanceName);
  1604.       if ( lstrcmp(InstanceName, pInstanceName) == 0 )
  1605.          {
  1606.  
  1607.          // Instance name matches
  1608.  
  1609.          if ( pParentName == NULL )
  1610.             {
  1611.  
  1612.             // No parent, we're done
  1613.  
  1614.             return pInstanceDef;
  1615.  
  1616.             }
  1617.          else
  1618.             {
  1619.  
  1620.             // Must match parent as well
  1621.  
  1622.             pParentObj = GetObjectDefByTitleIndex(
  1623.                pDataBlock,
  1624.                pInstanceDef->ParentObjectTitleIndex);
  1625.  
  1626.             if (!pParentObj)
  1627.                {
  1628.                // can't locate the parent, forget it
  1629.                break ;
  1630.                }
  1631.  
  1632.             // Object type of parent found; now find parent
  1633.             // instance
  1634.  
  1635.             pParentInst = GetInstance(pParentObj,
  1636.                pInstanceDef->ParentObjectInstance);
  1637.  
  1638.             if (!pParentInst)
  1639.                {
  1640.                // can't locate the parent instance, forget it
  1641.                break ;
  1642.                }
  1643.  
  1644.             GetInstanceNameStr(pParentInst,InstanceName);
  1645.             if ( lstrcmp(InstanceName, pParentName) == 0 )
  1646.                {
  1647.  
  1648.                // Parent Instance Name matches that passed in
  1649.  
  1650.                return pInstanceDef;
  1651.                }
  1652.             }
  1653.          }
  1654.       pInstanceDef = GetNextInstance(pInstanceDef);
  1655.       }
  1656.    return 0;
  1657. }
  1658.  
  1659. /***************************************************************************\
  1660. * GetInstanceByName()
  1661. *
  1662. * Entry: pointer to object type definition, the name of the instance,
  1663. *     and the name of the parent instance.
  1664. *     The name of the parent instance is NULL if no parent.
  1665. * Exit:  returns a pointer to the specified instance definition
  1666. *
  1667. \***************************************************************************/
  1668.  
  1669. PERF_INSTANCE_DEFINITION *GetInstanceByName(
  1670.     PERF_DATA_BLOCK *pDataBlock,
  1671.     PERF_OBJECT_TYPE *pObjectDef,
  1672.     LPTSTR pInstanceName,
  1673.     LPTSTR pParentName)
  1674. {
  1675.     BOOL fHaveParent;
  1676.  
  1677.     PERF_OBJECT_TYPE *pParentObj;
  1678.  
  1679.     PERF_INSTANCE_DEFINITION *pParentInst,
  1680.                  *pInstanceDef;
  1681.  
  1682.     LONG  NumInstance;
  1683.     TCHAR  InstanceName[256];
  1684.  
  1685.  
  1686.     fHaveParent = FALSE;
  1687.     pInstanceDef = FirstInstance(pObjectDef);
  1688.  
  1689.     for ( NumInstance = 0;
  1690.       NumInstance < pObjectDef->NumInstances;
  1691.       NumInstance++ ) {
  1692.  
  1693.         GetInstanceNameStr(pInstanceDef,InstanceName);
  1694.         if ( lstrcmp(InstanceName, pInstanceName) == 0 ) {
  1695.  
  1696.         // Instance name matches
  1697.  
  1698.         if ( !pInstanceDef->ParentObjectTitleIndex ) {
  1699.  
  1700.         // No parent, we're done
  1701.  
  1702.         return pInstanceDef;
  1703.  
  1704.         } else {
  1705.  
  1706.         // Must match parent as well
  1707.  
  1708.                 pParentObj = GetObjectDefByTitleIndex(
  1709.                  pDataBlock,
  1710.                                  pInstanceDef->ParentObjectTitleIndex);
  1711.  
  1712.         // Object type of parent found; now find parent
  1713.         // instance
  1714.  
  1715.         pParentInst = GetInstance(pParentObj,
  1716.                       pInstanceDef->ParentObjectInstance);
  1717.  
  1718.             GetInstanceNameStr(pParentInst,InstanceName);
  1719.                 if ( lstrcmp(InstanceName, pParentName) == 0 ) {
  1720.  
  1721.             // Parent Instance Name matches that passed in
  1722.  
  1723.             return pInstanceDef;
  1724.         }
  1725.         }
  1726.     }
  1727.         pInstanceDef = GetNextInstance(pInstanceDef);
  1728.     }
  1729.     return 0;
  1730. }  // GetInstanceByName
  1731.  
  1732.  
  1733. BOOL FailedLineData (PPERFDATA pPerfData,
  1734.                      PLINE pLine)
  1735. /*
  1736.         This routine handles the case where there is no data for a
  1737.         system.
  1738. */
  1739.  
  1740. {  // FailedLineData
  1741.    LONGLONG     liDummy ;
  1742.  
  1743.    // System no longer exists.
  1744.    liDummy = (LONGLONG) 0;
  1745.    if (pLine->lnCounterType == PERF_COUNTER_TIMER_INV)
  1746.    {
  1747.       // Timer inverse with Performance Counter as timer
  1748.       pLine->lnaOldCounterValue[0] = pLine->lnOldTime ;
  1749.       pLine->lnaCounterValue[0] = pLine->lnNewTime ;
  1750.    } else if (pLine->lnCounterType == PERF_100NSEC_TIMER_INV ||
  1751.               pLine->lnCounterType == PERF_100NSEC_MULTI_TIMER_INV)
  1752.    {
  1753.       // Timer inverse with System Time as timer
  1754.       pLine->lnaOldCounterValue[0] = pLine->lnOldTime100Ns ;
  1755.       pLine->lnaCounterValue[0] = pLine->lnNewTime100Ns ;
  1756.    } else
  1757.    {
  1758.       // Normal timer
  1759.       pLine->lnaOldCounterValue[0] =
  1760.       pLine->lnaCounterValue[0] =
  1761.       pLine->lnaOldCounterValue[1] =
  1762.       pLine->lnaCounterValue[1] = liDummy ;
  1763.    }
  1764.    return TRUE ;
  1765.  
  1766. }  // FailedLineData
  1767.  
  1768.  
  1769. BOOL UpdateLineData (PPERFDATA pPerfData, 
  1770.                      PLINE pLine,
  1771.                      PPERFSYSTEM pSystem)
  1772. /*
  1773.    Assert:        pPerfData holds the performance data for the same
  1774.                   system as pLine.
  1775. */
  1776. {  // UpdateLineData
  1777.    PPERFOBJECT       pObject ;
  1778.    PPERFINSTANCEDEF  pInstanceDef ;
  1779.    PPERFCOUNTERDEF   pCounterDef ;
  1780.    PPERFCOUNTERDEF   pCounterDef2 ;
  1781.    PDWORD            pCounterValue ;
  1782.    PDWORD            pCounterValue2 ;
  1783.    UINT              iCounterIndex ;
  1784.    LONGLONG          liDummy[2] ;
  1785.  
  1786.    // Use Object time units if available, otherwise use system
  1787.    // performance timer
  1788.  
  1789.    pLine->lnOldTime = pLine->lnNewTime;
  1790.  
  1791.    pLine->lnOldTime100Ns = pLine->lnNewTime100Ns;
  1792.    pLine->lnNewTime100Ns = *(LONGLONG UNALIGNED *)(&pPerfData->PerfTime100nSec);
  1793.  
  1794.    pLine->lnPerfFreq = *(LONGLONG UNALIGNED *)(&pPerfData->PerfFreq) ;
  1795.  
  1796.    if ((pLine->lnObject.TotalByteLength == 0) && !(PlayingBackLog()))
  1797.    {
  1798.       // this is the case when openning a setting file and the remote
  1799.       // system is not up at that time.  We have all the names but no
  1800.       // pObject, pCounter, etc.  So, we have to re-built the linedata.
  1801.       PPERFOBJECT       pObject ;
  1802.       PPERFCOUNTERDEF   pCounter ;
  1803.       PPERFINSTANCEDEF  pInstance ;
  1804.  
  1805.       pObject = LineFindObject (pSystem, pPerfData, pLine) ;
  1806.       if (!pObject)
  1807.       {
  1808.          //Something wrong, this object is still not there...
  1809.          return FALSE ;
  1810.       }
  1811.       pCounter = LineFindCounter (pSystem, pObject, pPerfData, pLine) ;
  1812.       if (!pCounter)
  1813.       {
  1814.          return FALSE ;
  1815.       }
  1816.       if (pObject &&
  1817.           pLine->lnObject.NumInstances > 0 &&
  1818.           pLine->lnInstanceName == NULL)
  1819.       {
  1820.          return FALSE ;
  1821.       }
  1822.       pInstance = LineFindInstance (pPerfData, pObject, pLine) ;
  1823.       if (!pInstance)
  1824.       {
  1825.          if (pLine->lnParentObjName)
  1826.          {
  1827.             MemoryFree (pLine->lnParentObjName) ;
  1828.             pLine->lnParentObjName = NULL ;
  1829.          }
  1830.       }
  1831.  
  1832.       pLine->lnCounterType = pCounter->CounterType;
  1833.       pLine->lnCounterLength = pCounter->CounterSize;
  1834.  
  1835.       if (pSystem->lpszValue && strsame (pSystem->lpszValue, L"Global"))
  1836.       {
  1837.          DWORD dwBufferSize = MemorySize (pSystem->lpszValue) ;
  1838.          memset (pSystem->lpszValue, 0, dwBufferSize) ;
  1839.       }
  1840.  
  1841.       AppendObjectToValueList (
  1842.                     pLine->lnObject.ObjectNameTitleIndex,
  1843.                     pSystem->lpszValue);
  1844.  
  1845.       
  1846.    }
  1847.  
  1848.    pObject = GetObjectDefByTitleIndex(
  1849.                 pPerfData,
  1850.                 pLine->lnObject.ObjectNameTitleIndex);
  1851.  
  1852.    if (!pObject)
  1853.    {
  1854.       // Object Type no longer exists.  This is possible if we are
  1855.       // looking at a log file which has not always collected all
  1856.       // the same data, such as appending measurements of different
  1857.       // object types.
  1858.  
  1859.       pCounterValue =
  1860.       pCounterValue2 = (PDWORD) liDummy;
  1861.       liDummy[0] = (LONGLONG)0;
  1862.  
  1863.  
  1864.       pLine->lnNewTime = *(LONGLONG UNALIGNED *)(&pPerfData->PerfTime);
  1865.  
  1866.       if (pLine->lnCounterType == PERF_COUNTER_TIMER_INV)
  1867.       {
  1868.          // Timer inverse with Performance Counter as timer
  1869.          pLine->lnaOldCounterValue[0] = pLine->lnOldTime ;
  1870.          pLine->lnaCounterValue[0] = pLine->lnNewTime ;
  1871.       } else if (pLine->lnCounterType == PERF_100NSEC_TIMER_INV ||
  1872.                  pLine->lnCounterType == PERF_100NSEC_MULTI_TIMER_INV)
  1873.       {
  1874.          // Timer inverse with System Time as timer
  1875.          pLine->lnaOldCounterValue[0] = pLine->lnOldTime100Ns ;
  1876.          pLine->lnaCounterValue[0] = pLine->lnNewTime100Ns ;
  1877.       } else
  1878.       {
  1879.          // Normal timer or counter
  1880.          pLine->lnaOldCounterValue[0] =
  1881.          pLine->lnaCounterValue[0] =
  1882.          pLine->lnaOldCounterValue[1] =
  1883.          pLine->lnaCounterValue[1] = liDummy[0] ;
  1884.       }
  1885.       return TRUE ;
  1886.    }
  1887.    else
  1888.    {
  1889.       pCounterDef = &pLine->lnCounterDef ;
  1890.  
  1891.       if (pCounterDef->CounterType & PERF_OBJECT_TIMER) {
  1892.          pLine->lnNewTime = *(LONGLONG UNALIGNED *)(&pObject->PerfTime);
  1893.       } else {
  1894.          pLine->lnNewTime = *(LONGLONG UNALIGNED *)(&pPerfData->PerfTime);
  1895.       }
  1896.     
  1897.       iCounterIndex = CounterIndex (pCounterDef, pObject) ;
  1898.  
  1899.       // Get second counter, only if we are not at
  1900.       // the end of the counters; some computations
  1901.       // require a second counter
  1902.  
  1903.       if (iCounterIndex < pObject->NumCounters-1 && iCounterIndex != -1) {
  1904.           pCounterDef2 = GetCounterDef(pObject, iCounterIndex+1);
  1905.       } else {
  1906.           pCounterDef2 = NULL;
  1907.       }
  1908.  
  1909.       if (pObject->NumInstances > 0)
  1910.       {
  1911.  
  1912.           if ( pLine->lnUniqueID != PERF_NO_UNIQUE_ID ) {
  1913.               pInstanceDef = GetInstanceByUniqueID(pObject,
  1914.                                                pLine->lnUniqueID);
  1915.           } else {
  1916.  
  1917.               pInstanceDef =
  1918.                   GetInstanceByNameUsingParentTitleIndex(
  1919.                       pPerfData,
  1920.                       pObject,
  1921.                       pLine->lnInstanceName,
  1922.                       pLine->lnPINName);
  1923.           }
  1924.  
  1925.           if (pInstanceDef) {
  1926.               pLine->lnInstanceDef = *pInstanceDef;
  1927.               pCounterValue = GetInstanceCounterData(pObject,
  1928.                                                pInstanceDef,
  1929.                                                pCounterDef);
  1930.               if ( pCounterDef2 ) {
  1931.                   pCounterValue2 = GetInstanceCounterData(pObject,
  1932.                                                     pInstanceDef,
  1933.                                                     pCounterDef2);
  1934.               }
  1935.           } else {
  1936.               pCounterValue =
  1937.               pCounterValue2 = (PDWORD) liDummy;
  1938.               liDummy[0] = (LONGLONG) 0;
  1939.               liDummy[1] = (LONGLONG) 0;
  1940.           }
  1941.  
  1942.           // Got everything...
  1943.  
  1944.       } // instances exist, look at them for counter blocks
  1945.  
  1946.       else
  1947.       {
  1948.           pCounterValue = GetCounterData(pObject, pCounterDef);
  1949.           if (pCounterDef2)
  1950.           {
  1951.               pCounterValue2 = GetCounterData(pObject, pCounterDef2);
  1952.           }
  1953.  
  1954.       } // counter def search when no instances
  1955.    }
  1956.  
  1957.    pLine->lnaOldCounterValue[0] = pLine->lnaCounterValue[0] ;
  1958.  
  1959.    if (pLine->lnCounterLength <= 4)
  1960.    {
  1961.        pLine->lnaCounterValue[0] = *pCounterValue;
  1962.        pLine->lnaCounterValue[0] &= (LONGLONG) (0x0ffffffff) ;
  1963.    }
  1964.    else
  1965.    {
  1966.        pLine->lnaCounterValue[0] = *(LONGLONG UNALIGNED *) pCounterValue;
  1967.    }
  1968.  
  1969.    // Get second counter, only if we are not at
  1970.    // the end of the counters; some computations
  1971.    // require a second counter
  1972.  
  1973.    if ( pCounterDef2 ) {
  1974.        pLine->lnaOldCounterValue[1] =
  1975.            pLine->lnaCounterValue[1] ;
  1976.        if (pCounterDef2->CounterSize <= 4)
  1977.        {
  1978.            pLine->lnaCounterValue[1] = *pCounterValue2;
  1979.            pLine->lnaCounterValue[1] &= (LONGLONG) (0x0ffffffff) ;
  1980.        }
  1981.        else
  1982.            pLine->lnaCounterValue[1] =
  1983.                *((LONGLONG UNALIGNED *) pCounterValue2);
  1984.       }
  1985.    return (TRUE) ;
  1986. }  // UpdateLineData
  1987.  
  1988.  
  1989.  
  1990. BOOL UpdateSystemData (PPERFSYSTEM pSystem, 
  1991.                        PPERFDATA *ppPerfData)
  1992.    {  // UpdateSystemData
  1993.    #define        PERF_SYSTEM_TIMEOUT (60L * 1000L)
  1994.    long           lError ;
  1995.    DWORD          Status ;
  1996.    DWORD          Size;
  1997.  
  1998.    if (!ppPerfData)
  1999.       return (FALSE) ;
  2000.  
  2001.    while (TRUE)
  2002.       {
  2003.       if (pSystem->FailureTime)
  2004.          {
  2005.          BOOL     TimeToCheck = FALSE ;
  2006.          DWORD    CurrentTickCount = GetTickCount() ;
  2007.  
  2008.          if (CurrentTickCount < pSystem->FailureTime) {
  2009.             // wrap-around case
  2010.             if (CurrentTickCount >= PERF_SYSTEM_TIMEOUT)
  2011.                TimeToCheck = TRUE ;
  2012.             else if ( ~pSystem->FailureTime >= PERF_SYSTEM_TIMEOUT)
  2013.                TimeToCheck = TRUE ;
  2014.             else if (CurrentTickCount + (~pSystem->FailureTime) >= PERF_SYSTEM_TIMEOUT)
  2015.                TimeToCheck = TRUE ;
  2016.             }
  2017.          else {
  2018.             if (CurrentTickCount - pSystem->FailureTime >= PERF_SYSTEM_TIMEOUT)
  2019.                TimeToCheck = TRUE ;
  2020.             }
  2021.  
  2022.          if (TimeToCheck)
  2023.             {
  2024.             // free any memory hanging off this system
  2025.             SystemFree (pSystem, FALSE) ;
  2026.  
  2027.             // get the registry info
  2028.             pSystem->sysDataKey = OpenSystemPerfData(pSystem->sysName) ;
  2029.  
  2030.             Status = !ERROR_SUCCESS ;
  2031.             if (pSystem->sysDataKey) 
  2032.                {
  2033.                Status = GetSystemNames(pSystem);
  2034.                }
  2035.  
  2036.             if (Status != ERROR_SUCCESS)
  2037.                {
  2038.                // something wrong in getting the registry info,
  2039.                // remote system must be still down (??)
  2040.                pSystem->FailureTime = GetTickCount();
  2041.  
  2042.                // Free any memory that may have created
  2043.                SystemFree (pSystem, FALSE) ;
  2044.  
  2045.                return (FALSE) ;
  2046.                }
  2047.  
  2048.             // time to check again
  2049.             pSystem->FailureTime = 0 ;
  2050.             }
  2051.          else
  2052.             {
  2053.             // not time to check again
  2054.             return (FALSE) ;
  2055.             }
  2056.          }
  2057.  
  2058.       if (pSystem->FailureTime == 0 )
  2059.          {
  2060.          Size = MemorySize (*ppPerfData);
  2061.  
  2062.          lError = GetSystemPerfData (pSystem->sysDataKey,
  2063.                                      pSystem->lpszValue,
  2064.                                      *ppPerfData,
  2065.                                      &Size) ;
  2066.          if ((!lError) &&
  2067.             (Size > 0) &&
  2068.             (*ppPerfData)->Signature[0] == (WCHAR)'P' &&
  2069.             (*ppPerfData)->Signature[1] == (WCHAR)'E' &&
  2070.             (*ppPerfData)->Signature[2] == (WCHAR)'R' &&
  2071.             (*ppPerfData)->Signature[3] == (WCHAR)'F' )
  2072.             {
  2073.             if (pSystem->dwSystemState == SYSTEM_OK)
  2074.                {
  2075.                return (TRUE) ;
  2076.                }
  2077.             else if (pSystem->dwSystemState == SYSTEM_DOWN ||
  2078.                pSystem->dwSystemState == SYSTEM_DOWN_RPT )
  2079.                {
  2080.                pSystem->dwSystemState = SYSTEM_RECONNECT ;
  2081.                }
  2082.             else if (pSystem->dwSystemState == SYSTEM_RECONNECT_RPT)
  2083.                {
  2084.                pSystem->dwSystemState = SYSTEM_OK ;
  2085.                }
  2086.             // for SYSTEM_RECONNECT case, we want to wait for Alert
  2087.             // view to report the re-connection first
  2088.             return (TRUE) ;
  2089.             }
  2090.  
  2091.          if (lError == ERROR_MORE_DATA)
  2092.             {
  2093.             *ppPerfData = MemoryResize (*ppPerfData, 
  2094.                                         MemorySize (*ppPerfData) +
  2095.                                         dwPerfDataIncrease) ;
  2096.             if (!*ppPerfData)
  2097.                {
  2098.                if (pSystem->dwSystemState != SYSTEM_DOWN_RPT)
  2099.                   {
  2100.                   pSystem->dwSystemState = SYSTEM_DOWN ;
  2101.                   }
  2102.                pSystem->FailureTime = GetTickCount();
  2103.                return (FALSE) ;
  2104.                }
  2105.             }
  2106.          else
  2107.             {
  2108.             if (pSystem->dwSystemState != SYSTEM_DOWN_RPT)
  2109.                {
  2110.                pSystem->dwSystemState = SYSTEM_DOWN ;
  2111.                }
  2112.             pSystem->FailureTime = GetTickCount();
  2113.             return (FALSE) ;
  2114.             }  // else
  2115.          } // if
  2116.       }  // while
  2117.    }  // UpdateSystemData
  2118.  
  2119.  
  2120.  
  2121. BOOL FailedLinesForSystem (LPTSTR lpszSystem,
  2122.                            PPERFDATA pPerfData, 
  2123.                            PLINE pLineFirst)
  2124.    {  // FailedLinesForSystem
  2125.    PLINE          pLine ;
  2126.    BOOL           bMatchFound = FALSE ;   // no line from this system
  2127.  
  2128.    for (pLine = pLineFirst ;
  2129.         pLine ;
  2130.         pLine = pLine->pLineNext)
  2131.       {  // for pLine
  2132.       if (strsamei (lpszSystem, pLine->lnSystemName))
  2133.          {
  2134.          FailedLineData (pPerfData, pLine) ;
  2135.          if (pLine->bFirstTime)
  2136.             {
  2137.             pLine->bFirstTime-- ;
  2138.             }
  2139.          bMatchFound = TRUE ; // one or more lines from this system
  2140.          }
  2141.       }  // for pLine
  2142.  
  2143.    return (bMatchFound) ;
  2144.    }
  2145.  
  2146.  
  2147. BOOL UpdateLinesForSystem (LPTSTR lpszSystem, 
  2148.                            PPERFDATA pPerfData, 
  2149.                            PLINE pLineFirst,
  2150.                            PPERFSYSTEM pSystem)
  2151.    {  // UpdateLinesForSystem
  2152.    PLINE          pLine ;
  2153.    BOOL           bMatchFound = FALSE ;   // no line from this system
  2154.  
  2155.    for (pLine = pLineFirst ;
  2156.         pLine ;
  2157.         pLine = pLine->pLineNext)
  2158.       {  // for pLine
  2159.       if (strsamei (lpszSystem, pLine->lnSystemName))
  2160.          {
  2161.          UpdateLineData (pPerfData, pLine, pSystem) ;
  2162.          if (pLine->bFirstTime)
  2163.             {
  2164.             pLine->bFirstTime-- ;
  2165.             }
  2166.          bMatchFound = TRUE ; // one or more lines from this system
  2167.          }
  2168.       }  // for pLine
  2169.  
  2170.    return (bMatchFound) ;
  2171.    }
  2172.  
  2173.  
  2174. BOOL PerfDataInitializeInstance (void)
  2175.    {
  2176. //   pGlobalPerfData = MemoryAllocate (STARTING_SYSINFO_SIZE) ;
  2177. //   return (pGlobalPerfData != NULL) ;
  2178.    return (TRUE) ;
  2179.    }
  2180.  
  2181. NTSTATUS  AddNamesToArray (LPTSTR lpNames,
  2182.    DWORD    dwLastId,
  2183.    LPWSTR   *lpCounterId)
  2184.    {
  2185.    LPWSTR      lpThisName;
  2186.    LPWSTR      lpStopString;
  2187.    DWORD       dwThisCounter;
  2188.    NTSTATUS    Status = ERROR_SUCCESS;
  2189.    
  2190.    for (lpThisName = lpNames;
  2191.         *lpThisName;
  2192.        )
  2193.       {
  2194.  
  2195.       // first string should be an integer (in decimal unicode digits)
  2196.       dwThisCounter = wcstoul(lpThisName, &lpStopString, 10);
  2197.  
  2198.       if ((dwThisCounter == 0) || (dwThisCounter == ULONG_MAX))
  2199.       {
  2200.          Status += 1;
  2201.          goto ADD_BAILOUT;  // bad entry
  2202.       }
  2203.  
  2204.       // point to corresponding counter name
  2205.  
  2206.       while (*lpThisName++);
  2207.  
  2208.       if (dwThisCounter <= dwLastId)
  2209.          {
  2210.  
  2211.          // and load array element;
  2212.  
  2213.          lpCounterId[dwThisCounter] = lpThisName;
  2214.  
  2215.          }
  2216.  
  2217.       while (*lpThisName++);
  2218.  
  2219.       }
  2220.  
  2221. ADD_BAILOUT:
  2222.    return (Status) ;
  2223.    }
  2224.  
  2225. // try the new way of getting data...
  2226.  
  2227. BOOL UpdateLines (PPPERFSYSTEM ppSystemFirst,
  2228.                   PLINE pLineFirst)
  2229.    {
  2230.    PPERFSYSTEM       pSystem ;
  2231.    int               iNoUseSystemDetected = 0 ;
  2232.    int               NumberOfSystems = 0 ;
  2233.    DWORD             WaitStatus ;
  2234.    HANDLE            *lpPacketHandles ;
  2235.    
  2236.    // allocate the handle array for multiple wait
  2237.    if (NumberOfHandles == 0)
  2238.       {
  2239.       NumberOfHandles = MAXIMUM_WAIT_OBJECTS ;
  2240.       lpHandles = (HANDLE *) MemoryAllocate (NumberOfHandles * sizeof (HANDLE)) ;
  2241.       if (!lpHandles)
  2242.          {
  2243.          // out of memory, can't go on
  2244.          NumberOfHandles = 0 ;
  2245.          return FALSE ;
  2246.          }
  2247.       }
  2248.  
  2249.  
  2250.    for (pSystem = *ppSystemFirst ;
  2251.         pSystem ;
  2252.         pSystem = pSystem->pSystemNext)
  2253.       {  // for
  2254.       
  2255.       // lock the state data mutex, should be quick unless this thread 
  2256.       // is still getting data from last time
  2257.       if (pSystem->hStateDataMutex == 0)
  2258.          continue ;
  2259.  
  2260.       WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 100L);
  2261.       if (WaitStatus == WAIT_OBJECT_0)
  2262.          {
  2263.          ResetEvent (pSystem->hPerfDataEvent) ;
  2264.          pSystem->StateData = WAIT_FOR_PERF_DATA ;
  2265.  
  2266.          // add this to the wait
  2267.          if (NumberOfSystems >= NumberOfHandles)
  2268.             {
  2269.             NumberOfHandles += MAXIMUM_WAIT_OBJECTS ;
  2270.             lpHandles = (HANDLE *) MemoryResize (
  2271.                lpHandles,
  2272.                NumberOfHandles * sizeof (HANDLE)) ;
  2273.             if (!lpHandles)
  2274.                {
  2275.                // out of memory, can't go on
  2276.                NumberOfHandles = 0 ;
  2277.                return FALSE ;
  2278.                }
  2279.             }
  2280.  
  2281.          lpHandles [NumberOfSystems] = pSystem->hPerfDataEvent ;
  2282.          NumberOfSystems++ ;
  2283.  
  2284.          // Send Message to thread to take a data sample
  2285.          PostThreadMessage (
  2286.             pSystem->dwThreadID,
  2287.             WM_GET_PERF_DATA,
  2288.             (WPARAM)0,
  2289.             (LPARAM)0) ;
  2290.  
  2291.          ReleaseMutex(pSystem->hStateDataMutex);
  2292.          }
  2293.       }
  2294.  
  2295.    // wait for all the data 
  2296.    if (NumberOfSystems)
  2297.       {
  2298.       // increase timeout if we are monitoring lots of systems
  2299.       // For every additional 5 systems, add 5 more seconds
  2300.       lpPacketHandles = lpHandles ;
  2301.       do
  2302.          {
  2303.          WaitStatus = WaitForMultipleObjects (
  2304.             min (NumberOfSystems, MAXIMUM_WAIT_OBJECTS),
  2305.             lpPacketHandles,
  2306.             TRUE,       // wait for all objects
  2307.             DataTimeOut + (NumberOfSystems / 5) * DEFAULT_DATA_TIMEOUT);
  2308.  
  2309.          if (WaitStatus == WAIT_TIMEOUT ||
  2310.             NumberOfSystems <= MAXIMUM_WAIT_OBJECTS)
  2311.             {
  2312. //if (WaitStatus == WAIT_TIMEOUT)
  2313. //   mike2(TEXT("WaitTimeOut for %ld systems\n"), NumberOfSystems) ;
  2314.  
  2315.             break ;
  2316.             }
  2317.  
  2318.          // more systems --> more to wait
  2319.          NumberOfSystems -= MAXIMUM_WAIT_OBJECTS ;
  2320.          lpPacketHandles += MAXIMUM_WAIT_OBJECTS ;
  2321.          } while (TRUE) ;
  2322.  
  2323.       for (pSystem = *ppSystemFirst ;
  2324.            pSystem ;
  2325.            pSystem = pSystem->pSystemNext)
  2326.          {  // for
  2327.  
  2328.          if (pSystem->hStateDataMutex == 0)
  2329.             continue ;
  2330.       
  2331.          // lock the state data mutex
  2332.          WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 100L);
  2333.          if (WaitStatus == WAIT_OBJECT_0)
  2334.             {
  2335.             if (pSystem->StateData != PERF_DATA_READY)
  2336.                {
  2337.                if (!FailedLinesForSystem (pSystem->sysName,
  2338.                   pSystem->pSystemPerfData,
  2339.                   pLineFirst))
  2340.                   {
  2341.                   if (!bAddLineInProgress)
  2342.                      {
  2343.                      // mark this system as no-longer-needed
  2344.                      iNoUseSystemDetected++ ;
  2345.                      pSystem->bSystemNoLongerNeeded = TRUE ;
  2346.                      }
  2347.                   }
  2348.                }
  2349.             else
  2350.                {
  2351.                if (!UpdateLinesForSystem (pSystem->sysName,
  2352.                     pSystem->pSystemPerfData,
  2353.                     pLineFirst,
  2354.                     pSystem))
  2355.                   {
  2356.                   if (!bAddLineInProgress)
  2357.                      {
  2358.                      // mark this system as no-longer-needed
  2359.                      iNoUseSystemDetected++ ;
  2360.                      pSystem->bSystemNoLongerNeeded = TRUE ;
  2361.                      }
  2362.                   }
  2363.                }
  2364.             pSystem->StateData = IDLE_STATE ;
  2365.             ReleaseMutex(pSystem->hStateDataMutex);
  2366.             }
  2367.          else
  2368.             {
  2369.             if (!FailedLinesForSystem (pSystem->sysName,
  2370.                pSystem->pSystemPerfData,
  2371.                pLineFirst))
  2372.                {
  2373.                if (!bAddLineInProgress)
  2374.                   {
  2375.                   // mark this system as no-longer-needed
  2376.                   iNoUseSystemDetected++ ;
  2377.                   pSystem->bSystemNoLongerNeeded = TRUE ;
  2378.                   }
  2379.                }
  2380.             }
  2381.          }
  2382.  
  2383.       // check for un-used systems
  2384.       if (iNoUseSystemDetected)
  2385.           {
  2386.           // some unused system(s) detected.
  2387.           DeleteUnusedSystems (ppSystemFirst, iNoUseSystemDetected) ;
  2388.           }
  2389.       }
  2390.  
  2391.    return (TRUE) ;
  2392.    }  // UpdateLines
  2393.  
  2394. void PerfDataThread (PPERFSYSTEM pSystem)
  2395.    {
  2396.    MSG      msg ;
  2397.    BOOL     bGetPerfData ;
  2398.    DWORD    WaitStatus ;
  2399.  
  2400.    while (GetMessage (&msg, NULL, 0, 0))
  2401.       {
  2402.       if (LOWORD(msg.message) == WM_GET_PERF_DATA)
  2403.          {
  2404.  
  2405.          // this system has been marked as no long used,
  2406.          // forget about getting data and continue until 
  2407.          // we get to the WM_FREE_SYSTEM msg
  2408.          if (pSystem->bSystemNoLongerNeeded)
  2409.             continue ;
  2410.  
  2411.          bGetPerfData = FALSE ;
  2412.  
  2413.          if (!bAddLineInProgress ||
  2414.             (pSystem->lpszValue &&
  2415.             !strsame (pSystem->lpszValue, L"Global")))
  2416.             {
  2417.             bGetPerfData = UpdateSystemData (pSystem, &(pSystem->pSystemPerfData)) ;
  2418.             }
  2419.  
  2420.          WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 1000L);
  2421.          if (WaitStatus == WAIT_OBJECT_0)
  2422.             {
  2423.             if (pSystem->StateData == WAIT_FOR_PERF_DATA)
  2424.                {
  2425.                pSystem->StateData = bGetPerfData ?
  2426.                   PERF_DATA_READY : PERF_DATA_FAIL ;
  2427.                }
  2428.             else
  2429.                {
  2430. //mike2(TEXT("Thread - System = %s, WaitStatus = %d\n"),
  2431. //pSystem->sysName, WaitStatus) ;
  2432.                }
  2433.             ReleaseMutex(pSystem->hStateDataMutex);
  2434.             SetEvent (pSystem->hPerfDataEvent) ;
  2435.             }
  2436.          }  // WM_GET_PERF_DATA MSG
  2437.  
  2438.       else if (LOWORD(msg.message) == WM_FREE_SYSTEM)
  2439.          {
  2440. //mike2(TEXT("Thread - System = %s closing\n"),
  2441. //pSystem->sysName) ;
  2442.          // do the memory cleanup during SystemFree stage
  2443.          // cleanup all the data collection variables
  2444.          if (pSystem->hPerfDataEvent)
  2445.              CloseHandle (pSystem->hPerfDataEvent) ;
  2446.  
  2447.          if (pSystem->hStateDataMutex)
  2448.              CloseHandle (pSystem->hStateDataMutex) ;
  2449.  
  2450.          if (pSystem->pSystemPerfData)
  2451.              MemoryFree (pSystem->pSystemPerfData);
  2452.  
  2453.          if (pSystem->lpszValue) {
  2454.              MemoryFree (pSystem->lpszValue);
  2455.              pSystem->lpszValue = NULL ;
  2456.          }
  2457.  
  2458.          CloseHandle (pSystem->hThread);
  2459.  
  2460.          MemoryFree (pSystem) ;
  2461.          break ;  // get out of message loop
  2462.          }  // WM_FREE_SYSTEM MSG
  2463.       }  // GetMessage Loop
  2464.  
  2465.    ExitThread (TRUE) ;
  2466.    }  // PerfDataThread
  2467.  
  2468.