#include <stdio.h>
#include <tchar.h>

#include "lib.h"
void b_free(void *p);
//void *b_realloc(void *cur, int sz);
//void *b_malloc(size_t sz);
#include "../dftp/common/clib.h"
#include <windows.h>
#include "Psapi.h"
#include "defines.h"
#include "perflib.h"
#include "../sam/lprintf.h"

int emsg(const char * arg_list, ...);
#define DMID 3
#include "debug.h"

#define MakePtr(cast, ptr, addValue) (cast)( (DWORD)(ptr) + (DWORD)(addValue))

// --------------------------------------------------------------------------------------------
// Performance text description database code - Keeps a single copy of database in memory (~70K)
// while in use by performance access functions below :-)
// --------------------------------------------------------------------------------------------

enum PERFORMANCE_TITLE_TYPE { PERF_TITLE_COUNTER, PERF_TITLE_EXPLAIN };

PTSTR       * m_TitleStrings;
PTSTR       m_pszRawStrings;
unsigned	m_nLastIndex;
int			refcount=0;

double static_workingset = 0;


int PerfTitleDB_init( int titleType )
{
    PTSTR psz009RegValue, pszLastIndexRegValue;
    HKEY hKeyPerflib = 0;
    DWORD cbLastIndex=sizeof(int);
    DWORD cbTitleStrings;
    PTSTR pszWorkStr;
	int ecode;
	char bf[BFSZ];
    unsigned cbCurrStr;

	if (refcount>0) return TRUE;

    m_nLastIndex = 0;
    m_TitleStrings = 0;
    m_pszRawStrings = 0;

    // Determine the appropriate strings to pass to RegOpenKeyEx
    if ( PERF_TITLE_COUNTER == titleType ){
        psz009RegValue = TEXT("Counter 009");
        pszLastIndexRegValue = TEXT("Last Counter");
    } else if ( PERF_TITLE_EXPLAIN == titleType ){
        psz009RegValue = TEXT("Explain 009");
        pszLastIndexRegValue = TEXT("Last Help");
    } else {
		emsg("Failed state 1\n");
        return FALSE;
	}

    // Determine maximum number of title strings
    if ( ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"), 0, KEY_READ, &hKeyPerflib ) ) {
		emsg("Failed state 2\n");
        return FALSE;
	}

	ecode = RegQueryValueEx( hKeyPerflib, pszLastIndexRegValue, 0, 0, (PBYTE)&m_nLastIndex, &cbLastIndex );
    if ( ERROR_SUCCESS != ecode ){
        RegCloseKey( hKeyPerflib );
		emsg("Failed state %s\n",system_error(ecode,bf,BFSZ-1));
        return FALSE;
    }
    RegCloseKey( hKeyPerflib );

    // Load in title strings
    if ( ERROR_SUCCESS != RegQueryValueEx( HKEY_PERFORMANCE_DATA, psz009RegValue, 0,0,0, &cbTitleStrings)) {
		emsg("Failed state 4\n");
        return FALSE;
	}
    m_pszRawStrings = malloc(sizeof(PTSTR)*cbTitleStrings);
    if ( ERROR_SUCCESS != RegQueryValueEx( HKEY_PERFORMANCE_DATA, psz009RegValue, 0, 0, (PBYTE)m_pszRawStrings, &cbTitleStrings ) ) {
        free(m_pszRawStrings);
		emsg("Failed state 5\n");
        return FALSE;
    }

    // Generate an index
    m_TitleStrings = malloc(sizeof(PTSTR)*(m_nLastIndex+1));
    if ( !m_TitleStrings ) {
        free(m_pszRawStrings);
		emsg("Failed state 6\n");
        return FALSE;
    }
    memset( m_TitleStrings, 0, sizeof(PTSTR) * m_nLastIndex );
    pszWorkStr = (PTSTR)m_pszRawStrings;
    while ( 0 != (cbCurrStr = lstrlen( pszWorkStr)) )
    {
        unsigned index = _ttoi( pszWorkStr );   // _ttoi -> atoi()
        if ( index > m_nLastIndex )
            break;
        pszWorkStr += cbCurrStr + 1;
        m_TitleStrings[index] = pszWorkStr;
        pszWorkStr += lstrlen(pszWorkStr) + 1;
    }
	refcount++;
	return TRUE;
}

