diff --git a/dlls/pdh/pdh.spec b/dlls/pdh/pdh.spec index 795a45eaee0..8735c0f58b0 100644 --- a/dlls/pdh/pdh.spec +++ b/dlls/pdh/pdh.spec @@ -16,7 +16,7 @@ @ stdcall PdhCloseQuery(ptr) @ stdcall PdhCollectQueryData(ptr) @ stdcall PdhCollectQueryDataWithTime(ptr ptr) -@ stub PdhCollectQueryDataEx +@ stdcall PdhCollectQueryDataEx(ptr long ptr) @ stub PdhComputeCounterStatistics @ stub PdhConnectMachineA @ stub PdhConnectMachineW diff --git a/dlls/pdh/pdh_main.c b/dlls/pdh/pdh_main.c index 8d5c081a202..479fe3b6522 100644 --- a/dlls/pdh/pdh_main.c +++ b/dlls/pdh/pdh_main.c @@ -151,6 +151,10 @@ struct query { DWORD magic; /* signature */ DWORD_PTR user; /* user data */ + HANDLE thread; /* collect thread */ + DWORD interval; /* collect interval */ + HANDLE wait; /* wait event */ + HANDLE stop; /* stop event */ struct list counters; /* counter list */ }; @@ -315,6 +319,18 @@ PDH_STATUS WINAPI PdhAddEnglishCounterW( PDH_HQUERY query, LPCWSTR path, return PdhAddCounterW( query, path, userdata, counter ); } +/* caller must hold query lock */ +static void shutdown_query_thread( struct query *query ) +{ + SetEvent( query->stop ); + WaitForSingleObject( query->thread, INFINITE ); + + CloseHandle( query->stop ); + CloseHandle( query->thread ); + + query->thread = NULL; +} + /*********************************************************************** * PdhCloseQuery (PDH.@) */ @@ -332,6 +348,8 @@ PDH_STATUS WINAPI PdhCloseQuery( PDH_HQUERY handle ) return PDH_INVALID_HANDLE; } + if (query->thread) shutdown_query_thread( query ); + LIST_FOR_EACH_SAFE( item, next, &query->counters ) { struct counter *counter = LIST_ENTRY( item, struct counter, entry ); @@ -391,6 +409,79 @@ PDH_STATUS WINAPI PdhCollectQueryData( PDH_HQUERY handle ) return ERROR_SUCCESS; } +static DWORD CALLBACK collect_query_thread( void *arg ) +{ + struct query *query = arg; + DWORD interval = query->interval; + HANDLE stop = query->stop; + + SetEvent( stop ); + for (;;) + { + if (WaitForSingleObject( stop, interval ) != WAIT_TIMEOUT) ExitThread( 0 ); + + EnterCriticalSection( &pdh_handle_cs ); + if (!query || query->magic != PDH_MAGIC_QUERY) + { + LeaveCriticalSection( &pdh_handle_cs ); + ExitThread( PDH_INVALID_HANDLE ); + } + + collect_query_data( query ); + + if (!SetEvent( query->wait )) + { + LeaveCriticalSection( &pdh_handle_cs ); + ExitThread( 0 ); + } + LeaveCriticalSection( &pdh_handle_cs ); + } +} + +/*********************************************************************** + * PdhCollectQueryDataEx (PDH.@) + */ +PDH_STATUS WINAPI PdhCollectQueryDataEx( PDH_HQUERY handle, DWORD interval, HANDLE event ) +{ + PDH_STATUS ret; + struct query *query = handle; + + TRACE("%p %d %p\n", handle, interval, event); + + EnterCriticalSection( &pdh_handle_cs ); + if (!query || query->magic != PDH_MAGIC_QUERY) + { + LeaveCriticalSection( &pdh_handle_cs ); + return PDH_INVALID_HANDLE; + } + if (list_empty( &query->counters )) + { + LeaveCriticalSection( &pdh_handle_cs ); + return PDH_NO_DATA; + } + if (query->thread) shutdown_query_thread( query ); + if (!(query->stop = CreateEventW( NULL, FALSE, FALSE, NULL ))) + { + ret = GetLastError(); + LeaveCriticalSection( &pdh_handle_cs ); + return ret; + } + query->wait = event; + query->interval = interval * 1000; + if (!(query->thread = CreateThread( NULL, 0, collect_query_thread, query, 0, NULL ))) + { + ret = GetLastError(); + CloseHandle( query->stop ); + + LeaveCriticalSection( &pdh_handle_cs ); + return ret; + } + WaitForSingleObject( query->stop, INFINITE ); + + LeaveCriticalSection( &pdh_handle_cs ); + return ERROR_SUCCESS; +} + /*********************************************************************** * PdhCollectQueryDataWithTime (PDH.@) */ diff --git a/dlls/pdh/tests/pdh.c b/dlls/pdh/tests/pdh.c index 85b08532f2c..2853f8bd61e 100644 --- a/dlls/pdh/tests/pdh.c +++ b/dlls/pdh/tests/pdh.c @@ -797,6 +797,56 @@ static void test_PdhValidatePathExW( void ) ok(ret == ERROR_SUCCESS, "PdhValidatePathExW failed 0x%08x\n", ret); } +static void test_PdhCollectQueryDataEx(void) +{ + PDH_STATUS status; + PDH_HQUERY query; + PDH_HCOUNTER counter; + HANDLE event; + BOOL ret; + UINT i; + + status = PdhOpenQueryA( NULL, 0, &query ); + ok(status == ERROR_SUCCESS, "PdhOpenQuery failed 0x%08x\n", status); + + event = CreateEventA( NULL, FALSE, FALSE, "winetest" ); + ok(event != NULL, "CreateEvent failed\n"); + + status = PdhAddCounterA( query, "\\System\\System Up Time", 0, &counter ); + ok(status == ERROR_SUCCESS, "PdhAddCounterA failed 0x%08x\n", status); + + status = PdhCollectQueryDataEx( NULL, 1, event ); + ok(status == PDH_INVALID_HANDLE, "PdhCollectQueryDataEx failed 0x%08x\n", status); + + status = PdhCollectQueryDataEx( query, 1, NULL ); + ok(status == ERROR_SUCCESS, "PdhCollectQueryDataEx failed 0x%08x\n", status); + + status = PdhCollectQueryDataEx( query, 1, event ); + ok(status == ERROR_SUCCESS, "PdhCollectQueryDataEx failed 0x%08x\n", status); + + status = PdhCollectQueryData( query ); + ok(status == ERROR_SUCCESS, "PdhCollectQueryData failed 0x%08x\n", status); + + for (i = 0; i < 3; i++) + { + if (WaitForSingleObject( event, INFINITE ) == WAIT_OBJECT_0) + { + PDH_FMT_COUNTERVALUE value; + + status = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE, NULL, &value ); + ok(status == ERROR_SUCCESS, "PdhGetFormattedCounterValue failed 0x%08x\n", status); + + trace( "uptime %x%08x\n", (DWORD)(value.largeValue >> 32), (DWORD)value.largeValue ); + } + } + + ret = CloseHandle( event ); + ok(ret, "CloseHandle failed\n"); + + status = PdhCloseQuery( query ); + ok(status == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", status); +} + START_TEST(pdh) { init_function_ptrs(); @@ -830,4 +880,6 @@ START_TEST(pdh) if (pPdhValidatePathExA) test_PdhValidatePathExA(); if (pPdhValidatePathExW) test_PdhValidatePathExW(); + + test_PdhCollectQueryDataEx(); } diff --git a/include/pdh.h b/include/pdh.h index 3aff6db154b..7018247e5bc 100644 --- a/include/pdh.h +++ b/include/pdh.h @@ -173,6 +173,7 @@ PDH_STATUS WINAPI PdhAddEnglishCounterW(PDH_HQUERY, LPCWSTR, DWORD_PTR, PDH_HCOU #define PdhAddEnglishCounter WINELIB_NAME_AW(PdhAddEnglishCounter) PDH_STATUS WINAPI PdhCloseQuery(PDH_HQUERY); PDH_STATUS WINAPI PdhCollectQueryData(PDH_HQUERY); +PDH_STATUS WINAPI PdhCollectQueryDataEx(PDH_HQUERY, DWORD, HANDLE); PDH_STATUS WINAPI PdhCollectQueryDataWithTime(PDH_HQUERY,LONGLONG *); PDH_STATUS WINAPI PdhGetCounterInfoA(PDH_HCOUNTER, BOOLEAN, LPDWORD, PPDH_COUNTER_INFO_A); PDH_STATUS WINAPI PdhGetCounterInfoW(PDH_HCOUNTER, BOOLEAN, LPDWORD, PPDH_COUNTER_INFO_W);