Example #1
0
JNIEXPORT jint JNICALL Java_org_krakenapps_winapi_PerformanceCounter_addCounter(JNIEnv *env, jobject obj, jint queryHandle, jstring category, jstring counter, jstring instance, jstring machine) {
	PDH_HCOUNTER phCounter = NULL;
	PDH_HQUERY phQuery = (PDH_HQUERY)queryHandle;
	LPTSTR counterPath = NULL;
	PDH_COUNTER_PATH_ELEMENTS pathElement;
	DWORD dwSize = 0;
	PDH_STATUS stat = 0;
	jboolean isCopy = JNI_FALSE;

	memset(&pathElement, 0, sizeof(pathElement));
	pathElement.szObjectName = category ? (LPTSTR)(*env)->GetStringChars(env, category, &isCopy) : NULL;
	pathElement.szCounterName = counter ? (LPTSTR)(*env)->GetStringChars(env, counter, &isCopy) : NULL;
	pathElement.szInstanceName = instance ? (LPTSTR)(*env)->GetStringChars(env, instance, &isCopy) : NULL;
	pathElement.szMachineName = machine ? (LPTSTR)(*env)->GetStringChars(env, machine, &isCopy) : NULL;

	if(pathElement.szMachineName) {
		stat = PdhConnectMachine(pathElement.szMachineName);
		if(stat != ERROR_SUCCESS) {
			fprintf(stderr, "Error in PdhConnectMachine:, 0x%x\n", stat);
		if(pathElement.szMachineName)
			(*env)->ReleaseStringChars(env, category, pathElement.szObjectName);
			(*env)->ReleaseStringChars(env, counter, pathElement.szCounterName);
			(*env)->ReleaseStringChars(env, instance, pathElement.szInstanceName);
			(*env)->ReleaseStringChars(env, machine, pathElement.szMachineName);
			return 0;
		}
	}

	PdhMakeCounterPath(&pathElement, NULL, &dwSize, 0);
	if(dwSize == 0) {
		fprintf(stderr, "Error in PdhMakeCounterPath\n");
		(*env)->ReleaseStringChars(env, category, pathElement.szObjectName);
		(*env)->ReleaseStringChars(env, counter, pathElement.szCounterName);
		(*env)->ReleaseStringChars(env, instance, pathElement.szInstanceName);
		(*env)->ReleaseStringChars(env, machine, pathElement.szMachineName);
		return 0;
	}

	counterPath = (LPTSTR)malloc(sizeof(TCHAR)*dwSize);
	stat = PdhMakeCounterPath(&pathElement, counterPath, &dwSize, 0);
	(*env)->ReleaseStringChars(env, category, pathElement.szObjectName);
	(*env)->ReleaseStringChars(env, counter, pathElement.szCounterName);
	(*env)->ReleaseStringChars(env, instance, pathElement.szInstanceName);
	(*env)->ReleaseStringChars(env, machine, pathElement.szMachineName);
	if(stat != ERROR_SUCCESS) {
		fprintf(stderr, "Error in PdhMakeCounterPath: 0x%x\n", stat);
		return 0;
	}

	stat = PdhAddCounter(phQuery, counterPath, 0, &phCounter);
	if(stat != ERROR_SUCCESS) {
		fprintf(stderr, "Error in PdhAddCounter: 0x%x\n", stat);
		return 0;
	}
	free(counterPath);

	PdhCollectQueryData(phQuery);

	return (jint)phCounter;
}
Example #2
0
PerformanceCounter::PerformanceCounter(const wchar_t* object_name,
                                       const wchar_t* counter_name,
                                       const wchar_t* instance_name)
    : valid_(false), query_(NULL), counter_(NULL) {
  PDH_COUNTER_PATH_ELEMENTS elements{};
  elements.szObjectName = const_cast<LPWSTR>(object_name);
  elements.szCounterName = const_cast<LPWSTR>(counter_name);
  elements.szInstanceName = const_cast<LPWSTR>(instance_name);

  DWORD length = 0;
  auto status = PdhMakeCounterPath(&elements, nullptr, &length, 0);
  if (status != PDH_MORE_DATA)
    return;

  std::wstring counter_path;
  counter_path.resize(length - 1);

  status = PdhMakeCounterPath(&elements, &counter_path[0], &length, 0);
  if (status != ERROR_SUCCESS)
    return;

  status = PdhOpenQuery(nullptr, 0, &query_);
  if (status != ERROR_SUCCESS)
    return;

  status = PdhAddCounter(query_, counter_path.c_str(), 0, &counter_);
  if (status != ERROR_SUCCESS)
    return;

  valid_ = PdhCollectQueryData(query_) == ERROR_SUCCESS;
}
Example #3
0
int
MakeCounterPath(LPTSTR	pszInstanceName,	// インスタンス名
	LPTSTR	pszCounterName,		// カウンター名
	LPTSTR	pszCounterPath,		// カウンターパス受け取りバッファー
	DWORD	dwCounterPathSize)	// カウンターパス受け取りバッファーのサイズ(文字数)
{
	PDH_COUNTER_PATH_ELEMENTS cpe;
	ZeroMemory(&cpe, sizeof(PDH_COUNTER_PATH_ELEMENTS));

	cpe.szMachineName = NULL;
	cpe.szObjectName = L"Process";
	cpe.szInstanceName = pszInstanceName;
	cpe.szParentInstance = NULL;
	cpe.dwInstanceIndex = 0;
	cpe.szCounterName = pszCounterName;

	// カウンターパスの作成
	if (ERROR_SUCCESS != PdhMakeCounterPath(&cpe,
		pszCounterPath,
		&dwCounterPathSize,
		0))
	{
		return -1;
	}

	return 1;
}
Example #4
0
PDH_STATUS	zbx_PdhMakeCounterPath(const char *function, PDH_COUNTER_PATH_ELEMENTS *cpe, char *counterpath)
{
    DWORD		dwSize = PDH_MAX_COUNTER_PATH;
    wchar_t		*wcounterPath = NULL;
    PDH_STATUS	pdh_status;

    wcounterPath = zbx_malloc(wcounterPath, sizeof(wchar_t) * PDH_MAX_COUNTER_PATH);

    if (ERROR_SUCCESS != (pdh_status = PdhMakeCounterPath(cpe, wcounterPath, &dwSize, 0)))
    {
        char	*object, *counter;

        object = zbx_unicode_to_utf8(cpe->szObjectName);
        counter = zbx_unicode_to_utf8(cpe->szCounterName);

        zabbix_log(LOG_LEVEL_ERR, "%s(): cannot make counterpath for \"\\%s\\%s\": %s",
                   function, object, counter, strerror_from_module(pdh_status, L"PDH.DLL"));

        zbx_free(counter);
        zbx_free(object);
    }
    else
        zbx_unicode_to_utf8_static(wcounterPath, counterpath, PDH_MAX_COUNTER_PATH);

    zbx_free(wcounterPath);

    return pdh_status;
}
Example #5
0
PDH_STATUS	zbx_PdhMakeCounterPath(const char *function, PDH_COUNTER_PATH_ELEMENTS *cpe, char *counterpath)
{
	DWORD		dwSize = PDH_MAX_COUNTER_PATH;
	LPTSTR		wcounterPath = NULL;
	PDH_STATUS	pdh_status;

	wcounterPath = zbx_realloc(wcounterPath, dwSize * sizeof(TCHAR));

	if (ERROR_SUCCESS != (pdh_status = PdhMakeCounterPath(cpe, wcounterPath, &dwSize, 0)))
	{
		zabbix_log(LOG_LEVEL_ERR, "%s(): cannot make counterpath '%s': %s",
				function, counterpath, strerror_from_module(pdh_status, L"PDH.DLL"));
	}

	zbx_unicode_to_utf8_static(wcounterPath, counterpath, PDH_MAX_COUNTER_PATH);
	zbx_free(wcounterPath);

	return pdh_status;
}
Example #6
0
/**
 * カウンターパスを作成する。
 *
 * @param pszInstanceName インスタンス名
 * @param pszCounterName カウンター名
 * @param pszCounterPath カウンターパス名格納先
 * @param dwCounterPathSize カウンターパス名格納可能サイズ
 * @return パスの作成に成功した場合は 1 、失敗した場合は -1
 */