void PerfTitleDatabase_free( )
{
    refcount--;
	if (refcount==0){
		free(m_TitleStrings);
		m_TitleStrings = 0;
		free(m_pszRawStrings);
		m_pszRawStrings = 0;
		m_nLastIndex = 0;
	}
}

PTSTR GetTitleStringFromIndex( unsigned index )
{
    if ( index > m_nLastIndex ) // Is index within range?
        return 0;

    return m_TitleStrings[ index ];
}

unsigned GetIndexFromTitleString( PTSTR pszTitleString )
{
	unsigned i;

    if ( IsBadStringPtr(pszTitleString, 0xFFFFFFFF) )
        return 0;

    for ( i = 1; i <= m_nLastIndex; i++ ){
        if ( m_TitleStrings[i] )
            if ( 0 == _tcsicmp( pszTitleString, m_TitleStrings[i] ) )
                return i;
    }
    return 0;
}

// --------------------------------------------------------------------------------------------
// Windows Performance Database access functions (Low level)
// Very much modelled on microsoft PDH helper dll functions, but pdh.dll cannot be loaded dynamically
// which means that the same binary will not work on W98 and Win NT. Further advantages: this gives
// us more control and some older systems may not have pdh.dll installed.
// --------------------------------------------------------------------------------------------

int FormatRaw( MWCOUNTER* pMwCounter, RAWITEM *pRawItem, double *pNumValue, PTSTR pStrValue, DWORD nSize, BOOL fHex );

int CreateQuery(QUERY**hQuery)
{
	QUERY* pNew;

	pNew=(QUERY *)malloc(sizeof(QUERY));
	if (!pNew) {
		*hQuery=NULL;
		emsg("CreateQuery, malloc failed\n");
		return FALSE;
	}
	pNew->pData = b_malloc(TOTALBYTES);
	pNew->nDataBufSize = TOTALBYTES;
	pNew->pPerfItems = NULL;
	pNew->QueryText[0] = '\0';

	// pQuery->QueryText = "Global";
	// pQuery->QueryText= "4";				// Memory??
	//strcpy(pNew->QueryText,"238");		// Processor

	pNew->LastTime.QuadPart = pNew->LastTime100ns.QuadPart = pNew->TimeDelta.QuadPart = pNew->TimeDelta100ns.QuadPart=0;

	*hQuery=pNew;

	if (!PerfTitleDB_init(PERF_TITLE_COUNTER)){
		emsg("PerfTitle failed\n");
		free(pNew);
		*hQuery=NULL;
		return FALSE;
	}

	return TRUE;
}

int AddCounter(QUERY *pQuery, char* countername, MWCOUNTER **hPerfItem)
{
	MWCOUNTER *pItem;
	char name[BFSZ],bf[BFSZ];
	char *p,*object,*instance,*counter;
	unsigned long ObjectIndex;
	unsigned long CounterIndex;

	if (hPerfItem) *hPerfItem=NULL;

	if (pQuery==NULL) return FALSE;

	strcpy(name,countername);
	object=instance=counter=NULL;

	//parse the name and lookup each value
	p=name;
	if (strcmp(p,"\\\\")==0) {
		// Possibly handle computernaming in future (currently not supported)
		return FALSE;
	}
	if (*p=='\\') {object=++p;} // bug fix, was p= instead of p==, 
	while ( *p && !(*p=='\\' || *p=='(') ) { p++; if (p-name>BFSZ) return FALSE;}
	if (*p=='('){
		*p++=0;
		instance=p;
		while ( *p && *p!=')') { p++; if (p-name>BFSZ) return FALSE;}
	}
	if (*p==')') *p++=0;
	if (*p=='\\') *p++=0;
	counter=p;

	ObjectIndex = GetIndexFromTitleString(object);
	CounterIndex = GetIndexFromTitleString(counter);
	if (ObjectIndex==0 || CounterIndex==0) return FALSE;

	pItem=(MWCOUNTER *)malloc(sizeof(MWCOUNTER));
	if (!pItem) {
		if (hPerfItem) *hPerfItem=NULL;
		return FALSE;
	}

	pItem->name = strdup(countername);
	pItem->ObjectIndex = ObjectIndex;
	pItem->InstanceName = strdup(instance);
	pItem->CounterIndex = CounterIndex;
	pItem->pQuery = pQuery;
	pItem->m_OldData.QuadPart = 0;

	pItem->next = pQuery->pPerfItems;
	pQuery->pPerfItems = pItem;
	if (hPerfItem) *hPerfItem=pItem;

	// Just make sure that we actually get this counter "object" when we ask for perf data
	sprintf(bf,"%d", ObjectIndex);
	if (strstr(pQuery->QueryText,bf)==0){
		if (pQuery->QueryText[0]!=0) strcat(pQuery->QueryText, " ");
		strcat(pQuery->QueryText,bf);
	}

	return TRUE;
}

