1181 lines
40 KiB
C
1181 lines
40 KiB
C
/*++
|
|
|
|
Copyright (c) 1991-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dumpload.c
|
|
|
|
Abstract:
|
|
|
|
functions to dump and load the contents of the performance related registry
|
|
entries
|
|
|
|
Author:
|
|
|
|
Bob Watson (bobw) 13 Jun 99
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
--*/
|
|
#ifndef UNICODE
|
|
#define UNICODE 1
|
|
#endif
|
|
|
|
#ifndef _UNICODE
|
|
#define _UNICODE 1
|
|
#endif
|
|
//
|
|
// "C" Include files
|
|
//
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
//
|
|
// Windows Include files
|
|
//
|
|
#include <windows.h>
|
|
#include <winperf.h>
|
|
#include <loadperf.h>
|
|
#include "wmistr.h"
|
|
#include "evntrace.h"
|
|
//
|
|
// application include files
|
|
//
|
|
#include "winperfp.h"
|
|
#include "common.h"
|
|
#include "ldprfmsg.h"
|
|
|
|
static const WCHAR cszServiceKeyName[] = {L"SYSTEM\\CurrentControlSet\\Services"};
|
|
static const WCHAR cszPerflibKeyName[] = {L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"};
|
|
static const WCHAR cszLastCounter[] = {L"Last Counter"};
|
|
static const WCHAR cszFirstHelp[] = {L"First Help"};
|
|
static const WCHAR cszLastHelp[] = {L"Last Help"};
|
|
static const WCHAR cszBaseIndex[] = {L"Base Index"};
|
|
static const WCHAR cszPerformance[] = {L"\\Performance"};
|
|
static const WCHAR cszDisablePerformanceCounters[] = {L"Disable Performance Counters"};
|
|
|
|
// headings in save file
|
|
static const WCHAR cszFmtSectionHeader[] = {L"\r\n\r\n[%s]"};
|
|
static const WCHAR cszFmtServiceSectionHeader[] = {L"\r\n\r\n[PERF_%s]"};
|
|
static const WCHAR cszFmtServiceSectionName[] = {L"PERF_%s"};
|
|
static const WCHAR cszFmtStringSectionHeader[] = {L"\r\n\r\n[PerfStrings_%s]"};
|
|
static const WCHAR cszFmtExtCtrString[] = {L"\r\n%d=%s"};
|
|
static const WCHAR cszFmtDecimalParam[] = {L"\r\n%s=%d"};
|
|
static const WCHAR cszFmtNoParam[] = {L"\r\n%s="};
|
|
|
|
static const WCHAR cszExtensiblePerfStrings[] = {L"Strings"};
|
|
static const WCHAR cszPerfCounterServices[] = {L"PerfCounterServices"};
|
|
static const WCHAR cszNoPerfCounterServices[] = {L"NoPerfCounterServices"};
|
|
static const WCHAR cszPerflib[] = {L"Perflib"};
|
|
|
|
// external forward definitions
|
|
LPWSTR
|
|
*BuildNameTable(
|
|
HKEY hKeyRegistry, // handle to registry db with counter names
|
|
LPWSTR lpszLangId, // unicode value of Language subkey
|
|
PDWORD pdwLastItem // size of array in elements
|
|
);
|
|
|
|
DWORD
|
|
UpdatePerfNameFilesX (
|
|
IN LPCWSTR szNewCtrFilePath, // data file with new base counter strings
|
|
IN LPCWSTR szNewHlpFilePath, // data file with new base counter strings
|
|
IN LPWSTR szLanguageID, // Lang ID to update
|
|
IN ULONG_PTR dwFlags // flags
|
|
);
|
|
|
|
DWORD
|
|
static
|
|
DumpNameTable (
|
|
IN HANDLE hOutputFile,
|
|
IN LPCWSTR szLangId,
|
|
IN LPCWSTR *pszNameTable,
|
|
IN DWORD dwStartIndex,
|
|
IN DWORD dwLastIndex
|
|
)
|
|
{
|
|
DWORD ndx;
|
|
WCHAR szOutputBuffer[4096];
|
|
DWORD dwSize, dwSizeWritten;
|
|
|
|
dwSize = swprintf (szOutputBuffer, cszFmtStringSectionHeader, szLangId);
|
|
dwSize *= sizeof (WCHAR);
|
|
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
|
|
for (ndx = dwStartIndex; ndx <= dwLastIndex; ndx++) {
|
|
if (pszNameTable[ndx] != NULL) {
|
|
dwSize = swprintf (szOutputBuffer, cszFmtExtCtrString, ndx, pszNameTable[ndx] );
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
}
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
static
|
|
DumpPerfServiceEntries (
|
|
IN HANDLE hOutputFile,
|
|
IN LPCWSTR szServiceName
|
|
)
|
|
{
|
|
LONG lStatus = ERROR_SUCCESS;
|
|
WCHAR szPerfSubKeyName[MAX_PATH+20];
|
|
HKEY hKeyPerformance;
|
|
HKEY hKeyServices = NULL;
|
|
DWORD dwItemSize, dwType, dwValue;
|
|
DWORD dwRegAccessMask;
|
|
DWORD dwRetStatus = ERROR_SUCCESS;
|
|
|
|
DWORD dwSize, dwSizeWritten;
|
|
WCHAR szOutputBuffer[4096];
|
|
|
|
// try read-only then
|
|
dwRegAccessMask = KEY_READ;
|
|
lStatus = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
|
|
cszServiceKeyName,
|
|
0L,
|
|
dwRegAccessMask,
|
|
&hKeyServices);
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
//try to open the perfkey under this key.
|
|
lstrcpy (szPerfSubKeyName, szServiceName);
|
|
lstrcat (szPerfSubKeyName, cszPerformance);
|
|
|
|
lStatus = RegOpenKeyExW (
|
|
hKeyServices,
|
|
szPerfSubKeyName,
|
|
0L,
|
|
dwRegAccessMask,
|
|
&hKeyPerformance);
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
// key found so service has perf data
|
|
dwSize = swprintf (szOutputBuffer, cszFmtServiceSectionHeader, szServiceName);
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
|
|
// now check to see if the strings have been loaded
|
|
dwType = dwValue = 0;
|
|
dwItemSize = sizeof (dwValue);
|
|
lStatus = RegQueryValueExW (
|
|
hKeyPerformance,
|
|
cszFirstCounter,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwItemSize);
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFSERVICEENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceName),
|
|
TRACE_WSTR(cszFirstCounter),
|
|
TRACE_DWORD(dwValue),
|
|
NULL));
|
|
if ((lStatus == ERROR_SUCCESS) &&
|
|
((dwType == REG_DWORD) || dwType == REG_BINARY)) {
|
|
dwSize = swprintf (szOutputBuffer, cszFmtDecimalParam, cszFirstCounter, dwValue);
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
}
|
|
|
|
dwType = dwValue = 0;
|
|
dwItemSize = sizeof (dwValue);
|
|
lStatus = RegQueryValueExW (
|
|
hKeyPerformance,
|
|
cszFirstHelp,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwItemSize);
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFSERVICEENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceName),
|
|
TRACE_WSTR(cszFirstHelp),
|
|
TRACE_DWORD(dwValue),
|
|
NULL));
|
|
if ((lStatus == ERROR_SUCCESS) &&
|
|
((dwType == REG_DWORD) || dwType == REG_BINARY)) {
|
|
dwSize = swprintf (szOutputBuffer, cszFmtDecimalParam, cszFirstHelp, dwValue);
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
}
|
|
|
|
dwType = dwValue = 0;
|
|
dwItemSize = sizeof (dwValue);
|
|
lStatus = RegQueryValueExW (
|
|
hKeyPerformance,
|
|
cszLastCounter,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwItemSize);
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFSERVICEENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceName),
|
|
TRACE_WSTR(cszLastCounter),
|
|
TRACE_DWORD(dwValue),
|
|
NULL));
|
|
if ((lStatus == ERROR_SUCCESS) &&
|
|
((dwType == REG_DWORD) || dwType == REG_BINARY)) {
|
|
dwSize = swprintf (szOutputBuffer, cszFmtDecimalParam, cszLastCounter, dwValue);
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
}
|
|
|
|
dwType = dwValue = 0;
|
|
dwItemSize = sizeof (dwValue);
|
|
lStatus = RegQueryValueExW (
|
|
hKeyPerformance,
|
|
cszLastHelp,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwItemSize);
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFSERVICEENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceName),
|
|
TRACE_WSTR(cszLastHelp),
|
|
TRACE_DWORD(dwValue),
|
|
NULL));
|
|
if ((lStatus == ERROR_SUCCESS) &&
|
|
((dwType == REG_DWORD) || dwType == REG_BINARY)) {
|
|
dwSize = swprintf (szOutputBuffer, cszFmtDecimalParam, cszLastHelp, dwValue);
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
}
|
|
|
|
dwType = dwValue = 0;
|
|
dwItemSize = sizeof (dwValue);
|
|
lStatus = RegQueryValueExW (
|
|
hKeyPerformance,
|
|
cszDisablePerformanceCounters,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwItemSize);
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFSERVICEENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceName),
|
|
TRACE_WSTR(cszDisablePerformanceCounters),
|
|
TRACE_DWORD(dwValue),
|
|
NULL));
|
|
if ((lStatus == ERROR_SUCCESS) &&
|
|
((dwType == REG_DWORD) || dwType == REG_BINARY)) {
|
|
dwSize = swprintf (szOutputBuffer, cszFmtDecimalParam, cszDisablePerformanceCounters, dwValue);
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
}
|
|
|
|
RegCloseKey (hKeyPerformance);
|
|
} else {
|
|
dwRetStatus = lStatus;
|
|
TRACE((WINPERF_DBG_TRACE_ERROR),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFSERVICEENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceName),
|
|
NULL));
|
|
}
|
|
|
|
RegCloseKey (hKeyServices);
|
|
}
|
|
else {
|
|
dwRetStatus = lStatus;
|
|
TRACE((WINPERF_DBG_TRACE_ERROR),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFSERVICEENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
lStatus,
|
|
TRACE_WSTR(cszServiceKeyName),
|
|
NULL));
|
|
}
|
|
|
|
return dwRetStatus;
|
|
}
|
|
|
|
DWORD
|
|
static
|
|
DumpPerflibEntries (
|
|
IN HANDLE hOutputFile,
|
|
IN LPDWORD pdwFirstExtCtrIndex
|
|
|
|
)
|
|
{
|
|
HKEY hKeyPerflib = NULL;
|
|
DWORD dwStatus;
|
|
DWORD dwItemSize, dwType, dwValue;
|
|
|
|
DWORD dwSize, dwSizeWritten;
|
|
WCHAR szOutputBuffer[4096];
|
|
|
|
dwStatus = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
|
|
cszPerflibKeyName,
|
|
0L,
|
|
KEY_READ,
|
|
&hKeyPerflib);
|
|
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
dwSize = swprintf (szOutputBuffer, cszFmtSectionHeader, cszPerflib);
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
}
|
|
else {
|
|
TRACE((WINPERF_DBG_TRACE_ERROR),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFLIBENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
dwStatus,
|
|
TRACE_WSTR(cszPerflibKeyName),
|
|
NULL));
|
|
}
|
|
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
dwType = dwValue = 0;
|
|
dwItemSize = sizeof (dwValue);
|
|
dwStatus = RegQueryValueEx (
|
|
hKeyPerflib,
|
|
cszBaseIndex,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwItemSize);
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFLIBENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
dwStatus,
|
|
TRACE_WSTR(cszBaseIndex),
|
|
TRACE_DWORD(dwValue),
|
|
NULL));
|
|
if ((dwStatus == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
|
|
dwSize = swprintf (szOutputBuffer, cszFmtDecimalParam, cszBaseIndex, dwValue);
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
*pdwFirstExtCtrIndex = dwValue + 1;
|
|
}
|
|
}
|
|
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
dwType = dwValue = 0;
|
|
dwItemSize = sizeof (dwValue);
|
|
dwStatus = RegQueryValueEx (
|
|
hKeyPerflib,
|
|
cszLastCounter,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwItemSize);
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFLIBENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
dwStatus,
|
|
TRACE_WSTR(cszLastCounter),
|
|
TRACE_DWORD(dwValue),
|
|
NULL));
|
|
if ((dwStatus == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
|
|
dwSize = swprintf (szOutputBuffer, cszFmtDecimalParam, cszLastCounter, dwValue);
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
}
|
|
}
|
|
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
dwType = dwValue = 0;
|
|
dwItemSize = sizeof (dwValue);
|
|
dwStatus = RegQueryValueEx (
|
|
hKeyPerflib,
|
|
cszLastHelp,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwItemSize);
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_DUMPPERFLIBENTRIES,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
dwStatus,
|
|
TRACE_WSTR(cszLastHelp),
|
|
TRACE_DWORD(dwValue),
|
|
NULL));
|
|
if ((dwStatus == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
|
|
dwSize = swprintf (szOutputBuffer, cszFmtDecimalParam, cszLastHelp, dwValue);
|
|
dwSize *= sizeof (WCHAR);
|
|
WriteFile (hOutputFile, szOutputBuffer, dwSize, &dwSizeWritten, NULL);
|
|
}
|
|
}
|
|
|
|
if (hKeyPerflib != NULL) RegCloseKey (hKeyPerflib);
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
DWORD
|
|
static
|
|
BuildServiceLists (
|
|
IN LPWSTR mszPerfServiceList,
|
|
IN LPDWORD pcchPerfServiceListSize,
|
|
IN LPWSTR mszNoPerfServiceList,
|
|
IN LPDWORD pcchNoPerfServiceListSize
|
|
)
|
|
{
|
|
LONG lStatus = ERROR_SUCCESS;
|
|
LONG lEnumStatus = ERROR_SUCCESS;
|
|
DWORD dwServiceIndex = 0;
|
|
WCHAR szServiceSubKeyName[MAX_PATH];
|
|
WCHAR szPerfSubKeyName[MAX_PATH+20];
|
|
DWORD dwNameSize = MAX_PATH;
|
|
HKEY hKeyPerformance;
|
|
HKEY hKeyServices = NULL;
|
|
DWORD dwItemSize, dwType, dwValue;
|
|
DWORD dwRegAccessMask;
|
|
DWORD bServiceHasPerfCounters;
|
|
DWORD dwRetStatus = ERROR_SUCCESS;
|
|
|
|
LPWSTR szNextNoPerfChar, szNextPerfChar;
|
|
DWORD dwNoPerfSizeRem, dwPerfSizeRem;
|
|
DWORD dwPerfSizeUsed = 0, dwNoPerfSizeUsed = 0;
|
|
|
|
// try read-only then
|
|
dwRegAccessMask = KEY_READ;
|
|
lStatus = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
|
|
cszServiceKeyName,
|
|
0L,
|
|
dwRegAccessMask,
|
|
&hKeyServices);
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
szNextNoPerfChar = mszNoPerfServiceList;
|
|
szNextPerfChar = mszPerfServiceList;
|
|
dwNoPerfSizeRem = *pcchPerfServiceListSize;
|
|
dwPerfSizeRem = *pcchNoPerfServiceListSize;
|
|
dwPerfSizeUsed = 0;
|
|
dwNoPerfSizeUsed = 0;
|
|
|
|
while ((lEnumStatus = RegEnumKeyExW (
|
|
hKeyServices,
|
|
dwServiceIndex,
|
|
szServiceSubKeyName,
|
|
&dwNameSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL)) == ERROR_SUCCESS) {
|
|
|
|
//try to open the perfkey under this key.
|
|
lstrcpy (szPerfSubKeyName, szServiceSubKeyName);
|
|
lstrcat (szPerfSubKeyName, cszPerformance);
|
|
|
|
lStatus = RegOpenKeyExW (
|
|
hKeyServices,
|
|
szPerfSubKeyName,
|
|
0L,
|
|
dwRegAccessMask,
|
|
&hKeyPerformance);
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
// key found so service has perf data
|
|
// now check to see if the strings have been loaded
|
|
dwType = dwValue = 0;
|
|
dwItemSize = sizeof (dwValue);
|
|
lStatus = RegQueryValueExW (
|
|
hKeyPerformance,
|
|
cszFirstCounter,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwItemSize);
|
|
if ((lStatus == ERROR_SUCCESS) &&
|
|
((dwType == REG_DWORD) || dwType == REG_BINARY)) {
|
|
bServiceHasPerfCounters = TRUE;
|
|
} else {
|
|
bServiceHasPerfCounters = FALSE;
|
|
}
|
|
|
|
RegCloseKey (hKeyPerformance);
|
|
} else {
|
|
// key not found so service doesn't have perfdata
|
|
bServiceHasPerfCounters = FALSE;
|
|
}
|
|
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_BUILDSERVICELISTS,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceSubKeyName),
|
|
TRACE_DWORD(bServiceHasPerfCounters),
|
|
NULL));
|
|
|
|
if (bServiceHasPerfCounters != FALSE) {
|
|
// add to the perf service list
|
|
if ((dwNameSize + 1)< dwPerfSizeRem) {
|
|
// add to list
|
|
lstrcpyW (szNextPerfChar, szServiceSubKeyName);
|
|
szNextPerfChar += dwNameSize;
|
|
*szNextPerfChar = 0;
|
|
szNextPerfChar++;
|
|
dwPerfSizeRem -= dwNameSize + 1;
|
|
} else {
|
|
dwRetStatus = ERROR_MORE_DATA;
|
|
}
|
|
dwPerfSizeUsed += dwNameSize + 1;
|
|
} else {
|
|
// add to the no perf list
|
|
if ((dwNameSize + 1) < dwNoPerfSizeRem) {
|
|
// add to list
|
|
lstrcpyW (szNextNoPerfChar, szServiceSubKeyName);
|
|
szNextNoPerfChar += dwNameSize;
|
|
*szNextNoPerfChar = 0;
|
|
szNextNoPerfChar++;
|
|
dwNoPerfSizeRem -= dwNameSize + 1;
|
|
} else {
|
|
dwRetStatus = ERROR_MORE_DATA;
|
|
}
|
|
dwNoPerfSizeUsed += dwNameSize + 1;
|
|
}
|
|
// reset for next loop
|
|
dwServiceIndex++;
|
|
dwNameSize = MAX_PATH;
|
|
}
|
|
|
|
// zero term the MSZ
|
|
if (1 < dwPerfSizeRem) {
|
|
*szNextPerfChar = 0;
|
|
szNextPerfChar++;
|
|
dwPerfSizeRem -= 1;
|
|
} else {
|
|
dwRetStatus = ERROR_MORE_DATA;
|
|
}
|
|
dwPerfSizeUsed += 1;
|
|
|
|
// zero term the no perf list
|
|
if (1 < dwNoPerfSizeRem) {
|
|
// add to list
|
|
*szNextNoPerfChar = 0;
|
|
szNextNoPerfChar++;
|
|
dwNoPerfSizeRem -= 1;
|
|
} else {
|
|
dwRetStatus = ERROR_MORE_DATA;
|
|
}
|
|
dwNoPerfSizeUsed += 1;
|
|
}
|
|
else {
|
|
TRACE((WINPERF_DBG_TRACE_ERROR),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_BUILDSERVICELISTS,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
lStatus,
|
|
TRACE_WSTR(cszServiceKeyName),
|
|
NULL));
|
|
}
|
|
|
|
if (hKeyServices != NULL) RegCloseKey (hKeyServices);
|
|
|
|
*pcchPerfServiceListSize = dwPerfSizeUsed;
|
|
*pcchNoPerfServiceListSize = dwNoPerfSizeUsed;
|
|
|
|
return dwRetStatus;
|
|
}
|
|
|
|
|
|
DWORD
|
|
BackupPerfRegistryToFileW (
|
|
IN LPCWSTR szFileName,
|
|
IN LPCWSTR szCommentString
|
|
)
|
|
{
|
|
HANDLE hOutFile;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
LPWSTR szNewFileName = NULL;
|
|
DWORD dwNewFileNameLen;
|
|
DWORD dwOrigFileNameLen;
|
|
DWORD dwFileNameSN;
|
|
|
|
LPWSTR mszPerfServiceList = NULL;
|
|
DWORD dwPerfServiceListSize = 0;
|
|
LPWSTR mszNoPerfServiceList = NULL;
|
|
DWORD dwNoPerfServiceListSize = 0;
|
|
|
|
LPWSTR *lpCounterText = NULL;
|
|
DWORD dwLastElement = 0;
|
|
DWORD dwFirstExtCtrIndex = 0;
|
|
|
|
LPWSTR szThisServiceName;
|
|
|
|
LPWSTR szLangId = (LPWSTR)L"009";
|
|
|
|
DBG_UNREFERENCED_PARAMETER (szCommentString);
|
|
|
|
WinPerfStartTrace(NULL);
|
|
|
|
// open output file
|
|
hOutFile = CreateFileW (
|
|
szFileName,
|
|
GENERIC_WRITE,
|
|
0, // no sharing
|
|
NULL, // default security
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
// if the file open failed
|
|
if (hOutFile == INVALID_HANDLE_VALUE) {
|
|
// see if it's because the file already exists
|
|
dwStatus = GetLastError();
|
|
if (dwStatus == ERROR_FILE_EXISTS) {
|
|
// then try appending a serial number to the name
|
|
dwOrigFileNameLen = lstrlenW (szFileName);
|
|
dwNewFileNameLen = dwOrigFileNameLen + 4;
|
|
szNewFileName = HeapAlloc (
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
(dwNewFileNameLen +1) * sizeof(WCHAR));
|
|
if (szNewFileName != NULL) {
|
|
lstrcpyW (szNewFileName, szFileName);
|
|
for (dwFileNameSN = 1; dwFileNameSN < 1000; dwFileNameSN++) {
|
|
swprintf (&szNewFileName[dwOrigFileNameLen],
|
|
(LPCWSTR)L"_%3.3d", dwFileNameSN);
|
|
hOutFile = CreateFileW (
|
|
szNewFileName,
|
|
GENERIC_WRITE,
|
|
0, // no sharing
|
|
NULL, // default security
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
// if the file open failed
|
|
if (hOutFile == INVALID_HANDLE_VALUE) {
|
|
dwStatus = GetLastError();
|
|
if (dwStatus != ERROR_FILE_EXISTS) {
|
|
// some other error occurred so bail out
|
|
break;
|
|
} else {
|
|
continue; // with the next try
|
|
}
|
|
} else {
|
|
// found one not in use so continue on
|
|
dwStatus = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
dwStatus = ERROR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
} else {
|
|
// file opened so continue
|
|
dwStatus = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
// dump perflib key entires
|
|
dwStatus = DumpPerflibEntries (hOutFile, &dwFirstExtCtrIndex);
|
|
}
|
|
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
do {
|
|
if (mszPerfServiceList != NULL) {
|
|
HeapFree (GetProcessHeap(), 0, mszPerfServiceList);
|
|
mszPerfServiceList = NULL;
|
|
}
|
|
|
|
if (mszNoPerfServiceList != NULL) {
|
|
HeapFree (GetProcessHeap(), 0, mszNoPerfServiceList);
|
|
mszNoPerfServiceList = NULL;
|
|
}
|
|
|
|
// build service lists
|
|
dwPerfServiceListSize += 32768;
|
|
dwNoPerfServiceListSize += 65536;
|
|
mszPerfServiceList = HeapAlloc (
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
(dwPerfServiceListSize) * sizeof(WCHAR));
|
|
|
|
mszNoPerfServiceList = HeapAlloc (
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
(dwNoPerfServiceListSize) * sizeof(WCHAR));
|
|
|
|
if ((mszNoPerfServiceList == NULL) || (mszPerfServiceList == NULL)) {
|
|
dwStatus = ERROR_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
dwStatus = BuildServiceLists (
|
|
mszPerfServiceList,
|
|
&dwPerfServiceListSize,
|
|
mszNoPerfServiceList,
|
|
&dwNoPerfServiceListSize);
|
|
if (dwStatus == ERROR_SUCCESS) break; // and continue on
|
|
}
|
|
} while (dwPerfServiceListSize < 4194304);
|
|
}
|
|
|
|
// dump service entries for those services with perf counters
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
for (szThisServiceName = mszPerfServiceList;
|
|
*szThisServiceName != 0;
|
|
szThisServiceName += lstrlenW(szThisServiceName)+1) {
|
|
|
|
dwStatus = DumpPerfServiceEntries (
|
|
hOutFile,
|
|
szThisServiceName);
|
|
|
|
if (dwStatus != ERROR_SUCCESS) break;
|
|
}
|
|
}
|
|
|
|
// dump perf string entries
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
// build Name table
|
|
// get ENGLISH string list
|
|
lpCounterText = BuildNameTable (
|
|
HKEY_LOCAL_MACHINE, // use only local machine
|
|
(LPWSTR)szLangId,
|
|
&dwLastElement);
|
|
|
|
if (lpCounterText != NULL) {
|
|
dwStatus = DumpNameTable (
|
|
hOutFile,
|
|
szLangId,
|
|
lpCounterText,
|
|
0, // dump the entire table for complete restore
|
|
dwLastElement
|
|
);
|
|
} else {
|
|
dwStatus = GetLastError();
|
|
}
|
|
}
|
|
|
|
// free buffers
|
|
if (lpCounterText != NULL) {
|
|
HeapFree (GetProcessHeap(), 0, lpCounterText);
|
|
lpCounterText = NULL;
|
|
}
|
|
|
|
if (mszNoPerfServiceList != NULL) {
|
|
HeapFree (GetProcessHeap(), 0, mszNoPerfServiceList);
|
|
mszNoPerfServiceList = NULL;
|
|
}
|
|
|
|
if (mszPerfServiceList != NULL) {
|
|
HeapFree (GetProcessHeap(), 0, mszPerfServiceList);
|
|
mszPerfServiceList = NULL;
|
|
}
|
|
|
|
if (szNewFileName != NULL) {
|
|
HeapFree (GetProcessHeap(), 0, szNewFileName);
|
|
szNewFileName = NULL;
|
|
}
|
|
|
|
// close file handles
|
|
if (hOutFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (hOutFile);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
DWORD
|
|
RestorePerfRegistryFromFileW (
|
|
IN LPCWSTR szFileName,
|
|
IN LPCWSTR szLangId
|
|
)
|
|
{
|
|
LONG lStatus = ERROR_SUCCESS;
|
|
LONG lEnumStatus = ERROR_SUCCESS;
|
|
DWORD dwServiceIndex = 0;
|
|
WCHAR szServiceSubKeyName[MAX_PATH];
|
|
WCHAR szPerfSubKeyName[MAX_PATH+20];
|
|
DWORD dwNameSize = MAX_PATH;
|
|
HKEY hKeyPerformance;
|
|
HKEY hKeyServices = NULL;
|
|
HKEY hKeyPerflib = NULL;
|
|
DWORD dwItemSize;
|
|
DWORD dwRegAccessMask;
|
|
DWORD dwRetStatus = ERROR_SUCCESS;
|
|
UINT nValue;
|
|
DWORD dwnValue;
|
|
BOOL bServiceRegistryOk = TRUE;
|
|
|
|
WCHAR wPerfSection[MAX_PATH * 2];
|
|
|
|
LPWSTR szLocalLangId;
|
|
|
|
WinPerfStartTrace(NULL);
|
|
|
|
if (szLangId == NULL) {
|
|
szLocalLangId = (LPWSTR)L"009";
|
|
} else {
|
|
szLocalLangId = (LPWSTR)szLangId;
|
|
}
|
|
|
|
lStatus = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
|
|
cszServiceKeyName,
|
|
0L,
|
|
KEY_READ,
|
|
&hKeyServices);
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
// enum service list
|
|
while ((lEnumStatus = RegEnumKeyExW (
|
|
hKeyServices,
|
|
dwServiceIndex,
|
|
szServiceSubKeyName,
|
|
&dwNameSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL)) == ERROR_SUCCESS) {
|
|
|
|
//try to open the perfkey under this key.
|
|
lstrcpy (szPerfSubKeyName, szServiceSubKeyName);
|
|
lstrcat (szPerfSubKeyName, cszPerformance);
|
|
|
|
bServiceRegistryOk = TRUE;
|
|
dwRegAccessMask = KEY_READ | KEY_WRITE;
|
|
// look for a performance subkey
|
|
lStatus = RegOpenKeyExW (
|
|
hKeyServices,
|
|
szPerfSubKeyName,
|
|
0L,
|
|
dwRegAccessMask,
|
|
&hKeyPerformance);
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
// key found so service has perf data
|
|
// if performance subkey then
|
|
dwItemSize = swprintf (wPerfSection,
|
|
cszFmtServiceSectionName, szServiceSubKeyName);
|
|
// look into the file for a perf entry for this service
|
|
nValue = GetPrivateProfileIntW (
|
|
wPerfSection,
|
|
cszFirstCounter,
|
|
-1,
|
|
szFileName);
|
|
|
|
if (nValue != (UINT) -1) {
|
|
// if found in file then update registry with values from file
|
|
lStatus = RegSetValueExW (hKeyPerformance,
|
|
cszFirstCounter,
|
|
0L,
|
|
REG_DWORD,
|
|
(const BYTE *) & nValue,
|
|
sizeof(nValue));
|
|
dwnValue = nValue;
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_RESTOREPERFREGISTRYFROMFILEW,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceSubKeyName),
|
|
TRACE_WSTR(cszFirstCounter),
|
|
TRACE_DWORD(dwnValue),
|
|
NULL));
|
|
// now read the other values
|
|
} else {
|
|
// there's one or more missing entries so
|
|
// remove the whole entry
|
|
bServiceRegistryOk = FALSE;
|
|
}
|
|
|
|
// look into the file for a perf entry for this service
|
|
nValue = GetPrivateProfileIntW (
|
|
wPerfSection,
|
|
cszFirstHelp,
|
|
-1,
|
|
szFileName);
|
|
|
|
if (nValue != (UINT)-1) {
|
|
// if found in file then update registry with values from file
|
|
lStatus = RegSetValueExW (hKeyPerformance,
|
|
cszFirstHelp,
|
|
0L,
|
|
REG_DWORD,
|
|
(const BYTE *)&nValue,
|
|
sizeof(nValue));
|
|
dwnValue = nValue;
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_RESTOREPERFREGISTRYFROMFILEW,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceSubKeyName),
|
|
TRACE_WSTR(cszFirstHelp),
|
|
TRACE_DWORD(dwnValue),
|
|
NULL));
|
|
// now read the other values
|
|
} else {
|
|
// there's one or more missing entries so
|
|
// remove the whole entry
|
|
bServiceRegistryOk = FALSE;
|
|
}
|
|
|
|
// look into the file for a perf entry for this service
|
|
nValue = GetPrivateProfileIntW (
|
|
wPerfSection,
|
|
cszLastCounter,
|
|
-1,
|
|
szFileName);
|
|
|
|
if (nValue != (UINT)-1) {
|
|
// if found in file then update registry with values from file
|
|
lStatus = RegSetValueExW (hKeyPerformance,
|
|
cszLastCounter,
|
|
0L,
|
|
REG_DWORD,
|
|
(const BYTE *)&nValue,
|
|
sizeof(nValue));
|
|
dwnValue = nValue;
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_RESTOREPERFREGISTRYFROMFILEW,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceSubKeyName),
|
|
TRACE_WSTR(cszLastCounter),
|
|
TRACE_DWORD(dwnValue),
|
|
NULL));
|
|
// now read the other values
|
|
} else {
|
|
// there's one or more missing entries so
|
|
// remove the whole entry
|
|
bServiceRegistryOk = FALSE;
|
|
}
|
|
|
|
// look into the file for a perf entry for this service
|
|
nValue = GetPrivateProfileIntW (
|
|
wPerfSection,
|
|
cszLastHelp,
|
|
-1,
|
|
szFileName);
|
|
|
|
if (nValue != (UINT)-1) {
|
|
// if found in file then update registry with values from file
|
|
lStatus = RegSetValueExW (hKeyPerformance,
|
|
cszLastHelp,
|
|
0L,
|
|
REG_DWORD,
|
|
(const BYTE *)&nValue,
|
|
sizeof(nValue));
|
|
dwnValue = nValue;
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_RESTOREPERFREGISTRYFROMFILEW,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceSubKeyName),
|
|
TRACE_WSTR(cszLastHelp),
|
|
TRACE_DWORD(dwnValue),
|
|
NULL));
|
|
// now read the other values
|
|
} else {
|
|
// there's one or more missing entries so
|
|
// remove the whole entry
|
|
bServiceRegistryOk = FALSE;
|
|
}
|
|
|
|
if (!bServiceRegistryOk) {
|
|
// an error occurred so delete the first/last counter/help values
|
|
RegDeleteValue (hKeyPerformance, cszFirstCounter);
|
|
RegDeleteValue (hKeyPerformance, cszFirstHelp);
|
|
RegDeleteValue (hKeyPerformance, cszLastCounter);
|
|
RegDeleteValue (hKeyPerformance, cszLastHelp);
|
|
} // else continiue
|
|
|
|
RegCloseKey (hKeyPerformance);
|
|
} // else this service has no perf data so skip
|
|
else {
|
|
TRACE((WINPERF_DBG_TRACE_ERROR),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_RESTOREPERFREGISTRYFROMFILEW,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
lStatus,
|
|
TRACE_WSTR(szServiceSubKeyName),
|
|
NULL));
|
|
}
|
|
|
|
// reset for next loop
|
|
dwServiceIndex++;
|
|
dwNameSize = MAX_PATH;
|
|
} // end enum service list
|
|
}
|
|
else {
|
|
TRACE((WINPERF_DBG_TRACE_ERROR),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_RESTOREPERFREGISTRYFROMFILEW,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
lStatus,
|
|
TRACE_WSTR(cszServiceKeyName),
|
|
NULL));
|
|
}
|
|
|
|
if (hKeyServices != NULL) RegCloseKey (hKeyServices);
|
|
|
|
if (dwRetStatus == ERROR_SUCCESS) {
|
|
// merge registry string values:
|
|
dwRetStatus = UpdatePerfNameFilesX (
|
|
szFileName, NULL,
|
|
szLocalLangId,
|
|
LODCTR_UPNF_RESTORE);
|
|
|
|
if (dwRetStatus == ERROR_SUCCESS) {
|
|
// update the keys in the registry
|
|
|
|
lStatus = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
|
|
cszPerflibKeyName,
|
|
0L,
|
|
KEY_ALL_ACCESS,
|
|
&hKeyPerflib);
|
|
if (lStatus != ERROR_SUCCESS) {
|
|
TRACE((WINPERF_DBG_TRACE_ERROR),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_RESTOREPERFREGISTRYFROMFILEW,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
lStatus,
|
|
TRACE_WSTR(cszPerflibKeyName),
|
|
NULL));
|
|
}
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
nValue = GetPrivateProfileIntW (
|
|
cszPerflib,
|
|
cszLastCounter,
|
|
-1,
|
|
szFileName);
|
|
|
|
if (nValue != (UINT)-1) {
|
|
// if found in file then update registry with values from file
|
|
lStatus = RegSetValueExW (hKeyPerflib,
|
|
cszLastCounter,
|
|
0L,
|
|
REG_DWORD,
|
|
(const BYTE *)&nValue,
|
|
sizeof(nValue));
|
|
dwnValue = nValue;
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_RESTOREPERFREGISTRYFROMFILEW,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
lStatus,
|
|
TRACE_WSTR(cszLastCounter),
|
|
TRACE_DWORD(dwnValue),
|
|
NULL));
|
|
}
|
|
}
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
// look into the file for a perf entry for this service
|
|
nValue = GetPrivateProfileIntW (
|
|
cszPerflib,
|
|
cszLastHelp,
|
|
-1,
|
|
szFileName);
|
|
|
|
if (nValue != (UINT)-1) {
|
|
// if found in file then update registry with values from file
|
|
lStatus = RegSetValueExW (hKeyPerflib,
|
|
cszLastHelp,
|
|
0L,
|
|
REG_DWORD,
|
|
(const BYTE *)&nValue,
|
|
sizeof(nValue));
|
|
dwnValue = nValue;
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_RESTOREPERFREGISTRYFROMFILEW,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
lStatus,
|
|
TRACE_WSTR(cszLastHelp),
|
|
TRACE_DWORD(dwnValue),
|
|
NULL));
|
|
}
|
|
}
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
// look into the file for a perf entry for this service
|
|
nValue = GetPrivateProfileIntW (
|
|
cszPerflib,
|
|
cszBaseIndex,
|
|
-1,
|
|
szFileName);
|
|
|
|
if (nValue != (UINT)-1) {
|
|
// if found in file then update registry with values from file
|
|
lStatus = RegSetValueExW (hKeyPerflib,
|
|
cszBaseIndex,
|
|
0L,
|
|
REG_DWORD,
|
|
(const BYTE *)&nValue,
|
|
sizeof(nValue));
|
|
dwnValue = nValue;
|
|
TRACE((WINPERF_DBG_TRACE_INFO),
|
|
(& LoadPerfGuid,
|
|
__LINE__,
|
|
LOADPERF_RESTOREPERFREGISTRYFROMFILEW,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
lStatus,
|
|
TRACE_WSTR(cszBaseIndex),
|
|
TRACE_DWORD(dwnValue),
|
|
NULL));
|
|
}
|
|
}
|
|
|
|
if (hKeyPerflib != NULL) RegCloseKey (hKeyPerflib);
|
|
}
|
|
dwRetStatus = lStatus;
|
|
}
|
|
|
|
return dwRetStatus;
|
|
}
|