static
bool MakeCounterPath(LPTSTR pszInstanceName, LPTSTR pszCounterName, LPTSTR pszCounterPath, DWORD dwCounterPathSize)
{
	PDH_COUNTER_PATH_ELEMENTS cpe;
	ZeroMemory( &cpe, sizeof(PDH_COUNTER_PATH_ELEMENTS) );

	cpe.szMachineName		= NULL; 
	cpe.szObjectName		= _T("Process");
	cpe.szInstanceName		= pszInstanceName;
	cpe.szParentInstance	= NULL;
	cpe.dwInstanceIndex		= -1;
	cpe.szCounterName		= pszCounterName;

	// カウンターパスの作成
	if( ERROR_SUCCESS != PdhMakeCounterPath( &cpe, pszCounterPath, &dwCounterPathSize, 0 ) )
	{
		return false;
	}

	return true;
}
BOOL WINAPI GetCounterValues(LPTSTR serverName, int instancesCount, char **instances)
{
    PDH_STATUS s;

    HQUERY hQuery;

    // Array to specify the performance object, counter and instance for
    // which performance data should be collected.

    // typedef struct _PDH_COUNTER_PATH_ELEMENTS {
    //   LPTSTR  szMachineName;
    //   LPTSTR  szObjectName;
    //   LPTSTR  szInstanceName;
    //   LPTSTR  szParentInstance;
    //   DWORD   dwInstanceIndex;
    //   LPTSTR  szCounterName;
    // } PDH_COUNTER_PATH_ELEMENTS, *PPDH_COUNTER_PATH_ELEMENTS;

    // Each element in the array is a PDH_COUNTER_PATH_ELEMENTS structure.

    PDH_COUNTER_PATH_ELEMENTS cpeTmpl[] =
    {
        { NULL, "%s:locks", "_total", NULL, -1, "lock waits/sec"},
        { NULL, "%s:general statistics", NULL, NULL, -1, "active temp tables"},
        { NULL, "%s:locks", "_total", NULL, -1, "average wait time (ms)"},
        { NULL, "%s:locks", "_total", NULL, -1, "lock timeouts (timeout > 0)/sec"},
        //{ NULL, "%s:wait statistics", "_total", NULL, -1, "page io latch waits"},
        { NULL, "%s:databases", "_total", NULL, -1, "repl. pending xacts"},
        { NULL, "%s:general statistics", NULL, NULL, -1, "logical connections"},
        { NULL, "%s:locks", "_total", NULL, -1, "lock wait time (ms)"},
        { NULL, "%s:general statistics", NULL, NULL, -1, "transactions"},
        { NULL, "%s:general statistics", NULL, NULL, -1, "processes blocked"},
        { NULL, "%s:sql statistics", NULL, NULL, -1, "sql compilations/sec"},
        { NULL, "%s:general statistics", NULL, NULL, -1, "user connections"},
        { NULL, "%s:locks", "_total", NULL, -1, "lock timeouts/sec"},
        { NULL, "%s:databases", "_total", NULL, -1, "percent log used"}
    };

    const int cpeTmplCount = sizeof(cpeTmpl) / sizeof(cpeTmpl[0]);
    const int countersCount = instancesCount * cpeTmplCount;
    int i, j;

    HCOUNTER *hCounter = malloc(sizeof(HCOUNTER) * countersCount);
    PDH_COUNTER_PATH_ELEMENTS *cpe = malloc(sizeof(PDH_COUNTER_PATH_ELEMENTS) * countersCount);

    char szFullPath[MAX_PATH];
    DWORD cbPathSize;

    int ret = -1;

    PDH_FMT_COUNTERVALUE counterValue;

    // Only do this setup once.
    if ((s = PdhOpenQuery(NULL, 0, &hQuery)) != ERROR_SUCCESS)
    {
        fprintf(stderr, "POQ failed %08x\n", s);
        return ret;
    }

    // Process instances to generate performance counter paths.
    for (i = 0; i < instancesCount; i++)
    {
        LPSTR instanceName = instances[i];

        for (j = 0; j < cpeTmplCount; j++) {
            
            int index = i * cpeTmplCount + j;

            cbPathSize = sizeof(szFullPath);

            PDH_COUNTER_PATH_ELEMENTS cpeTmplItem = cpeTmpl[j];

            cpe[index].szMachineName = cpeTmplItem.szMachineName;
            LPSTR szObjectName = malloc(cbPathSize);
            sprintf(szObjectName, cpeTmplItem.szObjectName, instanceName);
            cpe[index].szInstanceName = cpeTmplItem.szInstanceName;
            cpe[index].szObjectName = szObjectName;
            cpe[index].szParentInstance = cpeTmplItem.szParentInstance;
            cpe[index].dwInstanceIndex = cpeTmplItem.dwInstanceIndex;
            cpe[index].szCounterName = cpeTmplItem.szCounterName;

            if ((s = PdhMakeCounterPath(&cpe[index],
                szFullPath, &cbPathSize, 0)) != ERROR_SUCCESS)
            {
                fprintf(stderr,"MCP failed %08x\n", s);
                return ret;
            }

            if ((s = PdhAddCounter(hQuery, szFullPath, 0, &hCounter[index]))
                != ERROR_SUCCESS)
            {
                fprintf(stderr, "PAC failed %08x for %s\n", s, cpe[index].szCounterName);
                //return ret;
            }
        }
    }

    for (i = 0; i < 2; i++)
    {
        Sleep(100);

        // Collect data as often as you need to.
        if ((s = PdhCollectQueryData(hQuery)) != ERROR_SUCCESS)
        {
            fprintf(stderr, "PCQD failed %08x\n", s);
            return ret;
        }

        if (i == 0) continue;

        // Extract the calculated performance counter value for each counter or instance.
        for (j = 0; j < countersCount; j++)
        {
            if ((s = PdhGetFormattedCounterValue(hCounter[j], PDH_FMT_DOUBLE,
                NULL, &counterValue)) != ERROR_SUCCESS)
            {
                fprintf(stderr, "PGFCV failed %08x %d\n", s, hCounter[j]);
                continue;
            }
            if (cpe[j].szInstanceName)
            {
                printf("%s(%s)\\%s:%3.3f\n",
                    cpe[j].szObjectName,
                    cpe[j].szInstanceName,
                    cpe[j].szCounterName,
                    counterValue.doubleValue);
            }
            else
                printf("%s\\%s:%3.3f\n",
                    cpe[j].szObjectName,
                    cpe[j].szCounterName,
                    counterValue.doubleValue);
        }
    }

    // Remove all the counters from the query.
    for (i = 0; i < countersCount; i++)
    {
        PdhRemoveCounter(hCounter[i]);
        free(cpe[i].szObjectName);
    }

    // Only do this cleanup once.
    PdhCloseQuery(hQuery);

    free(hCounter);
    free(cpe);

    return 0;
}
int PerfCounterMuninNodePlugin::GetConfig(char *buffer, int len) 
{  
	if (!m_Counters.empty()) {

		PDH_STATUS status;
		DWORD infoSize = 0;
		status = PdhGetCounterInfo(m_Counters[0], TRUE, &infoSize, NULL);
		if (status != PDH_MORE_DATA && status != PDH_INSUFFICIENT_BUFFER)
			return -1;

		PDH_COUNTER_INFO *info = (PDH_COUNTER_INFO *)malloc(infoSize);
		status = PdhGetCounterInfo(m_Counters[0], TRUE, &infoSize, info);
		if (status != ERROR_SUCCESS)
			return -1;

		int printCount;
		std::string graphTitle = g_Config.GetValue(m_SectionName, "GraphTitle", "Disk Time");
		std::string graphCategory = g_Config.GetValue(m_SectionName, "GraphCategory", "system");
		std::string graphArgs = g_Config.GetValue(m_SectionName, "GraphArgs", "--base 1000 -l 0");
		std::string explainText = g_Config.GetValue(m_SectionName, "GraphInfo",
			info->szExplainText ? W2IConvert(info->szExplainText) : m_CounterNames[0].c_str());
		std::string counterName = g_Config.GetValue(m_SectionName, "GraphVLabel", W2IConvert(info->szCounterName));
		printCount = _snprintf(buffer, len, "graph_title %s\n"
			"graph_category %s\n"
			"graph_args %s\n"
			"graph_info %s\n"
			"graph_vlabel %s\n",
			graphTitle.c_str(), graphCategory.c_str(),
			graphArgs.c_str(),
			explainText.c_str(), counterName.c_str());
		len -= printCount;
		buffer += printCount;

		free(info);

		std::string graphDraw = g_Config.GetValue(m_SectionName, "GraphDraw", "LINE");
		std::string counterType = g_Config.GetValue(m_SectionName, "CounterType", "GAUGE");
		std::string warning = g_Config.GetValue(m_SectionName, "WarningValue", "");
		std::string critical = g_Config.GetValue(m_SectionName, "CriticalValue", "");

		assert(m_CounterNames.size() == m_Counters.size());

		std::string labels;

		// We handle multiple counters
		for (size_t i = 0; i < m_CounterNames.size(); i++) {
			PDH_STATUS status;
			DWORD infoSize = 0;
			status = PdhGetCounterInfo(m_Counters[i], TRUE, &infoSize, NULL);
			if (status != PDH_MORE_DATA && status != PDH_INSUFFICIENT_BUFFER)
				return -1;

			PDH_COUNTER_INFO *info = (PDH_COUNTER_INFO *)malloc(infoSize);
			status = PdhGetCounterInfo(m_Counters[i], TRUE, &infoSize, info);
			if (status != ERROR_SUCCESS) {
				free(info);
				return -1;
			}

			_Module.LogEvent("PerfCounter plugin: %s: counter id %i", m_Name.c_str(), info->dwType);

			DWORD npl = 260;
			TCHAR *np = new TCHAR[npl];
			PdhMakeCounterPath(&(info->CounterPath), np, &npl, 0);
			_Module.LogEvent("PerfCounter plugin: %s: counter path %ls, %ls", m_Name.c_str(), np, info->CounterPath.szObjectName);
			npl = 260;
			PdhMakeCounterPath(&(info->CounterPath), np, &npl, PDH_PATH_WBEM_INPUT);
			_Module.LogEvent("PerfCounter plugin: %s: counter path %ls, %ls", m_Name.c_str(), np, info->CounterPath.szObjectName);

			std::string explainText = info->szExplainText ? W2IConvert(info->szExplainText) : m_CounterNames[i].c_str();
			char* m_finalName = new char[128];

			if (i == 0)
				_snprintf(m_finalName, 127, "%s", m_Name.c_str());
			else
				_snprintf(m_finalName, 127, "%s_%i_", m_Name.c_str(), i);

			labels = "%s.label %s\n"
				"%s.draw %s\n"
				"%s.type %s\n"
				"%s.info %s\n";

			// First counter gets a normal name
			printCount = _snprintf(buffer, len,
				labels.c_str(),
				m_finalName, m_CounterNames[i].c_str(),
				m_finalName, graphDraw.c_str(),
				m_finalName, counterType.c_str(),
				m_finalName, explainText.c_str());
			len -= printCount;
			buffer += printCount;

			if (counterType == "DERIVE") {
				printCount = _snprintf(buffer, len,
					"%s.min 0\n",
					m_finalName);
				len -= printCount;
				buffer += printCount;
			}

			if (!warning.empty()) {
				printCount = _snprintf(buffer, len,
					"%s.warning %s\n",
					m_finalName,
					warning.c_str());
				len -= printCount;
				buffer += printCount;
			}
			if (!critical.empty()) {
				printCount = _snprintf(buffer, len,
					"%s.critical %s\n",
					m_finalName,
					critical.c_str());
				len -= printCount;
				buffer += printCount;
			}

			free(info);
		}
	}

  strncat(buffer, ".\n", len);
  return 0;
}
BOOL WINAPI GetCounterValues(LPTSTR serverName, int instancesCount, _TCHAR **instances)
{
    // Set to standard out to be unbuffered so we do not have to flush
    // each time we write out metric measurements
    setbuf(stdout, NULL);
    
    PDH_STATUS status;

    HQUERY hQuery;

    // Array to specify the performance object, counter and instance for
    // which performance data should be collected.

    // typedef struct _PDH_COUNTER_PATH_ELEMENTS {
    //   LPTSTR  szMachineName;
    //   LPTSTR  szObjectName;
    //   LPTSTR  szInstanceName;
    //   LPTSTR  szParentInstance;
    //   DWORD   dwInstanceIndex;
    //   LPTSTR  szCounterName;
    // } PDH_COUNTER_PATH_ELEMENTS, *PPDH_COUNTER_PATH_ELEMENTS;

    // Each element in the array is a PDH_COUNTER_PATH_ELEMENTS structure.
    PDH_COUNTER_PATH_ELEMENTS cpeTmpl[] =
    {
        { NULL, _TEXT("processor"), _TEXT("_total"), NULL, -1, _TEXT("% processor time")},
        { NULL, _TEXT("system"), NULL, NULL, -1, _TEXT("processor queue length")},
        { NULL, _TEXT("memory"), NULL, NULL, -1, _TEXT("available bytes")},
        { NULL, _TEXT("memory"), NULL, NULL, -1, _TEXT("pages/sec")},
        { NULL, _TEXT("physicaldisk"), _TEXT("_total"), NULL, -1 , _TEXT("% disk time")},
        { NULL, _TEXT("asp.net applications"), _TEXT("__total__"), NULL, -1, _TEXT("requests/sec")},
        { NULL, _TEXT("asp.net"), NULL, NULL, -1, _TEXT("application restarts")},
        { NULL, _TEXT("asp.net"), NULL, NULL, -1, _TEXT("request wait time")},
        { NULL, _TEXT("asp.net"), NULL, NULL, -1, _TEXT("requests queued")},
        { NULL, _TEXT(".net clr exceptions"), _TEXT("_global_"), NULL, -1, _TEXT("# of exceps thrown / sec")},
        { NULL, _TEXT(".net clr memory"), _TEXT("_global_"), NULL, -1, _TEXT("# total committed bytes")},
        { NULL, _TEXT("web service"), _TEXT("_total"), NULL, -1, _TEXT("get requests/sec")},
        { NULL, _TEXT("web service"), _TEXT("_total"), NULL, -1, _TEXT("post requests/sec")},
        { NULL, _TEXT("web service"), _TEXT("_total"), NULL, -1, _TEXT("current connections")}
    };

    const int cpeTmplCount = sizeof(cpeTmpl) / sizeof(cpeTmpl[0]);
    const int countersCount = cpeTmplCount;
    int i, j;

    HCOUNTER *hCounter = malloc(sizeof(HCOUNTER) * countersCount);
    PDH_COUNTER_PATH_ELEMENTS *cpe = malloc(sizeof(PDH_COUNTER_PATH_ELEMENTS) * countersCount);

    _TCHAR szFullPath[MAX_PATH];
    _TCHAR szMessage[MAX_PATH];
    DWORD cbPathSize;

    int result = -1;

    PDH_FMT_COUNTERVALUE counterValue;

    // Only do this setup once.
    status = PdhOpenQuery(NULL, 0, &hQuery);
    if (status != ERROR_SUCCESS)
    {
        OutputError(_TEXT("PdhOpenQuery() failed"), status);
        return result;
    }

    for (j = 0; j < cpeTmplCount; j++) {
        
        int index = i * cpeTmplCount + j;

        cbPathSize = sizeof(szFullPath);

        PDH_COUNTER_PATH_ELEMENTS cpeTmplItem = cpeTmpl[j];

        cpe[index].szMachineName = cpeTmplItem.szMachineName;
        cpe[index].szInstanceName = cpeTmplItem.szInstanceName;
        cpe[index].szObjectName = cpeTmplItem.szObjectName;
        cpe[index].szParentInstance = cpeTmplItem.szParentInstance;
        cpe[index].dwInstanceIndex = cpeTmplItem.dwInstanceIndex;
        cpe[index].szCounterName = cpeTmplItem.szCounterName;


        status = PdhMakeCounterPath(&cpe[index], szFullPath, &cbPathSize, 0);
        if (status != ERROR_SUCCESS)
        {
            OutputError(_TEXT("PdhMakeCounterPath() failed"), status);
            return result;
        }

        status = PdhAddCounter(hQuery, szFullPath, 0, &hCounter[index]);
        if (status != ERROR_SUCCESS)
        {
            swprintf(szMessage, sizeof(szMessage), _TEXT("PdhAddCounter() failed for \"%s\""), cpe[index].szCounterName);
            OutputError(szMessage, status);
            return result;
        }
    }

    for (i = 0; i < 2; i++)
    {
        Sleep(100);

        // Collect data as often as you need to.
        status = PdhCollectQueryData(hQuery);
        if (status != ERROR_SUCCESS)
        {
            OutputError(_TEXT("PdhCollectQuery() failed"), status);
            return result;
        }

        if (i == 0) continue;

        // Extract the calculated performance counter value for each counter or instance.
        for (j = 0; j < countersCount; j++)
        {
            status = PdhGetFormattedCounterValue(hCounter[j], PDH_FMT_DOUBLE, NULL, &counterValue);
            if (status != ERROR_SUCCESS)
            {
                wsprintf(szMessage, _TEXT("PdhGetFormattedCounterValue() failed for %d"), hCounter[j]);
                OutputError(szMessage, status);
                continue;
            }
            if (cpe[j].szInstanceName)
            {
                fwprintf(stdout, _TEXT("%s(%s)\\%s:%3.3f\n"),
                    cpe[j].szObjectName,
                    cpe[j].szInstanceName,
                    cpe[j].szCounterName,
                    counterValue.doubleValue);
            }
            else
                fwprintf(stdout, _TEXT("%s\\%s:%3.3f\n"),
                    cpe[j].szObjectName,
                    cpe[j].szCounterName,
                    counterValue.doubleValue);
        }
    }

    // Remove all the counters from the query.
    for (i = 0; i < countersCount; i++)
    {
        PdhRemoveCounter(hCounter[i]);
    }

    // Only do this cleanup once.
    PdhCloseQuery(hQuery);

    free(hCounter);
    free(cpe);

    return ERROR_SUCCESS;
}