int ReleaseQuery(QUERY *pQuery)
{
	MWCOUNTER *pItem, *pNext;

	for(pItem = pQuery->pPerfItems;pItem;pItem=pNext){
		pNext=pItem->next;
		free(pItem->name);
		free(pItem->InstanceName);
		free(pItem);
	}
	b_free((void *) pQuery->pData);
	free(pQuery);

	PerfTitleDatabase_free();

	return TRUE;
}

int CollectData(QUERY *pQuery)
{
	DWORD bfSizeInOut = pQuery->nDataBufSize;
	while (RegQueryValueEx( HKEY_PERFORMANCE_DATA,pQuery->QueryText,NULL,NULL,(LPBYTE)pQuery->pData,&bfSizeInOut ) == ERROR_MORE_DATA ){
		// Get a buffer that is big enough.
		pQuery->nDataBufSize += BYTEINCREMENT;
		if (pQuery->nDataBufSize<140000) pQuery->nDataBufSize = 140000;
		pQuery->pData = (PPERF_DATA_BLOCK) b_realloc( (char *) pQuery->pData, pQuery->nDataBufSize );
		bfSizeInOut = pQuery->nDataBufSize;
	}

	// Store time deltas for use later
	pQuery->TimeDelta.QuadPart = pQuery->pData->PerfTime.QuadPart - pQuery->LastTime.QuadPart;
	pQuery->LastTime.QuadPart = pQuery->pData->PerfTime.QuadPart;
	pQuery->TimeDelta100ns.QuadPart = pQuery->pData->PerfTime100nSec.QuadPart - pQuery->LastTime100ns.QuadPart;
	pQuery->LastTime100ns.QuadPart = pQuery->pData->PerfTime100nSec.QuadPart;

	return TRUE;
}


// Need to walk the item tree after each data collection as the format could be different between calls
// to RegQueryValueEx data collection calls (could walk once and make a hashed index or something but does
// not gain us much)
int WindowsPerfCounter(MWCOUNTER *pPerfItem, double /*value*/* numValue, char* strValue)
{
	PPERF_DATA_BLOCK PerfData;
	PPERF_OBJECT_TYPE PerfObj;
	PPERF_INSTANCE_DEFINITION PerfInst;
	PPERF_COUNTER_DEFINITION PerfCntr, CurCntr;
	PPERF_COUNTER_BLOCK PtrToCntr;

	DWORD i,j;
	LONG k;
	RAWITEM rawItem;

	if (numValue) *numValue=0;
	if (strValue) strcpy(strValue,"NO-SUCH-COUNTER");

	PerfData = pPerfItem->pQuery->pData;

	// Walk Perf objects
	PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfData + PerfData->HeaderLength);
	for( i=0; i < PerfData->NumObjectTypes; i++, PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfObj + PerfObj->TotalByteLength))
	{
		if (pPerfItem->ObjectIndex != PerfObj->ObjectNameTitleIndex) continue;
		//printf( "\nObject: (%ld) %s \n", PerfObj->ObjectNameTitleIndex, GetTitleStringFromIndex( PerfObj->ObjectNameTitleIndex ) );

		// Get the counter block.
		PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfObj + PerfObj->HeaderLength);
		if( PerfObj->NumInstances > 0 ){

			// Walk Instances
			PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj + PerfObj->DefinitionLength);
			for( k=0; k < PerfObj->NumInstances; k++, PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PtrToCntr + PtrToCntr->ByteLength) ){

				PtrToCntr = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst + PerfInst->ByteLength);

