2 * Performance Data Helper (pdh.dll)
4 * Copyright 2007 Andrey Turkin
5 * Copyright 2007 Hans Leidekker
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
34 #include "wine/debug.h"
35 #include "wine/list.h"
36 #include "wine/unicode.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(pdh);
40 static inline void *pdh_alloc( SIZE_T size )
42 return HeapAlloc( GetProcessHeap(), 0, size );
45 static inline void *pdh_alloc_zero( SIZE_T size )
47 return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
50 static inline void pdh_free( LPVOID mem )
52 HeapFree( GetProcessHeap(), 0, mem );
55 static inline WCHAR *pdh_strdup( const WCHAR *src )
59 if (!src) return NULL;
60 if ((dst = pdh_alloc( (strlenW( src ) + 1) * sizeof(WCHAR) ))) strcpyW( dst, src );
64 static inline WCHAR *pdh_strdup_aw( const char *src )
69 if (!src) return NULL;
70 len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 );
71 if ((dst = pdh_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len );
75 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
77 TRACE("(0x%p, %d, %p)\n",hinstDLL,fdwReason,lpvReserved);
79 if (fdwReason == DLL_WINE_PREATTACH) return FALSE; /* prefer native version */
81 if (fdwReason == DLL_PROCESS_ATTACH)
83 DisableThreadLibraryCalls( hinstDLL );
92 WCHAR *path; /* identifier */
93 DWORD type; /* counter type */
94 DWORD status; /* update status */
95 LONG scale; /* scale factor */
96 LONG defaultscale; /* default scale factor */
97 DWORD_PTR user; /* user data */
98 DWORD_PTR queryuser; /* query user data */
99 LONGLONG base; /* samples per second */
100 FILETIME stamp; /* time stamp */
101 void (CALLBACK *collect)( struct counter * ); /* collect callback */
107 } one; /* first value */
113 } two; /* second value */
116 static struct counter *create_counter( void )
118 struct counter *counter;
120 if ((counter = pdh_alloc_zero( sizeof(struct counter) ))) return counter;
124 #define PDH_MAGIC_QUERY 0x50444830 /* 'PDH0' */
128 DWORD magic; /* signature */
129 DWORD_PTR user; /* user data */
130 struct list counters; /* counter list */
133 static struct query *create_query( void )
137 if ((query = pdh_alloc_zero( sizeof(struct query) )))
139 query->magic = PDH_MAGIC_QUERY;
140 list_init( &query->counters );
148 DWORD index; /* name index */
149 const WCHAR *path; /* identifier */
150 void (CALLBACK *collect)( struct counter * ); /* collect callback */
151 DWORD type; /* counter type */
152 LONG scale; /* default scale factor */
153 LONGLONG base; /* samples per second */
156 static const WCHAR path_processor_time[] =
157 {'\\','P','r','o','c','e','s','s','o','r','(','_','T','o','t','a','l',')',
158 '\\','%',' ','P','r','o','c','e','s','s','o','r',' ','T','i','m','e',0};
159 static const WCHAR path_uptime[] =
160 {'\\','S','y','s','t','e','m', '\\', 'S','y','s','t','e','m',' ','U','p',' ','T','i','m','e',0};
162 static void CALLBACK collect_processor_time( struct counter *counter )
164 counter->two.largevalue = 500000; /* FIXME */
165 counter->status = PDH_CSTATUS_VALID_DATA;
168 static void CALLBACK collect_uptime( struct counter *counter )
170 counter->two.largevalue = GetTickCount64();
171 counter->status = PDH_CSTATUS_VALID_DATA;
174 #define TYPE_PROCESSOR_TIME \
175 (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | \
176 PERF_INVERSE_COUNTER | PERF_DISPLAY_PERCENT)
178 #define TYPE_UPTIME \
179 (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_ELAPSED | PERF_OBJECT_TIMER | PERF_DISPLAY_SECONDS)
181 /* counter source registry */
182 static const struct source counter_sources[] =
184 { 6, path_processor_time, collect_processor_time, TYPE_PROCESSOR_TIME, -5, 10000000 },
185 { 674, path_uptime, collect_uptime, TYPE_UPTIME, -3, 1000 }
188 static BOOL pdh_match_path( LPCWSTR fullpath, LPCWSTR path )
192 if (strchrW( path, '\\')) p = fullpath;
193 else p = strrchrW( fullpath, '\\' ) + 1;
194 if (strcmpW( p, path )) return FALSE;
198 /***********************************************************************
199 * PdhAddCounterA (PDH.@)
201 PDH_STATUS WINAPI PdhAddCounterA( PDH_HQUERY query, LPCSTR path,
202 DWORD_PTR userdata, PDH_HCOUNTER *counter )
207 TRACE("%p %s %lx %p\n", query, debugstr_a(path), userdata, counter);
209 if (!path) return PDH_INVALID_ARGUMENT;
211 if (!(pathW = pdh_strdup_aw( path )))
212 return PDH_MEMORY_ALLOCATION_FAILURE;
214 ret = PdhAddCounterW( query, pathW, userdata, counter );
220 /***********************************************************************
221 * PdhAddCounterW (PDH.@)
223 PDH_STATUS WINAPI PdhAddCounterW( PDH_HQUERY hquery, LPCWSTR path,
224 DWORD_PTR userdata, PDH_HCOUNTER *hcounter )
226 struct query *query = hquery;
227 struct counter *counter;
230 TRACE("%p %s %lx %p\n", hquery, debugstr_w(path), userdata, hcounter);
232 if (!path || !hcounter) return PDH_INVALID_ARGUMENT;
233 if (!query || (query->magic != PDH_MAGIC_QUERY)) return PDH_INVALID_HANDLE;
236 for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
238 if (pdh_match_path( counter_sources[i].path, path ))
240 if ((counter = create_counter()))
242 counter->path = pdh_strdup( counter_sources[i].path );
243 counter->collect = counter_sources[i].collect;
244 counter->type = counter_sources[i].type;
245 counter->defaultscale = counter_sources[i].scale;
246 counter->base = counter_sources[i].base;
247 counter->queryuser = query->user;
248 counter->user = userdata;
250 list_add_tail( &query->counters, &counter->entry );
253 return ERROR_SUCCESS;
255 return PDH_MEMORY_ALLOCATION_FAILURE;
258 return PDH_CSTATUS_NO_COUNTER;
261 /***********************************************************************
262 * PdhAddEnglishCounterA (PDH.@)
264 PDH_STATUS WINAPI PdhAddEnglishCounterA( PDH_HQUERY query, LPCSTR path,
265 DWORD_PTR userdata, PDH_HCOUNTER *counter )
267 return PdhAddCounterA( query, path, userdata, counter );
270 /***********************************************************************
271 * PdhAddEnglishCounterW (PDH.@)
273 PDH_STATUS WINAPI PdhAddEnglishCounterW( PDH_HQUERY query, LPCWSTR path,
274 DWORD_PTR userdata, PDH_HCOUNTER *counter )
276 return PdhAddCounterW( query, path, userdata, counter );
279 /***********************************************************************
280 * PdhCloseQuery (PDH.@)
282 PDH_STATUS WINAPI PdhCloseQuery( PDH_HQUERY handle )
284 struct query *query = handle;
285 struct list *item, *next;
287 TRACE("%p\n", handle);
289 if (!query || (query->magic != PDH_MAGIC_QUERY)) return PDH_INVALID_HANDLE;
291 LIST_FOR_EACH_SAFE( item, next, &query->counters )
293 struct counter *counter = LIST_ENTRY( item, struct counter, entry );
295 list_remove( &counter->entry );
297 pdh_free( counter->path );
304 return ERROR_SUCCESS;
307 /***********************************************************************
308 * PdhCollectQueryData (PDH.@)
310 PDH_STATUS WINAPI PdhCollectQueryData( PDH_HQUERY handle )
312 struct query *query = handle;
315 TRACE("%p\n", handle);
317 if (!query || (query->magic != PDH_MAGIC_QUERY)) return PDH_INVALID_HANDLE;
319 LIST_FOR_EACH( item, &query->counters )
322 struct counter *counter = LIST_ENTRY( item, struct counter, entry );
324 counter->collect( counter );
326 GetLocalTime( &time );
327 SystemTimeToFileTime( &time, &counter->stamp );
329 return ERROR_SUCCESS;
332 /***********************************************************************
333 * PdhCollectQueryDataWithTime (PDH.@)
335 PDH_STATUS WINAPI PdhCollectQueryDataWithTime( PDH_HQUERY handle, LONGLONG *timestamp )
338 struct query *query = handle;
340 TRACE("%p %p\n", handle, timestamp);
342 if (!query || (query->magic != PDH_MAGIC_QUERY)) return PDH_INVALID_HANDLE;
344 if (list_empty( &query->counters )) return PDH_NO_DATA;
346 ret = PdhCollectQueryData( query );
347 if (!ret && timestamp)
349 struct list *item = list_head( &query->counters );
350 struct counter *counter = LIST_ENTRY( item, struct counter, entry );
352 *timestamp = ((LONGLONG)counter->stamp.dwHighDateTime << 32) | counter->stamp.dwLowDateTime;
357 /***********************************************************************
358 * PdhGetCounterInfoA (PDH.@)
360 PDH_STATUS WINAPI PdhGetCounterInfoA( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_A info )
362 struct counter *counter = handle;
364 TRACE("%p %d %p %p\n", handle, text, size, info);
366 if (!counter) return PDH_INVALID_HANDLE;
367 if (!size) return PDH_INVALID_ARGUMENT;
369 if (*size < sizeof(PDH_COUNTER_INFO_A))
371 *size = sizeof(PDH_COUNTER_INFO_A);
372 return PDH_MORE_DATA;
375 memset( info, 0, sizeof(PDH_COUNTER_INFO_A) );
377 info->dwType = counter->type;
378 info->CStatus = counter->status;
379 info->lScale = counter->scale;
380 info->lDefaultScale = counter->defaultscale;
381 info->dwUserData = counter->user;
382 info->dwQueryUserData = counter->queryuser;
384 *size = sizeof(PDH_COUNTER_INFO_A);
385 return ERROR_SUCCESS;
388 /***********************************************************************
389 * PdhGetCounterInfoW (PDH.@)
391 PDH_STATUS WINAPI PdhGetCounterInfoW( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_W info )
393 struct counter *counter = handle;
395 TRACE("%p %d %p %p\n", handle, text, size, info);
397 if (!counter) return PDH_INVALID_HANDLE;
398 if (!size) return PDH_INVALID_ARGUMENT;
400 if (*size < sizeof(PDH_COUNTER_INFO_W))
402 *size = sizeof(PDH_COUNTER_INFO_W);
403 return PDH_MORE_DATA;
406 memset( info, 0, sizeof(PDH_COUNTER_INFO_W) );
408 info->dwType = counter->type;
409 info->CStatus = counter->status;
410 info->lScale = counter->scale;
411 info->lDefaultScale = counter->defaultscale;
412 info->dwUserData = counter->user;
413 info->dwQueryUserData = counter->queryuser;
415 *size = sizeof(PDH_COUNTER_INFO_W);
416 return ERROR_SUCCESS;
419 /***********************************************************************
420 * PdhGetCounterTimeBase (PDH.@)
422 PDH_STATUS WINAPI PdhGetCounterTimeBase( PDH_HCOUNTER handle, LONGLONG *base )
424 struct counter *counter = handle;
426 TRACE("%p %p\n", handle, base);
428 if (!base) return PDH_INVALID_ARGUMENT;
429 if (!counter) return PDH_INVALID_HANDLE;
431 *base = counter->base;
432 return ERROR_SUCCESS;
435 /***********************************************************************
436 * PdhGetFormattedCounterValue (PDH.@)
438 PDH_STATUS WINAPI PdhGetFormattedCounterValue( PDH_HCOUNTER handle, DWORD format,
439 LPDWORD type, PPDH_FMT_COUNTERVALUE value )
442 struct counter *counter = handle;
444 TRACE("%p %x %p %p\n", handle, format, type, value);
446 if (!value) return PDH_INVALID_ARGUMENT;
447 if (!counter) return PDH_INVALID_HANDLE;
449 if (counter->status) return PDH_INVALID_DATA;
451 factor = counter->scale ? counter->scale : counter->defaultscale;
452 if (format & PDH_FMT_LONG)
454 if (format & PDH_FMT_1000) value->u.longValue = counter->two.longvalue * 1000;
455 else value->u.longValue = counter->two.longvalue * pow( 10, factor );
457 else if (format & PDH_FMT_LARGE)
459 if (format & PDH_FMT_1000) value->u.largeValue = counter->two.largevalue * 1000;
460 else value->u.largeValue = counter->two.largevalue * pow( 10, factor );
462 else if (format & PDH_FMT_DOUBLE)
464 if (format & PDH_FMT_1000) value->u.doubleValue = counter->two.doublevalue * 1000;
465 else value->u.doubleValue = counter->two.doublevalue * pow( 10, factor );
469 WARN("unknown format %x\n", format);
470 return PDH_INVALID_ARGUMENT;
472 value->CStatus = ERROR_SUCCESS;
474 if (type) *type = counter->type;
475 return ERROR_SUCCESS;
478 /***********************************************************************
479 * PdhGetRawCounterValue (PDH.@)
481 PDH_STATUS WINAPI PdhGetRawCounterValue( PDH_HCOUNTER handle, LPDWORD type,
482 PPDH_RAW_COUNTER value )
484 struct counter *counter = handle;
486 TRACE("%p %p %p\n", handle, type, value);
488 if (!value) return PDH_INVALID_ARGUMENT;
489 if (!counter) return PDH_INVALID_HANDLE;
491 value->CStatus = counter->status;
492 value->TimeStamp.dwLowDateTime = counter->stamp.dwLowDateTime;
493 value->TimeStamp.dwHighDateTime = counter->stamp.dwHighDateTime;
494 value->FirstValue = counter->one.largevalue;
495 value->SecondValue = counter->two.largevalue;
496 value->MultiCount = 1; /* FIXME */
498 if (type) *type = counter->type;
499 return ERROR_SUCCESS;
502 /***********************************************************************
503 * PdhLookupPerfIndexByNameA (PDH.@)
505 PDH_STATUS WINAPI PdhLookupPerfIndexByNameA( LPCSTR machine, LPCSTR name, LPDWORD index )
510 TRACE("%s %s %p\n", debugstr_a(machine), debugstr_a(name), index);
512 if (!name || !index) return PDH_INVALID_ARGUMENT;
516 FIXME("remote machine not supported\n");
517 return PDH_CSTATUS_NO_MACHINE;
519 if (!(nameW = pdh_strdup_aw( name )))
520 return PDH_MEMORY_ALLOCATION_FAILURE;
522 ret = PdhLookupPerfIndexByNameW( NULL, nameW, index );
528 /***********************************************************************
529 * PdhLookupPerfIndexByNameW (PDH.@)
531 PDH_STATUS WINAPI PdhLookupPerfIndexByNameW( LPCWSTR machine, LPCWSTR name, LPDWORD index )
535 TRACE("%s %s %p\n", debugstr_w(machine), debugstr_w(name), index);
537 if (!name || !index) return PDH_INVALID_ARGUMENT;
541 FIXME("remote machine not supported\n");
542 return PDH_CSTATUS_NO_MACHINE;
544 for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
546 if (pdh_match_path( counter_sources[i].path, name ))
548 *index = counter_sources[i].index;
549 return ERROR_SUCCESS;
552 return PDH_STRING_NOT_FOUND;
555 /***********************************************************************
556 * PdhLookupPerfNameByIndexA (PDH.@)
558 PDH_STATUS WINAPI PdhLookupPerfNameByIndexA( LPCSTR machine, DWORD index, LPSTR buffer, LPDWORD size )
561 WCHAR bufferW[PDH_MAX_COUNTER_NAME];
562 DWORD sizeW = sizeof(bufferW) / sizeof(WCHAR);
564 TRACE("%s %d %p %p\n", debugstr_a(machine), index, buffer, size);
568 FIXME("remote machine not supported\n");
569 return PDH_CSTATUS_NO_MACHINE;
572 if (!buffer && !size) return PDH_INVALID_ARGUMENT;
573 if (!index) return ERROR_SUCCESS;
575 if (!(ret = PdhLookupPerfNameByIndexW( NULL, index, bufferW, &sizeW )))
577 int required = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
579 if (size && *size < required) ret = PDH_MORE_DATA;
580 else WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, required, NULL, NULL );
581 if (size) *size = required;
586 /***********************************************************************
587 * PdhLookupPerfNameByIndexW (PDH.@)
589 PDH_STATUS WINAPI PdhLookupPerfNameByIndexW( LPCWSTR machine, DWORD index, LPWSTR buffer, LPDWORD size )
594 TRACE("%s %d %p %p\n", debugstr_w(machine), index, buffer, size);
598 FIXME("remote machine not supported\n");
599 return PDH_CSTATUS_NO_MACHINE;
602 if (!buffer && !size) return PDH_INVALID_ARGUMENT;
603 if (!index) return ERROR_SUCCESS;
605 for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
607 if (counter_sources[i].index == index)
609 WCHAR *p = strrchrW( counter_sources[i].path, '\\' ) + 1;
610 unsigned int required = strlenW( p ) + 1;
612 if (*size < required) ret = PDH_MORE_DATA;
615 strcpyW( buffer, p );
622 return PDH_INVALID_ARGUMENT;
625 /***********************************************************************
626 * PdhOpenQueryA (PDH.@)
628 PDH_STATUS WINAPI PdhOpenQueryA( LPCSTR source, DWORD_PTR userdata, PDH_HQUERY *query )
631 WCHAR *sourceW = NULL;
633 TRACE("%s %lx %p\n", debugstr_a(source), userdata, query);
635 if (source && !(sourceW = pdh_strdup_aw( source ))) return PDH_MEMORY_ALLOCATION_FAILURE;
637 ret = PdhOpenQueryW( sourceW, userdata, query );
643 /***********************************************************************
644 * PdhOpenQueryW (PDH.@)
646 PDH_STATUS WINAPI PdhOpenQueryW( LPCWSTR source, DWORD_PTR userdata, PDH_HQUERY *handle )
650 TRACE("%s %lx %p\n", debugstr_w(source), userdata, handle);
652 if (!handle) return PDH_INVALID_ARGUMENT;
656 FIXME("log file data source not supported\n");
657 return PDH_INVALID_ARGUMENT;
659 if ((query = create_query()))
661 query->user = userdata;
664 return ERROR_SUCCESS;
666 return PDH_MEMORY_ALLOCATION_FAILURE;
669 /***********************************************************************
670 * PdhRemoveCounter (PDH.@)
672 PDH_STATUS WINAPI PdhRemoveCounter( PDH_HCOUNTER handle )
674 struct counter *counter = handle;
676 TRACE("%p\n", handle);
678 if (!counter) return PDH_INVALID_HANDLE;
680 list_remove( &counter->entry );
682 pdh_free( counter->path );
685 return ERROR_SUCCESS;
688 /***********************************************************************
689 * PdhSetCounterScaleFactor (PDH.@)
691 PDH_STATUS WINAPI PdhSetCounterScaleFactor( PDH_HCOUNTER handle, LONG factor )
693 struct counter *counter = handle;
695 TRACE("%p\n", handle);
697 if (!counter) return PDH_INVALID_HANDLE;
698 if (factor < PDH_MIN_SCALE || factor > PDH_MAX_SCALE) return PDH_INVALID_ARGUMENT;
700 counter->scale = factor;
701 return ERROR_SUCCESS;