PerfCounter::PerfCounter() { PdhOpenQuery(NULL, NULL, &m_query); HMODULE hProcess = GetModuleHandle(NULL); wchar_t fileNameBuf[MAX_PATH]; GetModuleFileName((HMODULE) hProcess, fileNameBuf, MAX_PATH); wchar_t baseNameBuf[MAX_PATH]; _wsplitpath_s(fileNameBuf, NULL, 0, NULL, 0, baseNameBuf, MAX_PATH, NULL, 0); m_processName = baseNameBuf; DWORD processId = GetProcessId(GetCurrentProcess()); //we need to figure out the correct instance name //start by asking for all the counters which match the process name std::wstring wildcard = (boost::wformat(L"\\Process(%1%*)\\ID Process") % m_processName).str(); wchar_t paths[1024]; DWORD size = 1024; PdhExpandWildCardPath(NULL, wildcard.c_str(), paths, &size, 0); //create each ProcessID counter, check its value to see if it's the one we want size_t len = wcslen(paths); wchar_t* pathPtr = paths; bool found = false; while(len != 0) { PDH_HCOUNTER counter; PdhAddCounter(m_query, pathPtr, NULL, &counter); PdhCollectQueryData(m_query); PDH_RAW_COUNTER counterValue; PdhGetRawCounterValue(counter, 0, &counterValue); PdhRemoveCounter(counter); if(counterValue.FirstValue == processId) { found = true; break; } pathPtr += len + 1; len = wcslen(pathPtr); } if(found) { //we've got our desired instance name, which is ProcessName#N const wchar_t* instStart = wcschr(wildcard.c_str(), L'(') + 1; const wchar_t* instEnd = wcschr(wildcard.c_str(), L')') - 1; m_instName = std::wstring(instStart, instEnd - instStart); } else { //oh well, just roll with what we've got m_instName = m_processName; } }
bool PerfCounterMuninNodePlugin::OpenCounter() { PDH_STATUS status; m_Name = m_SectionName.substr(strlen(PerfCounterMuninNodePlugin::SectionPrefix)); OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (!GetVersionEx(&osvi) || (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT)) { _Module.LogError("PerfCounter plugin: %s: unknown OS or not NT based", m_Name.c_str()); return false; //unknown OS or not NT based } // Create a PDH query status = PdhOpenQuery(NULL, 0, &m_PerfQuery); if (status != ERROR_SUCCESS) { _Module.LogError("PerfCounter plugin: %s: PdhOpenQuery error=%x", m_Name.c_str(), status); return false; } TString objectName = A2TConvert(g_Config.GetValue(m_SectionName, "Object", "LogicalDisk")); TString counterName = A2TConvert(g_Config.GetValue(m_SectionName, "Counter", "% Disk Time")); TString instanceName = A2TConvert(g_Config.GetValue(m_SectionName, "Instance", "*")); bool useEnglishNames = g_Config.GetValueB(m_SectionName, "UseEnglishObjectNames", true); if (useEnglishNames) { counterName = GetPdhCounterLocalizedName(counterName.c_str()); objectName = GetPdhCounterLocalizedName(objectName.c_str()); // NB: instance names are not localized } TCHAR *counterPath = new TCHAR[MAX_PATH]; status = _sntprintf(counterPath, MAX_PATH, _T("\\%s(%s)\\%s"), objectName.c_str(), instanceName.c_str(), counterName.c_str()); DWORD pathListBufsz = 0; status = PdhExpandWildCardPath(NULL, counterPath, NULL, &pathListBufsz, 0); if (status != PDH_MORE_DATA && status != PDH_INSUFFICIENT_BUFFER) { _Module.LogError("PerfCounter plugin: %s: PdhExpandWildCardPath error=%x", m_Name.c_str(), status); return false; } TCHAR *pathList = new TCHAR[pathListBufsz+2]; status = PdhExpandWildCardPath(NULL, counterPath, (PZZTSTR)pathList, &pathListBufsz, 0); if (status != ERROR_SUCCESS) { _Module.LogError("PerfCounter plugin: %s: PdhExpandWildCardPath error=%x", m_Name.c_str(), status); return false; } // read config TString includeRE = A2TConvert(g_Config.GetValue(m_SectionName, "IncludePaths", ".+")); TString excludeRE = A2TConvert(g_Config.GetValue(m_SectionName, "ExcludePaths", "^$")); // create regex matchers CRegexpT <TCHAR> includeRegEx(includeRE.c_str(), IGNORECASE); CRegexpT <TCHAR> excludeRegEx(excludeRE.c_str(), IGNORECASE); HCOUNTER counterHandle; for (; *pathList; pathList += _tcslen(pathList) + 1) { /* anatomy of a PDH path: \\machine\object(instance)\counter * anomalies of a PDH path: the instance name is optional, and * may contain parantheses and/or backslashes * thus, the safest way is to check for the first '(' and the * last '\' to separate the object, counter, instance names */ int backslashes[2] = {0, 0}; int para = 0; int idx; for (idx = 2; pathList[idx]; idx++) { if (pathList[idx] == '\\') { if (backslashes[0]) { backslashes[1] = idx; } else { backslashes[0] = idx; } } else if (pathList[idx] == '(' && (!para) && backslashes[0] && (!backslashes[1])) { para = idx; } } TCHAR *matchPath; // use regex matching either on the original path or the // back-translated constructed path if (useEnglishNames) { DWORD instPos = para ? para : backslashes[1]; TCHAR *oName = new TCHAR[instPos - backslashes[0]]; TCHAR *cName = new TCHAR[idx - backslashes[1] + 1]; TCHAR *iName = new TCHAR[backslashes[1] - para + 1]; // copy the object name wcsncpy(oName, pathList + backslashes[0] + 1, instPos - backslashes[0] - 1); oName[instPos - backslashes[0] - 1] = 0; // copy the counter name (end of complete path, so \0 already exists) wcsncpy(cName, pathList + backslashes[1] + 1, idx - backslashes[1]); cName[idx - backslashes[1]] = 0; // if there's an instance name, copy it, too. if (para) { wcsncpy(iName, pathList + para, backslashes[1] - para); } iName[backslashes[1] - para] = 0; matchPath = new TCHAR[MAX_PATH]; _snwprintf(matchPath, MAX_PATH, _T("\\%s%s\\%s"), GetPdhCounterEnglishName(oName), iName, GetPdhCounterEnglishName(cName)); delete oName; delete cName; delete iName; } else { matchPath = pathList; } // handle includes & excludes if (!includeRegEx.MatchExact(matchPath).IsMatched() || excludeRegEx.MatchExact(matchPath).IsMatched()) { if (useEnglishNames) { delete matchPath; } continue; } if (useEnglishNames) { delete matchPath; } // add the counter status = PdhAddCounter(m_PerfQuery, pathList, 0, &counterHandle); if (status != ERROR_SUCCESS) { _Module.LogError("PerfCounter plugin: %s: PDH add counter error=%x", m_Name.c_str(), status); return false; } // replace the backslash before the counter name with a space pathList[backslashes[1]] = ' '; std::string cn = W2IConvert(pathList + (para ? para : (backslashes[1] + 1))); _Module.LogEvent("PerfCounter plugin: %s: added counter %s", m_Name.c_str(), cn.c_str()); m_Counters.push_back(counterHandle); m_CounterNames.push_back(cn); } // Collect init data status = PdhCollectQueryData(m_PerfQuery); if (status != ERROR_SUCCESS) { if (status == PDH_INVALID_HANDLE) { _Module.LogError("PerfCounter plugin: %s: PDH collect data: PDH_INVALID_HANDLE", m_Name.c_str()); return false; } if (status == PDH_NO_DATA) { _Module.LogError("PerfCounter plugin: %s: PDH collect data: PDH_NO_DATA", m_Name.c_str()); return false; } _Module.LogError("PerfCounter plugin: %s: PDH collect data error", m_Name.c_str()); return false; } // Setup Counter Format m_dwCounterFormat = PDH_FMT_DOUBLE; std::string counterFormatStr = g_Config.GetValue(m_SectionName, "CounterFormat", "double"); if (!counterFormatStr.compare("double") || !counterFormatStr.compare("float")) { m_dwCounterFormat = PDH_FMT_DOUBLE; } else if (!counterFormatStr.compare("int") || !counterFormatStr.compare("long")) { m_dwCounterFormat = PDH_FMT_LONG; } else if (!counterFormatStr.compare("int64") || !counterFormatStr.compare("longlong") || !counterFormatStr.compare("large")) { m_dwCounterFormat = PDH_FMT_LARGE; } else { _Module.LogError("PerfCounter plugin: %s: Unknown CounterFormat", m_Name.c_str()); assert(!"Unknown CounterFormat!"); } m_CounterMultiply = g_Config.GetValueF(m_SectionName, "CounterMultiply", 1.0); return true; }
static INT_PTR CALLBACK OptionsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { PPH_PERFMON_CONTEXT context = NULL; if (uMsg == WM_INITDIALOG) { context = (PPH_PERFMON_CONTEXT)PhAllocate(sizeof(PH_PERFMON_CONTEXT)); memset(context, 0, sizeof(PH_PERFMON_CONTEXT)); SetProp(hwndDlg, L"Context", (HANDLE)context); } else { context = (PPH_PERFMON_CONTEXT)GetProp(hwndDlg, L"Context"); if (uMsg == WM_NCDESTROY) { PPH_STRING string; ClearCounterList(CountersList); CopyCounterList(CountersList, context->CountersListEdited); PhDereferenceObject(context->CountersListEdited); string = SaveCounterList(CountersList); PhSetStringSetting2(SETTING_NAME_PERFMON_LIST, &string->sr); PhDereferenceObject(string); RemoveProp(hwndDlg, L"Context"); PhFree(context); } } if (context == NULL) return FALSE; switch (uMsg) { case WM_INITDIALOG: { context->CountersListEdited = PhCreateList(2); context->ListViewHandle = GetDlgItem(hwndDlg, IDC_PERFCOUNTER_LISTVIEW); PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); PhSetControlTheme(context->ListViewHandle, L"explorer"); PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 420, L"Counter"); PhSetExtendedListView(context->ListViewHandle); ClearCounterList(context->CountersListEdited); CopyCounterList(context->CountersListEdited, CountersList); LoadCountersToListView(context, context->CountersListEdited); } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_ADD_BUTTON: { PDH_STATUS counterStatus = 0; PPH_STRING counterPathString = NULL; PPH_STRING counterWildCardString = NULL; PDH_BROWSE_DLG_CONFIG browseConfig = { 0 }; WCHAR counterPathBuffer[PDH_MAX_COUNTER_PATH] = L""; browseConfig.bIncludeInstanceIndex = FALSE; browseConfig.bSingleCounterPerAdd = FALSE;// Fix empty CounterPathBuffer browseConfig.bSingleCounterPerDialog = TRUE; browseConfig.bLocalCountersOnly = FALSE; browseConfig.bWildCardInstances = TRUE; // Seems to cause a lot of crashes browseConfig.bHideDetailBox = TRUE; browseConfig.bInitializePath = FALSE; browseConfig.bDisableMachineSelection = FALSE; browseConfig.bIncludeCostlyObjects = FALSE; browseConfig.bShowObjectBrowser = FALSE; browseConfig.hWndOwner = hwndDlg; browseConfig.szReturnPathBuffer = counterPathBuffer; browseConfig.cchReturnPathLength = PDH_MAX_COUNTER_PATH; browseConfig.CallBackStatus = ERROR_SUCCESS; browseConfig.dwDefaultDetailLevel = PERF_DETAIL_WIZARD; browseConfig.szDialogBoxCaption = L"Select a counter to monitor."; __try { // Display the counter browser window. if ((counterStatus = PdhBrowseCounters(&browseConfig)) != ERROR_SUCCESS) { if (counterStatus != PDH_DIALOG_CANCELLED) { PhShowError(hwndDlg, L"PdhBrowseCounters failed with status 0x%x.", counterStatus); } __leave; } else if (wcslen(counterPathBuffer) == 0) { // This gets called when pressing the X on the BrowseCounters dialog. __leave; } counterPathString = PhCreateString(counterPathBuffer); // Check if we need to expand any wildcards... if (PhFindCharInString(counterPathString, 0, '*') != -1) { ULONG counterWildCardLength = 0; // Query WildCard buffer length... PdhExpandWildCardPath( NULL, counterPathString->Buffer, NULL, &counterWildCardLength, 0 ); counterWildCardString = PhCreateStringEx(NULL, counterWildCardLength * sizeof(WCHAR)); if ((counterStatus = PdhExpandWildCardPath( NULL, counterPathString->Buffer, counterWildCardString->Buffer, &counterWildCardLength, 0 )) == ERROR_SUCCESS) { PH_STRINGREF part; PH_STRINGREF remaining = counterWildCardString->sr; while (remaining.Length != 0) { // Split the results if (!PhSplitStringRefAtChar(&remaining, '\0', &part, &remaining)) break; if (remaining.Length == 0) break; if ((counterStatus = PdhValidatePath(part.Buffer)) != ERROR_SUCCESS) { PhShowError(hwndDlg, L"PdhValidatePath failed with status 0x%x.", counterStatus); __leave; } AddCounterToListView(context, part.Buffer); } } else { PhShowError(hwndDlg, L"PdhExpandWildCardPath failed with status 0x%x.", counterStatus); } } else { if ((counterStatus = PdhValidatePath(counterPathString->Buffer)) != ERROR_SUCCESS) { PhShowError(hwndDlg, L"PdhValidatePath failed with status 0x%x.", counterStatus); __leave; } AddCounterToListView(context, counterPathString->Buffer); } } __finally { if (counterWildCardString) PhDereferenceObject(counterWildCardString); if (counterPathString) PhDereferenceObject(counterPathString); } } break; case IDC_REMOVE_BUTTON: { INT itemIndex; // Get the first selected item itemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED); while (itemIndex != -1) { PPH_PERFMON_ENTRY entry; if (PhGetListViewItemParam(context->ListViewHandle, itemIndex, (PPVOID)&entry)) { ULONG index = PhFindItemList(context->CountersListEdited, entry); if (index != -1) { PhRemoveItemList(context->CountersListEdited, index); PhRemoveListViewItem(context->ListViewHandle, itemIndex); FreeCounterEntry(entry); } } // Get the next selected item itemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED); } } break; case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); break; case IDOK: EndDialog(hwndDlg, IDOK); break; } } break; } return FALSE; }