//				if (strcmp(PerfItem->InstanceName, (wchar_t *)((PBYTE)PerfInst + PerfInst->NameOffset)) != 0) continue;
				// could not find ansi-unicode strcmp so roll our own for now
				{
					char *p1,*p2;
					p1=pPerfItem->InstanceName;
					p2=(char*)((PBYTE)PerfInst + PerfInst->NameOffset);	// Always unicode
					while (*p1==*p2 && *p1!=0 && *p2!=0 && *p2!=' ') {p1++;p2+=2;}
					if (!(*p1==0 && (*p2==0 || *p2==' '))) continue;
				}
				//printf( "\n\tInstance: %S\n", (char *)((PBYTE)PerfInst + PerfInst->NameOffset) );

				// Walk the counters.
				for( j=0, CurCntr = PerfCntr; j < PerfObj->NumCounters; j++, CurCntr=(PPERF_COUNTER_DEFINITION)((PBYTE)CurCntr+CurCntr->ByteLength) ){

					if (pPerfItem->CounterIndex != CurCntr->CounterNameTitleIndex) continue;
					//printf("\t\tCounter: (%ld) %s ",CurCntr->CounterNameTitleIndex,GetTitleStringFromIndex(CurCntr->CounterNameTitleIndex));
					// Data is (LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset);

					// [ possible improvement, cache a formatting fn for common counters: if (pPerfItem->formatfn) call that direct ]

					// Setup values for formatting
					rawItem.m_pData = (LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset);	// Actual Data pointer
					rawItem.m_type = CurCntr->CounterType;									// CounterType
					rawItem.m_cbData = CurCntr->CounterSize;								// Countersize
					rawItem.pObj = PerfObj;

					FormatRaw(pPerfItem, &rawItem, numValue, strValue,BFSZ,FALSE);

					if (strcmp(pPerfItem->name, "\\Process(surgemail)\\Working Set") == 0){
						static_workingset = *numValue;
					}
				}

			}
		}else{
			// Walk the counters.
			PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfObj + PerfObj->DefinitionLength );
			for( j=0; j < PerfObj->NumCounters; j++, PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr + PerfCntr->ByteLength) ){

				if (pPerfItem->CounterIndex != PerfCntr->CounterNameTitleIndex) continue;
				//printf( "\tCounter: (%ld) %s ", PerfCntr->CounterNameTitleIndex, GetTitleStringFromIndex(PerfCntr->CounterNameTitleIndex) );
				// Data is (LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

				// Setup values for formatting
				rawItem.m_pData = (LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);	// Actual Data pointer
				rawItem.m_type = PerfCntr->CounterType;									// CounterType
				rawItem.m_cbData = PerfCntr->CounterSize;								// Countersize
				rawItem.pObj = PerfObj;

				FormatRaw(pPerfItem, &rawItem, numValue, strValue,BFSZ,FALSE);
			}
		}
	}
	return 0;
}


int WindowsPerfCounter_instances(MWCOUNTER *pPerfItem)
{
	PPERF_DATA_BLOCK PerfData;
	PPERF_OBJECT_TYPE PerfObj;
	PPERF_COUNTER_DEFINITION PerfCntr;

	DWORD i;
	int instances=0;

	PerfData = pPerfItem->pQuery->pData;

	// Walk Perf objects
	PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfData + PerfData->HeaderLength);
	for( i=0; i < PerfData->NumObjectTypes; i++, PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfObj + PerfObj->TotalByteLength))
	{
		if (pPerfItem->ObjectIndex != PerfObj->ObjectNameTitleIndex) continue;
		//printf( "\nObject: (%ld) %s \n", PerfObj->ObjectNameTitleIndex, GetTitleStringFromIndex( PerfObj->ObjectNameTitleIndex ) );

		// Get the counter block.
		PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfObj + PerfObj->HeaderLength);
		instances = PerfObj->NumInstances;
	}
	return instances;
}



