PDH_FUNCTION PdhExpandCounterPathA ( IN LPCSTR szWildCardPath, IN LPSTR mszExpandedPathList, IN LPDWORD pcchPathListLength ) { LPWSTR szWideWildCardPath = NULL; DWORD dwSize; PDH_STATUS pdhStatus; __try { dwSize = lstrlenA (szWildCardPath); szWideWildCardPath = G_ALLOC (GPTR, ((dwSize+1) * sizeof (WCHAR))); if (szWideWildCardPath == NULL) { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } else { mbstowcs (szWideWildCardPath, szWildCardPath, (dwSize+1)); pdhStatus = PdhiExpandCounterPath ( szWideWildCardPath, (LPVOID)mszExpandedPathList, pcchPathListLength, FALSE); } } __except (EXCEPTION_EXECUTE_HANDLER) { pdhStatus = PDH_INVALID_ARGUMENT; } if (szWideWildCardPath != NULL) G_FREE (szWideWildCardPath); return pdhStatus; }
static PDH_STATUS PdhiExpandCounterPath ( IN LPCWSTR szWildCardPath, IN LPVOID pExpandedPathList, IN LPDWORD pcchPathListLength, IN BOOL bUnicode ) { PPERF_MACHINE pMachine; PPDHI_COUNTER_PATH pWildCounterPath = NULL; WCHAR szWorkBuffer[MAX_PATH]; WCHAR szCounterName[MAX_PATH]; WCHAR szInstanceName[MAX_PATH]; LPWSTR szEndOfObjectString; LPWSTR szInstanceString; LPWSTR szCounterString; LPVOID szNextUserString; PERF_OBJECT_TYPE *pObjectDef; PERF_OBJECT_TYPE *pParentObjectDef; PERF_COUNTER_DEFINITION *pCounterDef; PERF_INSTANCE_DEFINITION *pInstanceDef; PERF_INSTANCE_DEFINITION *pParentInstanceDef; DWORD dwBufferRemaining; DWORD dwSize; DWORD dwSizeReturned = 0; PDH_STATUS pdhStatus = ERROR_SUCCESS; DWORD dwCtrNdx, dwInstNdx; BOOL bMoreData = FALSE; // allocate buffers pWildCounterPath = G_ALLOC (GPTR, PDHI_COUNTER_PATH_BUFFER_SIZE); if (pWildCounterPath == NULL) { // unable to allocate memory so bail out pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } else { __try { dwBufferRemaining = *pcchPathListLength; szNextUserString = pExpandedPathList; } __except (EXCEPTION_EXECUTE_HANDLER) { pdhStatus = PDH_INVALID_ARGUMENT; } } if (pdhStatus == ERROR_SUCCESS) { // Parse wild card Path dwSize = G_SIZE (pWildCounterPath); if (ParseFullPathNameW (szWildCardPath, &dwSize, pWildCounterPath)) { // get the machine referenced in the path pMachine = GetMachine (pWildCounterPath->szMachineName, 0); if (pMachine != NULL) { if (wcsncmp (cszDoubleBackSlash, szWildCardPath, 2) == 0) { // the caller wants the machine name in the path so // copy it to the work buffer lstrcpyW (szWorkBuffer, pWildCounterPath->szMachineName); } else { *szWorkBuffer = 0; } // append the object name (since wild card objects are not // currently supported. lstrcatW (szWorkBuffer, cszBackSlash); lstrcatW (szWorkBuffer, pWildCounterPath->szObjectName); szEndOfObjectString = &szWorkBuffer[lstrlenW(szWorkBuffer)]; // get object pointer (since objects are not wild) pObjectDef = GetObjectDefByName ( pMachine->pSystemPerfData, pMachine->dwLastPerfString, pMachine->szPerfStrings, pWildCounterPath->szObjectName); if (pObjectDef != NULL) { // for each counters and identify matches pCounterDef = FirstCounter (pObjectDef); for (dwCtrNdx = 0; dwCtrNdx < pObjectDef->NumCounters; dwCtrNdx++) { // for each counter check instances (if supported) // and keep matches if ((pCounterDef->CounterNameTitleIndex > 0) && (pCounterDef->CounterNameTitleIndex < pMachine->dwLastPerfString ) && (!((pCounterDef->CounterType & PERF_DISPLAY_NOSHOW) && // this is a hack because this type is not defined correctly (pCounterDef->CounterType != PERF_AVERAGE_BULK)))) { // look up name of each object & store size lstrcpyW (szCounterName, pMachine->szPerfStrings[pCounterDef->CounterNameTitleIndex]); if (WildStringMatchW(pWildCounterPath->szCounterName, szCounterName)) { // if this object has instances, then walk down // the instance list and save any matches if (pObjectDef->NumInstances != PERF_NO_INSTANCES) { // then walk instances to find matches pInstanceDef = FirstInstance (pObjectDef); if (pObjectDef->NumInstances > 0) { for (dwInstNdx = 0; dwInstNdx < (DWORD)pObjectDef->NumInstances; dwInstNdx++) { szInstanceString = szEndOfObjectString; if (pInstanceDef->ParentObjectTitleIndex > 0) { // then add in parent instance name pParentObjectDef = GetObjectDefByTitleIndex ( pMachine->pSystemPerfData, pInstanceDef->ParentObjectTitleIndex); if (pParentObjectDef != NULL) { pParentInstanceDef = GetInstance ( pParentObjectDef, pInstanceDef->ParentObjectInstance); if (pParentInstanceDef != NULL) { GetInstanceNameStr (pParentInstanceDef, szInstanceName, pObjectDef->CodePage); if (WildStringMatchW (pWildCounterPath->szParentName, szInstanceName)) { // add this string szInstanceString = szEndOfObjectString; lstrcpyW (szInstanceString, cszLeftParen); lstrcatW (szInstanceString, szInstanceName); lstrcatW (szInstanceString, cszSlash); } else { // get next instance and continue pInstanceDef = NextInstance(pInstanceDef); continue; } } else { // unable to locate parent instance // so cancel this one, then // get next instance and continue pInstanceDef = NextInstance(pInstanceDef); continue; } } else { // unable to locate parent object // so cancel this one, then // get next instance and continue pInstanceDef = NextInstance(pInstanceDef); continue; } } else { // no parent name so continue szInstanceString = szEndOfObjectString; lstrcpyW (szInstanceString, cszSlash); } GetInstanceNameStr (pInstanceDef, szInstanceName, pObjectDef->CodePage); // // BUGBUG: need to do something with indexes. // // if this instance name matches, then keep it if (WildStringMatchW (pWildCounterPath->szInstanceName, szInstanceName)) { lstrcatW (szInstanceString, szInstanceName); lstrcatW (szInstanceString, cszRightParenBackSlash); // now append this counter name lstrcatW (szInstanceString, szCounterName); // add it to the user's buffer if there's room dwSize = lstrlenW(szWorkBuffer) + 1; if (!bMoreData && (dwSize < dwBufferRemaining)) { if (bUnicode) { lstrcpyW ((LPWSTR)szNextUserString, szWorkBuffer); (LPBYTE)szNextUserString += dwSize * sizeof(WCHAR); } else { wcstombs ((LPSTR)szNextUserString, szWorkBuffer, dwSize); (LPBYTE)szNextUserString += dwSize * sizeof(CHAR); } dwSizeReturned += dwSize; dwBufferRemaining -= dwSize; } else { // they've run out of buffer so just update the size required bMoreData = TRUE; dwSizeReturned += dwSize; } } else { // they don't want this instance so skip it } pInstanceDef = NextInstance (pInstanceDef); } // end for each instance in object } else { // this object supports instances, // but doesn't currently have any // so do nothing. } } else { // this object does not use instances so copy this // counter to the caller's buffer. szCounterString = szEndOfObjectString; lstrcpyW (szCounterString, cszBackSlash); lstrcatW (szCounterString, szCounterName); dwSize = lstrlenW(szWorkBuffer) + 1; if (!bMoreData && (dwSize < dwBufferRemaining)) { if (bUnicode) { lstrcpyW ((LPWSTR)szNextUserString, szWorkBuffer); (LPBYTE)szNextUserString += dwSize * sizeof(WCHAR); } else { wcstombs ((LPSTR)szNextUserString, szWorkBuffer, dwSize); (LPBYTE)szNextUserString += dwSize * sizeof(CHAR); } dwSizeReturned += dwSize; dwBufferRemaining -= dwSize; } else { // they've run out of buffer so bail out of this loop bMoreData = TRUE; dwSizeReturned += dwSize; } } } else { // this counter doesn't match so skip it } } else { // this counter string is not available } pCounterDef = NextCounter(pCounterDef); } // end for each counter in this object if (bUnicode) { *(LPWSTR)szNextUserString = 0; // MSZ terminator } else { *(LPSTR)szNextUserString = 0; // MSZ terminator } *pcchPathListLength = dwSizeReturned; if (bMoreData) { pdhStatus = PDH_MORE_DATA; } else { pdhStatus = ERROR_SUCCESS; } } else { // unable to find object pdhStatus = PDH_INVALID_PATH; } } else { // unable to connect to machine. pdhStatus = PDH_CANNOT_CONNECT_MACHINE; } } else { // unable to read input path string pdhStatus = PDH_INVALID_PATH; } } if (pWildCounterPath != NULL) G_FREE (pWildCounterPath); return pdhStatus; }
PDH_FUNCTION WriteTextLogHeader ( IN PLOG_INFO pLog ) { LONG pdhStatus = ERROR_SUCCESS; PLOG_COUNTER_INFO pThisCounter; CHAR cDelim; CHAR szLeadDelim[4]; DWORD dwLeadSize; CHAR szTrailDelim[4]; DWORD dwTrailSize; DWORD dwBytesWritten; PPDH_COUNTER_INFO_A pCtrInfo; DWORD dwCtrInfoSize; BOOL bResult; pCtrInfo = G_ALLOC (8192); if (pCtrInfo == NULL) { return PDH_MEMORY_ALLOCATION_FAILURE; } cDelim = (LOWORD(pLog->dwLogFormat) == OPD_CSV_FILE) ? COMMA_DELIMITER : TAB_DELIMITER; szLeadDelim[0] = cDelim; szLeadDelim[1] = DOUBLE_QUOTE; szLeadDelim[2] = 0; szLeadDelim[3] = 0; dwLeadSize = 2; szTrailDelim[0] = DOUBLE_QUOTE; szTrailDelim[1] = 0; szTrailDelim[2] = 0; szTrailDelim[3] = 0; dwTrailSize = 1; // write the logfile header record bResult = WriteFile (pLog->hLogFileHandle, (LPCVOID)&szTrailDelim[0], 1, &dwBytesWritten, NULL); if (!bResult) { pdhStatus = GetLastError(); } if (pdhStatus == ERROR_SUCCESS) { // write the time stamp title bResult = WriteFile (pLog->hLogFileHandle, (LPCVOID)szTimeStampLabel, dwTimeStampLabelLength, &dwBytesWritten, NULL); if (!bResult) { pdhStatus = GetLastError(); } } if (pdhStatus == ERROR_SUCCESS) { // check each counter in the list of counters for this query and // write them to the file // output the path names pThisCounter = pFirstCounter; if (pThisCounter != NULL) { do { // write the leading delimiter bResult = WriteFile (pLog->hLogFileHandle, (LPCVOID)szLeadDelim, dwLeadSize, &dwBytesWritten, NULL); if (!bResult) { pdhStatus = GetLastError(); break; // out of the Do Loop } // get the counter path information from the counter dwCtrInfoSize = 8192; pdhStatus = PdhGetCounterInfoA ( pThisCounter->hCounter, FALSE, &dwCtrInfoSize, pCtrInfo); if (pdhStatus == ERROR_SUCCESS) { // write the counter name bResult = WriteFile (pLog->hLogFileHandle, (LPCVOID)pCtrInfo->szFullPath, lstrlen(pCtrInfo->szFullPath), &dwBytesWritten, NULL); if (!bResult) { pdhStatus = GetLastError(); break; // out of the Do Loop } } else { // unable to get counter information so bail here break; } // write the trailing delimiter bResult = WriteFile (pLog->hLogFileHandle, (LPCVOID)szTrailDelim, dwTrailSize, &dwBytesWritten, NULL); if (!bResult) { pdhStatus = GetLastError(); break; // out of the Do Loop } pThisCounter = pThisCounter->next; } while (pThisCounter != NULL); } } if (pdhStatus == ERROR_SUCCESS) { // write the record terminator bResult = WriteFile (pLog->hLogFileHandle, (LPCVOID)szRecordTerminator, dwRecordTerminatorLength, &dwBytesWritten, NULL); if (!bResult) { pdhStatus = GetLastError(); } } G_FREE (pCtrInfo); return pdhStatus; }
static DWORD AddUniqueStringToMultiSz ( IN LPVOID mszDest, IN LPSTR szSource, IN BOOL bUnicodeDest ) /*++ Routine Description: searches the Multi-SZ list, mszDest for szSource and appends it to mszDest if it wasn't found Arguments: OUT LPVOID mszDest Multi-SZ list to get new string IN LPSTR szSource string to add if it's not already in list ReturnValue: The new length of the destination string including both trailing NULL characters if the string was added, or 0 if the string is already in the list. --*/ { LPVOID szDestElem; DWORD dwReturnLength; LPWSTR wszSource = NULL; DWORD dwLength; // check arguments if ((mszDest == NULL) || (szSource == NULL)) return 0; // invalid buffers if (*szSource == '\0') return 0; // no source string to add // if unicode list, make a unicode copy of the string to compare // and ultimately copy if it's not already in the list if (bUnicodeDest) { dwLength = lstrlenA(szSource) + 1; wszSource = G_ALLOC (dwLength * sizeof(WCHAR)); if (wszSource != NULL) { dwReturnLength = mbstowcs (wszSource, szSource, dwLength); } else { // unable to allocate memory for the temp string dwReturnLength = 0; } } else { // just use the ANSI version of the source file name dwReturnLength = 1; } if (dwReturnLength > 0) { // go to end of dest string // for (szDestElem = mszDest; (bUnicodeDest ? (*(LPWSTR)szDestElem != 0) : (*(LPSTR)szDestElem != 0)); ) { if (bUnicodeDest) { // bail out if string already in lsit if (lstrcmpiW((LPCWSTR)szDestElem, wszSource) == 0) { return 0; } else { // goto the next item szDestElem = (LPVOID)((LPWSTR)szDestElem + (lstrlenW((LPCWSTR)szDestElem)+1)); } } else { // bail out if string already in lsit if (lstrcmpiA((LPSTR)szDestElem, szSource) == 0) { return 0; } else { // goto the next item szDestElem = (LPVOID)((LPSTR)szDestElem + (lstrlenA((LPCSTR)szDestElem)+1)); } } } // if here, then add string // szDestElem is at end of list if (bUnicodeDest) { lstrcpyW ((LPWSTR)szDestElem, wszSource); szDestElem = (LPVOID)((LPWSTR)szDestElem + lstrlenW(wszSource) + 1); *((LPWSTR)szDestElem)++ = L'\0'; dwReturnLength = (DWORD)((LPWSTR)szDestElem - (LPWSTR)mszDest); } else { lstrcpyA ((LPSTR)szDestElem, szSource); szDestElem = (LPVOID)((LPSTR)szDestElem + lstrlenA(szDestElem) + 1); *((LPSTR)szDestElem)++ = '\0'; // add second NULL dwReturnLength = (DWORD)((LPSTR)szDestElem - (LPSTR)mszDest); } } return dwReturnLength; }
BOOL LoggingProc ( IN LPLOG_THREAD_DATA pArg ) { HQUERY hQuery; HCOUNTER hThisCounter; DWORD dwDelay; DWORD dwSampleInterval, dwSampleTime; PDH_STATUS pdhStatus; DWORD dwNumCounters; LONG lStatus; TCHAR szDefaultDir[MAX_PATH]; TCHAR szBaseName[MAX_PATH]; LPTSTR szThisPath; DWORD dwLogType = OPD_CSV_FILE; BOOL bRun = FALSE; DWORD dwSamplesUntilNewFile; TCHAR szCurrentLogFile[MAX_PATH]; LONG lWaitStatus; LPTSTR szStringArray[4]; DWORD dwFileSizeLimit; LONGLONG llFileSizeLimit; LONGLONG llFileSize; PLOG_COUNTER_INFO pCtrInfo; // read registry values if (!LoadDataFromRegistry (pArg, szDefaultDir, szBaseName, szCurrentLogFile)) { // unable to initialize the query from the registry return FALSE; } // convert to milliseconds for use in timeouts dwSampleInterval = pArg->dwTimeInterval * 1000L; // open query and add counters from info file pdhStatus = PdhOpenQuery (NULL, 0, &hQuery); // from current activity if (pdhStatus == ERROR_SUCCESS) { dwNumCounters = 0; for (szThisPath = pArg->mszCounterList; *szThisPath != 0; szThisPath += lstrlen(szThisPath) + 1) { pdhStatus = PdhAddCounter (hQuery, (LPTSTR)szThisPath, dwNumCounters++, &hThisCounter); if (pdhStatus == ERROR_SUCCESS) { // then add this handle to the list pCtrInfo = G_ALLOC (sizeof (LOG_COUNTER_INFO)); if (pCtrInfo != NULL) { // insert at front of list since the order isn't // important and this is simpler than walking the // list each time. pCtrInfo->hCounter = hThisCounter; pCtrInfo->next = pFirstCounter; pFirstCounter = pCtrInfo; } } } // to make sure we get to log the data SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST); bRun = TRUE; while (bRun) { // Get the current Log filename if (pArg->dwRenameIntervalCount != 0) { // then this is an autonamed file // so make current name BuildCurrentLogFileName ( szBaseName, szDefaultDir, szCurrentLogFile, &pArg->dwCurrentSerialNumber, pArg->dwAutoNameFormat, pArg->dwLogType); // reset loop counter switch (pArg->dwRenameIntervalUnits) { case OPD_RENAME_KBYTES: dwFileSizeLimit = pArg->dwRenameIntervalCount * 1024; dwSamplesUntilNewFile = 0; break; case OPD_RENAME_MBYTES: dwFileSizeLimit = pArg->dwRenameIntervalCount * 1024 * 1024; dwSamplesUntilNewFile = 0; break; case OPD_RENAME_HOURS: case OPD_RENAME_DAYS: case OPD_RENAME_MONTHS: default: dwSamplesUntilNewFile = GetSamplesInRenameInterval( pArg->dwTimeInterval, pArg->dwRenameIntervalCount, pArg->dwRenameIntervalUnits); dwFileSizeLimit = 0; break; } } else { // filename is left as read from the registry dwSamplesUntilNewFile = 0; dwFileSizeLimit = 0; } llFileSizeLimit = dwFileSizeLimit; // open log file using this query dwLogType = pArg->dwLogType; pdhStatus = OpenLogW ( szCurrentLogFile, LOG_WRITE_ACCESS | LOG_CREATE_ALWAYS, &dwLogType, hQuery, 0); if (pdhStatus == ERROR_SUCCESS) { szStringArray[0] = pArg->szQueryName; szStringArray[1] = szCurrentLogFile; ReportEvent (hEventLog, EVENTLOG_INFORMATION_TYPE, 0, PERFLOG_LOGGING_QUERY, NULL, 2, 0, szStringArray, NULL); // start sampling immediately dwDelay = 0; while ((lWaitStatus = WaitForSingleObject (pArg->hExitEvent, dwDelay)) == WAIT_TIMEOUT) { // the event flag will be set when the sampling should exit. if // the wait times out, then that means it's time to collect and // log another sample of data. // the argument received the time it took to take the // sample so the delay can be adjusted accordingly dwSampleTime = 0; pdhStatus = UpdateLog (&dwSampleTime); if (pdhStatus == ERROR_SUCCESS) { // see if it's time to rename the file if (dwSamplesUntilNewFile) { if (!--dwSamplesUntilNewFile) break; } else if (llFileSizeLimit) { // see if the file is too big pdhStatus = GetLogFileSize (&llFileSize); if (pdhStatus == ERROR_SUCCESS) { if (llFileSizeLimit <= llFileSize) break; } } // compute new timeout value if (dwSampleTime < dwSampleInterval) { dwDelay = dwSampleInterval - dwSampleTime; } else { dwDelay = 0; } } else { // unable to update the log so log event and exit ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, 0, PERFLOG_UNABLE_UPDATE_LOG, NULL, 0, sizeof(DWORD), NULL, (LPVOID)&pdhStatus); bRun = FALSE; break; } } // end while wait keeps timing out if (lWaitStatus == WAIT_OBJECT_0) { // then the loop was terminated by the Exit event // so clear the "run" flag to exit the loop & thread bRun = FALSE; } CloseLog (0); } else { // unable to open log file so log event log message bRun = FALSE; // exit now } } // end while (bRun) PdhCloseQuery (hQuery); // update log serial number if necssary if (pArg->dwAutoNameFormat == OPD_NAME_NNNNNN) { lStatus = RegSetValueEx ( pArg->hKeyQuery, TEXT("Log File Serial Number"), 0L, REG_DWORD, (LPBYTE)&pArg->dwCurrentSerialNumber, sizeof(DWORD)); } } else { // unable to open query so write event log message } return bRun; }
BOOL LoadDataFromRegistry ( IN LPLOG_THREAD_DATA pArg, IN LPTSTR szDefaultDir, IN LPTSTR szBaseName, IN LPTSTR szCurrentLogFile ) { LONG lStatus; DWORD dwType; DWORD dwSize; DWORD dwData; LPTSTR szStringArray[2]; // get size of buffer required by counter list, // then allocate the buffer and retrieve the counter list dwType = 0; dwData = 0; dwSize = 0; lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Counter List"), NULL, &dwType, (LPBYTE)NULL, &dwSize); pArg->mszCounterList = (LPTSTR)G_ALLOC(dwSize); if (pArg->mszCounterList != NULL) { dwType = 0; lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Counter List"), NULL, &dwType, (LPBYTE)pArg->mszCounterList, &dwSize); if ((lStatus != ERROR_SUCCESS) || (dwSize == 0)) { // no counter list retrieved so there's not much // point in continuing szStringArray[0] = pArg->szQueryName; ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, 0, PERFLOG_UNABLE_READ_COUNTER_LIST, NULL, 1, sizeof(DWORD), szStringArray, (LPVOID)&lStatus); return FALSE; } } else { szStringArray[0] = pArg->szQueryName; ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, 0, PERFLOG_UNABLE_ALLOC_COUNTER_LIST, NULL, 1, sizeof(DWORD), szStringArray, (LPVOID)&lStatus); return FALSE; } dwType = 0; dwData = 0; dwSize = sizeof(DWORD); lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Auto Name Interval"), NULL, &dwType, (LPBYTE)&dwData, &dwSize); if (lStatus != ERROR_SUCCESS) { dwData = 0; // default is no autonaming } else if (dwType != REG_DWORD) { dwData = 0; // default is no autonaming } // else assume success pArg->dwRenameIntervalCount = dwData; dwType = 0; dwData = 0; dwSize = sizeof(DWORD); lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Auto Rename Units"), NULL, &dwType, (LPBYTE)&dwData, &dwSize); if (lStatus != ERROR_SUCCESS) { dwData = OPD_RENAME_DAYS; // default is days } else if (dwType != REG_DWORD) { dwData = OPD_RENAME_DAYS; // default is days } // else assume success pArg->dwRenameIntervalUnits = dwData; dwType = 0; dwData = 0; dwSize = sizeof(DWORD); lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Log File Auto Format"), NULL, &dwType, (LPBYTE)&dwData, &dwSize); if (lStatus != ERROR_SUCCESS) { dwData = OPD_NAME_NNNNNN; // default is a serial number } else if (dwType != REG_DWORD) { dwData = OPD_NAME_NNNNNN; // default is a serial number } // else assume success pArg->dwAutoNameFormat = dwData; dwType = 0; dwData = 0; dwSize = sizeof(DWORD); lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Log File Type"), NULL, &dwType, (LPBYTE)&dwData, &dwSize); if (lStatus != ERROR_SUCCESS) { dwData = OPD_CSV_FILE; // default is a CSV file } else if (dwType != REG_DWORD) { dwData = OPD_CSV_FILE; // default is a CSV file } // else assume success pArg->dwLogType = dwData; dwType = 0; dwData = 0; dwSize = sizeof(DWORD); lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Sample Interval"), NULL, &dwType, (LPBYTE)&dwData, &dwSize); if (lStatus != ERROR_SUCCESS) { dwData = SECONDS_IN_MINUTE; // default is 1 Minute samples } else if (dwType != REG_DWORD) { dwData = SECONDS_IN_MINUTE; // default is 1 Minute samples } // else assume success pArg->dwTimeInterval = dwData; // get filename or components if auto name if (pArg->dwRenameIntervalCount > 0) { // this is an autoname file so get components dwType = 0; *szDefaultDir = 0; dwSize = MAX_PATH * sizeof(TCHAR); lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Log Default Directory"), NULL, &dwType, (LPBYTE)&szDefaultDir[0], &dwSize); if (lStatus != ERROR_SUCCESS) { *szDefaultDir = 0; } // else assume success dwType = 0; *szBaseName = 0; dwSize = MAX_PATH * sizeof(TCHAR); lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Base Filename"), NULL, &dwType, (LPBYTE)&szBaseName[0], &dwSize); if (lStatus != ERROR_SUCCESS) { // apply default lstrcpy (szBaseName, TEXT("perfdata")); } // else assume success } else { // this is a manual name file so read name dwType = 0; *szCurrentLogFile = 0; dwSize = MAX_PATH * sizeof(TCHAR); lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Log Filename"), NULL, &dwType, (LPBYTE)&szCurrentLogFile[0], &dwSize); if (lStatus != ERROR_SUCCESS) { // apply default lstrcpy (szCurrentLogFile, TEXT("c:\\perfdata.log")); } // else assume success } dwType = 0; dwData = 0; dwSize = sizeof(DWORD); lStatus = RegQueryValueEx ( pArg->hKeyQuery, TEXT("Log File Serial Number"), NULL, &dwType, (LPBYTE)&dwData, &dwSize); if (lStatus != ERROR_SUCCESS) { dwData = 1; // default is to start at 1 } else if (dwType != REG_DWORD) { dwData = 1; // default is to start at 1 } // else assume success pArg->dwCurrentSerialNumber = dwData; return TRUE; }
void PerfDataLogServiceStart ( IN DWORD argc, IN LPTSTR *argv ) { LONG lStatus; HKEY hKeyLogQueries; HKEY hKeyThisLogQuery; DWORD dwQueryIndex; TCHAR szQueryNameBuffer[MAX_PATH]; DWORD dwQueryNameBufferSize; TCHAR szQueryClassBuffer[MAX_PATH]; DWORD dwQueryClassBufferSize; LPLOG_THREAD_DATA lpThreadData; HANDLE hThread; LPTSTR szStringArray[2]; DWORD dwThreadId; ssPerfLogStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ssPerfLogStatus.dwCurrentState = SERVICE_START_PENDING; ssPerfLogStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | // SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN; ssPerfLogStatus.dwWin32ExitCode = 0; ssPerfLogStatus.dwServiceSpecificExitCode = 0; ssPerfLogStatus.dwCheckPoint = 0; ssPerfLogStatus.dwWaitHint = 0; hPerfLogStatus = RegisterServiceCtrlHandler ( TEXT("PerfDataLog"), PerfDataLogServiceControlHandler); if (hPerfLogStatus == (SERVICE_STATUS_HANDLE)0) { lStatus = GetLastError(); ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, 0, PERFLOG_UNABLE_REGISTER_HANDLER, NULL, 0, sizeof(DWORD), NULL, (LPVOID)&lStatus); // this is fatal so bail out return; } // registered the service successfully, so load the log queries // assign the handle buffer pThreadHandleArray = &LocalThreadArray[0]; dwMaxHandleCount = LOCAL_HANDLE_COUNT; // open (each) query lStatus = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\PerfDataLog\\Log Queries"), 0L, KEY_READ, &hKeyLogQueries); if (lStatus != ERROR_SUCCESS) { // unable to read the log query information from the registry lStatus = GetLastError(); ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, 0, PERFLOG_UNABLE_OPEN_LOG_QUERY, NULL, 0, sizeof(DWORD), NULL, (LPVOID)&lStatus); // we can't start the service with out the evnt log. ssPerfLogStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus); return; } // enumerate and start the queries in the registry dwQueryIndex = 0; *szQueryNameBuffer = 0; dwQueryNameBufferSize = MAX_PATH; *szQueryClassBuffer; dwQueryClassBufferSize = MAX_PATH; while ((lStatus = RegEnumKeyEx ( hKeyLogQueries, dwQueryIndex, szQueryNameBuffer, &dwQueryNameBufferSize, NULL, szQueryClassBuffer, &dwQueryClassBufferSize, NULL)) != ERROR_NO_MORE_ITEMS) { // open this key lStatus = RegOpenKeyEx ( hKeyLogQueries, szQueryNameBuffer, 0L, KEY_READ | KEY_WRITE, &hKeyThisLogQuery); if (lStatus != ERROR_SUCCESS) { szStringArray[0] = szQueryNameBuffer; ReportEvent (hEventLog, EVENTLOG_WARNING_TYPE, 0, PERFLOG_UNABLE_READ_LOG_QUERY, NULL, 1, sizeof(DWORD), szStringArray, (LPVOID)&lStatus); // skip to next item goto CONTINUE_ENUM_LOOP; } // update the service status ssPerfLogStatus.dwCheckPoint++; SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus); // allocate a thread info block. lpThreadData = G_ALLOC (sizeof(LOG_THREAD_DATA)); if (lpThreadData == NULL) { lStatus = GetLastError(); szStringArray[0] = szQueryNameBuffer; ReportEvent (hEventLog, EVENTLOG_WARNING_TYPE, 0, PERFLOG_UNABLE_ALLOCATE_DATABLOCK, NULL, 1, sizeof(DWORD), szStringArray, (LPVOID)&lStatus); goto CONTINUE_ENUM_LOOP; } // initialize the thread data block lpThreadData->hKeyQuery = hKeyThisLogQuery; lpThreadData->hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); lpThreadData->bReloadNewConfig = FALSE; lstrcpy (lpThreadData->szQueryName, szQueryNameBuffer); // start logging thread hThread = CreateThread ( NULL, 0, LoggingThreadProc, (LPVOID)lpThreadData, 0, &dwThreadId); if (hThread != NULL) { // add it to the list and continue if (pFirstThread == NULL) { // then this is the first thread so add it lpThreadData->next = NULL; pFirstThread = lpThreadData; } else { // insert this at the head of the list since // that's the easiest and the order isn't // really important lpThreadData->next = pFirstThread; pFirstThread = lpThreadData; } // add thread to array for termination wait if (dwHandleCount < dwMaxHandleCount) { pThreadHandleArray[dwHandleCount++] = hThread; } else { // realloc buffer and try again // this will be added when multi-query // support is added. for now we'll ignore // ones that don't fit. } lpThreadData = NULL; //clear for next lap } else { // unable to start thread lStatus = GetLastError(); szStringArray[0] = szQueryNameBuffer; ReportEvent (hEventLog, EVENTLOG_WARNING_TYPE, 0, PERFLOG_UNABLE_START_THREAD, NULL, 1, sizeof(DWORD), szStringArray, (LPVOID)&lStatus); } CONTINUE_ENUM_LOOP: // prepare for next loop dwQueryIndex++; // for now we just do the first item in the list // the full multiple log query feature will be // added later. if (dwQueryIndex > 0) break; // otherwise we would continue here *szQueryNameBuffer = 0; dwQueryNameBufferSize = MAX_PATH; *szQueryClassBuffer; dwQueryClassBufferSize = MAX_PATH; } // end enumeration of log queries // service is now started ssPerfLogStatus.dwCurrentState = SERVICE_RUNNING; ssPerfLogStatus.dwCheckPoint++; SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus); // wait for (all) timing and logging threads to complete lStatus = WaitForMultipleObjects (dwHandleCount, pThreadHandleArray, TRUE, INFINITE); ssPerfLogStatus.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus); // when here, all logging threads have terminated so the // memory can be released and the service can exit and shutdown. for (dwQueryIndex = 0; dwQueryIndex < dwHandleCount; dwQueryIndex++) { CloseHandle (pThreadHandleArray[dwQueryIndex]); } // release the dynamic memory FreeThreadData (pFirstThread); // and update the service status ssPerfLogStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus); if (hEventLog != NULL) CloseHandle (hEventLog); return; }
// // FUNCTION: WndProc(HWND, unsigned, WORD, LONG) // // PURPOSE: Processes messages for the main window. // // MESSAGES: // // WM_COMMAND - process the application menu // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return // WM_DISPLAYCHANGE - message sent to Plug & Play systems when the display changes // WM_RBUTTONDOWN - Right mouse click -- put up context menu here if appropriate // WM_NCRBUTTONUP - User has clicked the right button on the application's system menu // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; POINT pnt; HMENU hMenu; BOOL bGotHelp; switch (message) { case WM_CREATE: // clear timer flags TimerID = 0; TimerRunning = FALSE; // enable "Start" menu selection hAppMenu = GetMenu (hWnd); hTestMenu = GetSubMenu (hAppMenu, 1); EnableMenuItem (hTestMenu, IDM_STOP, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem (hTestMenu, IDM_START, MF_BYCOMMAND | MF_ENABLED); break; case WM_COMMAND: wmId = LOWORD(wParam); // Remember, these are... wmEvent = HIWORD(wParam); // ...different for Win32! //Parse the menu selections: switch (wmId) { case IDM_EXIT: DestroyWindow (hWnd); break; case IDM_START: if (!TimerRunning) { TimerID = SetTimer (hWnd, LEAK_TIMER, TIME_INTERVAL, NULL); if (TimerID != 0) { TimerRunning = TRUE; EnableMenuItem (hTestMenu, IDM_START, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem (hTestMenu, IDM_STOP, MF_BYCOMMAND | MF_ENABLED); } else { //unable to start timer MessageBeep (MB_ICONEXCLAMATION); } } InvalidateRect (hWnd, NULL, TRUE); break; case IDM_STOP: if (TimerRunning) { KillTimer (hWnd, LEAK_TIMER); TimerID = 0; TimerRunning = FALSE; EnableMenuItem (hTestMenu, IDM_STOP, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem (hTestMenu, IDM_START, MF_BYCOMMAND | MF_ENABLED); } InvalidateRect (hWnd, NULL, TRUE); break; case IDM_RESET: FreeAllocatedMemory(); InvalidateRect (hWnd, NULL, TRUE); break; case IDM_ABOUT: DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)About); break; case IDM_HELPTOPICS: // Only called in Windows 95 bGotHelp = WinHelp (hWnd, APPNAME".HLP", HELP_FINDER,(DWORD)0); if (!bGotHelp) { MessageBox (GetFocus(), GetStringRes(IDS_NO_HELP), szAppName, MB_OK|MB_ICONHAND); } break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } break; case WM_TIMER: { PMEMORY_ALLOC_BLOCK pMab, pNewMab; pNewMab = (PMEMORY_ALLOC_BLOCK)G_ALLOC (GPTR, ALLOCATION_SIZE); if (pNewMab != NULL) { // save this pointer pNewMab->pNext = NULL; if (mabListHead.pNext == NULL) { // this is the first entry mabListHead.pNext = pNewMab; } else { // go to end of list pMab = mabListHead.pNext; while (pMab->pNext != NULL) pMab = pMab->pNext; pMab->pNext = pNewMab; } InvalidateRect (hWnd, NULL, TRUE); } } break; case WM_RBUTTONDOWN: // RightClick in windows client area... pnt.x = LOWORD(lParam); pnt.y = HIWORD(lParam); ClientToScreen(hWnd, (LPPOINT) &pnt); // This is where you would determine the appropriate 'context' // menu to bring up. Since this app has no real functionality, // we will just bring up the 'Help' menu: hMenu = GetSubMenu (GetMenu (hWnd), 2); if (hMenu) { TrackPopupMenu (hMenu, 0, pnt.x, pnt.y, 0, hWnd, NULL); } else { // Couldn't find the menu... MessageBeep(0); } break; case WM_DISPLAYCHANGE: // Only comes through on plug'n'play systems { SIZE szScreen; DWORD dwBitsPerPixel = (DWORD)wParam; szScreen.cx = LOWORD(lParam); szScreen.cy = HIWORD(lParam); MessageBox (GetFocus(), GetStringRes(IDS_DISPLAYCHANGED), szAppName, 0); } break; case WM_PAINT: { MEMORYSTATUS MemoryStatusData; LONGLONG llInUse; DWORD dwPercentUsed; int nX, nY; LONG lTextOutReturn; int nStringLength; CHAR szOutputString[100]; hdc = BeginPaint (hWnd, &ps); // Add any drawing code here... GlobalMemoryStatus (& MemoryStatusData); llInUse = (LONGLONG)(MemoryStatusData.dwTotalPageFile - MemoryStatusData.dwAvailPageFile + 5 ); llInUse *= 1000; llInUse /= MemoryStatusData.dwTotalPageFile; llInUse /= 10; dwPercentUsed = (DWORD)llInUse; nX = 0; nY = 0; _snprintf_s(szOutputString, 100, _TRUNCATE, "Reported Memory Load: \t%3.1d%%", MemoryStatusData.dwMemoryLoad); nStringLength = lstrlen (szOutputString) * sizeof (CHAR); lTextOutReturn = TabbedTextOut (hdc, nX, nY, szOutputString, nStringLength, 0, NULL, 0); nY += HIWORD (lTextOutReturn); _snprintf_s(szOutputString, 100, _TRUNCATE, "Page file in use: \t%3.1d%%", dwPercentUsed); nStringLength = lstrlen (szOutputString) * sizeof (CHAR); lTextOutReturn = TabbedTextOut(hdc, nX, nY, szOutputString, nStringLength, 0, NULL, 0); nY += HIWORD(lTextOutReturn); EndPaint (hWnd, &ps); } break; case WM_DESTROY: FreeAllocatedMemory(); // Tell WinHelp we don't need it any more... WinHelp(hWnd, APPNAME".HLP", HELP_QUIT,(DWORD)0); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } return (0); }