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
;