int FormatRaw( MWCOUNTER* pMwCounter, RAWITEM *pRawItem, double *pNumValue, PTSTR pStrValue, DWORD nSize, BOOL fHex )
{
    PTSTR pszPrefix = TEXT("");
    TCHAR szTemp[512];
	PTSTR pszFmt;
	LARGE_INTEGER DeltaC,DeltaT;
	LARGE_INTEGER data;

	double tmp;

    // First, ascertain the basic type (number, counter, text, or zero
	switch ( pRawItem->m_type & 0x00000C00 ){
        case PERF_TYPE_ZERO:{
            wsprintf( pStrValue, TEXT("ZERO") ); return TRUE;
        }
        case PERF_TYPE_TEXT:{
            wsprintf( pStrValue, TEXT("text counter") ); return TRUE;
        }
        case PERF_TYPE_COUNTER:{
            switch( pRawItem->m_type & 0x00070000 ){
                case PERF_COUNTER_RATE:
                    pszPrefix = TEXT("{counter rate} "); break;
                case PERF_COUNTER_FRACTION:
                    pszPrefix = TEXT("{counter fraction} "); break;
                case PERF_COUNTER_BASE:
                    pszPrefix = TEXT("{counter base} "); break;
                case PERF_COUNTER_ELAPSED:
                    pszPrefix = TEXT("{counter elapsed} "); break;
                case PERF_COUNTER_QUEUELEN:
                    pszPrefix = TEXT("{counter queuelen} "); break;
                case PERF_COUNTER_HISTOGRAM:
                    pszPrefix = TEXT("{counter histogram} "); break;
                default:
                    pszPrefix = TEXT("{counter value} "); break;
            }
			break;
        }
        case PERF_TYPE_NUMBER:{
            pszPrefix = TEXT("{number}"); break;
        }
        default: {
            wsprintf( pStrValue, TEXT("UNKNOWN TYPE ") ); return TRUE;
        }
    }

	switch (pRawItem->m_type & 0x00300000){
		case PERF_TIMER_100NS:
			DeltaT.QuadPart = pMwCounter->pQuery->TimeDelta100ns.QuadPart; break;
		case PERF_TIMER_TICK:
			DeltaT.QuadPart = pMwCounter->pQuery->TimeDelta.QuadPart / pMwCounter->pQuery->pData->PerfFreq.QuadPart;  // current frequency
			break;
		case PERF_OBJECT_TIMER:
            wsprintf( pStrValue, TEXT("UNHANDLED TYPE ") ); return TRUE;
		default:
			DeltaT.QuadPart = pMwCounter->pQuery->TimeDelta.QuadPart;

	}
	pszFmt = fHex ? TEXT("%s%Xh") : TEXT("%s%u");

    switch ( pRawItem->m_cbData ){
        case 1: data.QuadPart = *(PBYTE)pRawItem->m_pData;
                break;
        case 2: data.QuadPart = *(PWORD)pRawItem->m_pData;
                break;
        case 4: data.QuadPart = *(PDWORD)pRawItem->m_pData;
                break;
        case 8: data.QuadPart = *(PLONGLONG)pRawItem->m_pData;
				break;
		default: wsprintf( pStrValue, TEXT("<unhandled size %u>"), pRawItem->m_cbData );
    }

	DeltaC.QuadPart = data.QuadPart - pMwCounter->m_OldData.QuadPart;

	switch ( pRawItem->m_type & 0x00000C00 ){
        case PERF_TYPE_COUNTER:{
			switch( pRawItem->m_type & 0x00070000 ){
				case PERF_COUNTER_VALUE:
					tmp = (double)DeltaC.QuadPart;
					break;
				case PERF_COUNTER_RATE:
					tmp = (double)DeltaC.QuadPart/DeltaT.QuadPart;
					break;
				case PERF_COUNTER_FRACTION:
					//tmp = DeltaC/DeltaB;
		            wsprintf( pStrValue, TEXT("UNHANDLED TYPE ") ); return TRUE;
					break;
				case PERF_COUNTER_BASE:
					// NEVER DISPLAY
					break;
				case PERF_COUNTER_ELAPSED:
					//tmp=counter-time;
		            wsprintf( pStrValue, TEXT("UNHANDLED TYPE ") ); return TRUE;
					break;
				case PERF_COUNTER_QUEUELEN:
					//tmp = (C1 + (T1 * B1))/DeltaT
		            wsprintf( pStrValue, TEXT("UNHANDLED TYPE ") ); return TRUE;
					break;
				case PERF_COUNTER_HISTOGRAM:
					// HIST
		            wsprintf( pStrValue, TEXT("UNHANDLED TYPE ") ); return TRUE;
					break;
				default:
		            wsprintf( pStrValue, TEXT("UNHANDLED TYPE ") ); return TRUE;
					break;
			}
			break;
		}
        case PERF_TYPE_NUMBER:{
            tmp= (double) data.QuadPart;
        }
	}
//	tmp = (1.0 - (1.0*DeltaC / pMwCounter->pQuery->TimeDelta100ns)) * 100.0;

	if (pRawItem->m_type & PERF_INVERSE_COUNTER) tmp = 1.0 - tmp;
	if (pRawItem->m_type & PERF_DISPLAY_PERCENT) tmp*=100;

//    LARGE_INTEGER   PerfTime;           // Sample Time in "Object" units
//    LARGE_INTEGER   PerfFreq;           // Frequency of "Object" units in
//} PERF_OBJECT_TYPE, *PPERF_OBJECT_TYPE;

	sprintf( szTemp, TEXT("%s %f"), pszPrefix, tmp);

    switch ( pRawItem->m_cbData ){
        case 1: pMwCounter->m_OldData.QuadPart = *(PBYTE)pRawItem->m_pData;
                break;
        case 2: pMwCounter->m_OldData.QuadPart = *(PWORD)pRawItem->m_pData;
                break;
        case 4: pMwCounter->m_OldData.QuadPart = *(PDWORD)pRawItem->m_pData;
                break;
        case 8: pMwCounter->m_OldData.QuadPart = *(PLONGLONG)pRawItem->m_pData;
				break;
		default: wsprintf( pStrValue, TEXT("<unhandled size %u>"), pRawItem->m_cbData );
    }

    switch ( pRawItem->m_type & 0x70000000 ){
        case PERF_DISPLAY_SECONDS:
            _tcscat( szTemp, TEXT(" secs") ); break;
        case PERF_DISPLAY_PERCENT:
            _tcscat( szTemp, TEXT(" %") ); break;
        case PERF_DISPLAY_PER_SEC:
            _tcscat( szTemp, TEXT(" /sec") ); break;
    }

    if (pStrValue) lstrcpyn( pStrValue, szTemp, nSize );
	if (pNumValue) *pNumValue = tmp;

    return TRUE;
}



// --------------------------------------------------------------------------------------------
// Main function / test call for test purposes
// --------------------------------------------------------------------------------------------

#ifdef __PERFLIB_EXE
void main()
#else
void test_perflib()
#endif
{
	QUERY *pQuery = NULL;
	MWCOUNTER *pcounter=NULL;
	double value;
	char bf[BFSZ];

	if (!CreateQuery(&pQuery)){
		printf("Failed to init perf stuff\n");
		exit(99);
	}

	AddCounter(pQuery,"\\Processor(_Total)\\% Processor Time",NULL);
	AddCounter(pQuery,"\\Memory\\Committed Bytes",NULL);
	AddCounter(pQuery,"\\Process(surgemail)\\% Processor Time",NULL);
	AddCounter(pQuery,"\\Process(surgemail)\\Working Set",NULL);
	AddCounter(pQuery,"\\PhysicalDisk(_Total)\\Disk Reads/sec",NULL);
	AddCounter(pQuery,"\\PhysicalDisk(_Total)\\Disk Writes/sec",NULL);

//	AddCounter(pQuery,"\\Process(surgemail)\\Handle Count",NULL);
//	AddCounter(pQuery,"\\Process(surgemail)\\Thread Count",NULL);

	CollectData(pQuery);
	Sleep(1000);

	for(;;){

		CollectData(pQuery);

		//for each object;
		for(pcounter = pQuery->pPerfItems;pcounter;pcounter=pcounter->next){
			WindowsPerfCounter(pcounter, &value, bf);
			printf("Perf counter \"%s\" %s [%f]\n",pcounter->name,bf,value);
		}
		printf("\n\n");
		Sleep(60000);
	}

	ReleaseQuery(pQuery);
}

char *get_vmsize_disabled(char *tmp3)
{
	return "DISABLED";
}
char *get_vmsize(char *tmp3)
{
	lprintf(tmp3, BFSZ - 1, "%.0fmb", static_workingset / 1000000.0);
	return tmp3;
}
char *get_vmsize_broken(char *tmp3)
{
	QUERY *pQuery = NULL;
	MWCOUNTER *pcounter=NULL;
	double value;
	char bf[BFSZ];
	double saved=0;

	if (!CreateQuery(&pQuery)){
		emsg("Failed to init perf stuff\n");
		return "";
	}

	AddCounter(pQuery,"\\Process(surgemail)\\Working Set",NULL);
	CollectData(pQuery);
	//Sleep(100);

	for(pcounter = pQuery->pPerfItems;pcounter;pcounter=pcounter->next){
		WindowsPerfCounter(pcounter, &value, bf);
		//printf("Perf counter \"%s\" %s [%f]\n",pcounter->name,bf,value);
		saved = value;
	}
	ReleaseQuery(pQuery);
	lprintf(tmp3,BFSZ-1,"%.0fmb",saved/1000000.0);
	return tmp3;
}
