winealsa: Don't use default:XX to open up a hardware control.
[wine] / dlls / pdh / pdh_main.c
1 /*
2  * Performance Data Helper (pdh.dll)
3  *
4  * Copyright 2007 Andrey Turkin
5  * Copyright 2007 Hans Leidekker
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <stdarg.h>
23 #include <math.h>
24
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include "windef.h"
28 #include "winbase.h"
29
30 #include "pdh.h"
31 #include "pdhmsg.h"
32 #include "winperf.h"
33
34 #include "wine/debug.h"
35 #include "wine/list.h"
36 #include "wine/unicode.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(pdh);
39
40 static CRITICAL_SECTION pdh_handle_cs;
41 static CRITICAL_SECTION_DEBUG pdh_handle_cs_debug =
42 {
43     0, 0, &pdh_handle_cs,
44     { &pdh_handle_cs_debug.ProcessLocksList,
45       &pdh_handle_cs_debug.ProcessLocksList },
46       0, 0, { (DWORD_PTR)(__FILE__ ": pdh_handle_cs") }
47 };
48 static CRITICAL_SECTION pdh_handle_cs = { &pdh_handle_cs_debug, -1, 0, 0, 0, 0 };
49
50 static inline void *pdh_alloc( SIZE_T size )
51 {
52     return HeapAlloc( GetProcessHeap(), 0, size );
53 }
54
55 static inline void *pdh_alloc_zero( SIZE_T size )
56 {
57     return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
58 }
59
60 static inline void pdh_free( LPVOID mem )
61 {
62     HeapFree( GetProcessHeap(), 0, mem );
63 }
64
65 static inline WCHAR *pdh_strdup( const WCHAR *src )
66 {
67     WCHAR *dst;
68
69     if (!src) return NULL;
70     if ((dst = pdh_alloc( (strlenW( src ) + 1) * sizeof(WCHAR) ))) strcpyW( dst, src );
71     return dst;
72 }
73
74 static inline WCHAR *pdh_strdup_aw( const char *src )
75 {
76     int len;
77     WCHAR *dst;
78
79     if (!src) return NULL;
80     len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 );
81     if ((dst = pdh_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len );
82     return dst;
83 }
84
85 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
86 {
87     TRACE("(0x%p, %d, %p)\n",hinstDLL,fdwReason,lpvReserved);
88
89     if (fdwReason == DLL_WINE_PREATTACH) return FALSE;    /* prefer native version */
90
91     if (fdwReason == DLL_PROCESS_ATTACH)
92     {
93         DisableThreadLibraryCalls( hinstDLL );
94     }
95
96     return TRUE;
97 }
98
99 union value
100 {
101     LONG     longvalue;
102     double   doublevalue;
103     LONGLONG largevalue;
104 };
105
106 struct counter
107 {
108     DWORD           magic;                          /* signature */
109     struct list     entry;                          /* list entry */
110     WCHAR          *path;                           /* identifier */
111     DWORD           type;                           /* counter type */
112     DWORD           status;                         /* update status */
113     LONG            scale;                          /* scale factor */
114     LONG            defaultscale;                   /* default scale factor */
115     DWORD_PTR       user;                           /* user data */
116     DWORD_PTR       queryuser;                      /* query user data */
117     LONGLONG        base;                           /* samples per second */
118     FILETIME        stamp;                          /* time stamp */
119     void (CALLBACK *collect)( struct counter * );   /* collect callback */
120     union value     one;                            /* first value */
121     union value     two;                            /* second value */
122 };
123
124 #define PDH_MAGIC_COUNTER   0x50444831 /* 'PDH1' */
125
126 static struct counter *create_counter( void )
127 {
128     struct counter *counter;
129
130     if ((counter = pdh_alloc_zero( sizeof(struct counter) )))
131     {
132         counter->magic = PDH_MAGIC_COUNTER;
133         return counter;
134     }
135     return NULL;
136 }
137
138 static void destroy_counter( struct counter *counter )
139 {
140     counter->magic = 0;
141     pdh_free( counter->path );
142     pdh_free( counter );
143 }
144
145 #define PDH_MAGIC_QUERY     0x50444830 /* 'PDH0' */
146
147 struct query
148 {
149     DWORD       magic;      /* signature */
150     DWORD_PTR   user;       /* user data */
151     HANDLE      thread;     /* collect thread */
152     DWORD       interval;   /* collect interval */
153     HANDLE      wait;       /* wait event */
154     HANDLE      stop;       /* stop event */
155     struct list counters;   /* counter list */
156 };
157
158 static struct query *create_query( void )
159 {
160     struct query *query;
161
162     if ((query = pdh_alloc_zero( sizeof(struct query) )))
163     {
164         query->magic = PDH_MAGIC_QUERY;
165         list_init( &query->counters );
166         return query;
167     }
168     return NULL;
169 }
170
171 static void destroy_query( struct query *query )
172 {
173     query->magic = 0;
174     pdh_free( query );
175 }
176
177 struct source
178 {
179     DWORD           index;                          /* name index */
180     const WCHAR    *path;                           /* identifier */
181     void (CALLBACK *collect)( struct counter * );   /* collect callback */
182     DWORD           type;                           /* counter type */
183     LONG            scale;                          /* default scale factor */
184     LONGLONG        base;                           /* samples per second */
185 };
186
187 static const WCHAR path_processor_time[] =
188     {'\\','P','r','o','c','e','s','s','o','r','(','_','T','o','t','a','l',')',
189      '\\','%',' ','P','r','o','c','e','s','s','o','r',' ','T','i','m','e',0};
190 static const WCHAR path_uptime[] =
191     {'\\','S','y','s','t','e','m', '\\', 'S','y','s','t','e','m',' ','U','p',' ','T','i','m','e',0};
192
193 static void CALLBACK collect_processor_time( struct counter *counter )
194 {
195     counter->two.largevalue = 500000; /* FIXME */
196     counter->status = PDH_CSTATUS_VALID_DATA;
197 }
198
199 static void CALLBACK collect_uptime( struct counter *counter )
200 {
201     counter->two.largevalue = GetTickCount64();
202     counter->status = PDH_CSTATUS_VALID_DATA;
203 }
204
205 #define TYPE_PROCESSOR_TIME \
206     (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | \
207      PERF_INVERSE_COUNTER | PERF_DISPLAY_PERCENT)
208
209 #define TYPE_UPTIME \
210     (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_ELAPSED | PERF_OBJECT_TIMER | PERF_DISPLAY_SECONDS)
211
212 /* counter source registry */
213 static const struct source counter_sources[] =
214 {
215     { 6,    path_processor_time,    collect_processor_time,     TYPE_PROCESSOR_TIME,    -5,     10000000 },
216     { 674,  path_uptime,            collect_uptime,             TYPE_UPTIME,            -3,     1000 }
217 };
218
219 static BOOL pdh_match_path( LPCWSTR fullpath, LPCWSTR path )
220 {
221     const WCHAR *p;
222
223     if (strchrW( path, '\\')) p = fullpath;
224     else p = strrchrW( fullpath, '\\' ) + 1;
225     if (strcmpW( p, path )) return FALSE;
226     return TRUE;
227 }
228
229 /***********************************************************************
230  *              PdhAddCounterA   (PDH.@)
231  */
232 PDH_STATUS WINAPI PdhAddCounterA( PDH_HQUERY query, LPCSTR path,
233                                   DWORD_PTR userdata, PDH_HCOUNTER *counter )
234 {
235     PDH_STATUS ret;
236     WCHAR *pathW;
237
238     TRACE("%p %s %lx %p\n", query, debugstr_a(path), userdata, counter);
239
240     if (!path) return PDH_INVALID_ARGUMENT;
241
242     if (!(pathW = pdh_strdup_aw( path )))
243         return PDH_MEMORY_ALLOCATION_FAILURE;
244
245     ret = PdhAddCounterW( query, pathW, userdata, counter );
246
247     pdh_free( pathW );
248     return ret;
249 }
250
251 /***********************************************************************
252  *              PdhAddCounterW   (PDH.@)
253  */
254 PDH_STATUS WINAPI PdhAddCounterW( PDH_HQUERY hquery, LPCWSTR path,
255                                   DWORD_PTR userdata, PDH_HCOUNTER *hcounter )
256 {
257     struct query *query = hquery;
258     struct counter *counter;
259     unsigned int i;
260
261     TRACE("%p %s %lx %p\n", hquery, debugstr_w(path), userdata, hcounter);
262
263     if (!path  || !hcounter) return PDH_INVALID_ARGUMENT;
264
265     EnterCriticalSection( &pdh_handle_cs );
266     if (!query || query->magic != PDH_MAGIC_QUERY)
267     {
268         LeaveCriticalSection( &pdh_handle_cs );
269         return PDH_INVALID_HANDLE;
270     }
271
272     *hcounter = NULL;
273     for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
274     {
275         if (pdh_match_path( counter_sources[i].path, path ))
276         {
277             if ((counter = create_counter()))
278             {
279                 counter->path         = pdh_strdup( counter_sources[i].path );
280                 counter->collect      = counter_sources[i].collect;
281                 counter->type         = counter_sources[i].type;
282                 counter->defaultscale = counter_sources[i].scale;
283                 counter->base         = counter_sources[i].base;
284                 counter->queryuser    = query->user;
285                 counter->user         = userdata;
286
287                 list_add_tail( &query->counters, &counter->entry );
288                 *hcounter = counter;
289
290                 LeaveCriticalSection( &pdh_handle_cs );
291                 return ERROR_SUCCESS;
292             }
293             LeaveCriticalSection( &pdh_handle_cs );
294             return PDH_MEMORY_ALLOCATION_FAILURE;
295         }
296     }
297     LeaveCriticalSection( &pdh_handle_cs );
298     return PDH_CSTATUS_NO_COUNTER;
299 }
300
301 /***********************************************************************
302  *              PdhAddEnglishCounterA   (PDH.@)
303  */
304 PDH_STATUS WINAPI PdhAddEnglishCounterA( PDH_HQUERY query, LPCSTR path,
305                                          DWORD_PTR userdata, PDH_HCOUNTER *counter )
306 {
307     TRACE("%p %s %lx %p\n", query, debugstr_a(path), userdata, counter);
308
309     if (!query) return PDH_INVALID_ARGUMENT;
310     return PdhAddCounterA( query, path, userdata, counter );
311 }
312
313 /***********************************************************************
314  *              PdhAddEnglishCounterW   (PDH.@)
315  */
316 PDH_STATUS WINAPI PdhAddEnglishCounterW( PDH_HQUERY query, LPCWSTR path,
317                                          DWORD_PTR userdata, PDH_HCOUNTER *counter )
318 {
319     TRACE("%p %s %lx %p\n", query, debugstr_w(path), userdata, counter);
320
321     if (!query) return PDH_INVALID_ARGUMENT;
322     return PdhAddCounterW( query, path, userdata, counter );
323 }
324
325 /* caller must hold counter lock */
326 static PDH_STATUS format_value( struct counter *counter, DWORD format, union value *raw1,
327                                 union value *raw2, PDH_FMT_COUNTERVALUE *value )
328 {
329     LONG factor;
330
331     factor = counter->scale ? counter->scale : counter->defaultscale;
332     if (format & PDH_FMT_LONG)
333     {
334         if (format & PDH_FMT_1000) value->u.longValue = raw2->longvalue * 1000;
335         else value->u.longValue = raw2->longvalue * pow( 10, factor );
336     }
337     else if (format & PDH_FMT_LARGE)
338     {
339         if (format & PDH_FMT_1000) value->u.largeValue = raw2->largevalue * 1000;
340         else value->u.largeValue = raw2->largevalue * pow( 10, factor );
341     }
342     else if (format & PDH_FMT_DOUBLE)
343     {
344         if (format & PDH_FMT_1000) value->u.doubleValue = raw2->doublevalue * 1000;
345         else value->u.doubleValue = raw2->doublevalue * pow( 10, factor );
346     }
347     else
348     {
349         WARN("unknown format %x\n", format);
350         return PDH_INVALID_ARGUMENT;
351     }
352     return ERROR_SUCCESS;
353 }
354
355 /***********************************************************************
356  *              PdhCalculateCounterFromRawValue   (PDH.@)
357  */
358 PDH_STATUS WINAPI PdhCalculateCounterFromRawValue( PDH_HCOUNTER handle, DWORD format,
359                                                    PPDH_RAW_COUNTER raw1, PPDH_RAW_COUNTER raw2,
360                                                    PPDH_FMT_COUNTERVALUE value )
361 {
362     PDH_STATUS ret;
363     struct counter *counter = handle;
364
365     TRACE("%p 0x%08x %p %p %p\n", handle, format, raw1, raw2, value);
366
367     if (!value) return PDH_INVALID_ARGUMENT;
368
369     EnterCriticalSection( &pdh_handle_cs );
370     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
371     {
372         LeaveCriticalSection( &pdh_handle_cs );
373         return PDH_INVALID_HANDLE;
374     }
375
376     ret = format_value( counter, format, (union value *)&raw1->SecondValue,
377                                          (union value *)&raw2->SecondValue, value );
378
379     LeaveCriticalSection( &pdh_handle_cs );
380     return ret;
381 }
382
383 /* caller must hold query lock */
384 static void shutdown_query_thread( struct query *query )
385 {
386     SetEvent( query->stop );
387     WaitForSingleObject( query->thread, INFINITE );
388
389     CloseHandle( query->stop );
390     CloseHandle( query->thread );
391
392     query->thread = NULL;
393 }
394
395 /***********************************************************************
396  *              PdhCloseQuery   (PDH.@)
397  */
398 PDH_STATUS WINAPI PdhCloseQuery( PDH_HQUERY handle )
399 {
400     struct query *query = handle;
401     struct list *item, *next;
402
403     TRACE("%p\n", handle);
404
405     EnterCriticalSection( &pdh_handle_cs );
406     if (!query || query->magic != PDH_MAGIC_QUERY)
407     {
408         LeaveCriticalSection( &pdh_handle_cs );
409         return PDH_INVALID_HANDLE;
410     }
411
412     if (query->thread) shutdown_query_thread( query );
413
414     LIST_FOR_EACH_SAFE( item, next, &query->counters )
415     {
416         struct counter *counter = LIST_ENTRY( item, struct counter, entry );
417
418         list_remove( &counter->entry );
419         destroy_counter( counter );
420     }
421
422     destroy_query( query );
423
424     LeaveCriticalSection( &pdh_handle_cs );
425     return ERROR_SUCCESS;
426 }
427
428 /* caller must hold query lock */
429 static void collect_query_data( struct query *query )
430 {
431     struct list *item;
432
433     LIST_FOR_EACH( item, &query->counters )
434     {
435         SYSTEMTIME time;
436         struct counter *counter = LIST_ENTRY( item, struct counter, entry );
437
438         counter->collect( counter );
439
440         GetLocalTime( &time );
441         SystemTimeToFileTime( &time, &counter->stamp );
442     }
443 }
444
445 /***********************************************************************
446  *              PdhCollectQueryData   (PDH.@)
447  */
448 PDH_STATUS WINAPI PdhCollectQueryData( PDH_HQUERY handle )
449 {
450     struct query *query = handle;
451
452     TRACE("%p\n", handle);
453
454     EnterCriticalSection( &pdh_handle_cs );
455     if (!query || query->magic != PDH_MAGIC_QUERY)
456     {
457         LeaveCriticalSection( &pdh_handle_cs );
458         return PDH_INVALID_HANDLE;
459     }
460
461     if (list_empty( &query->counters ))
462     {
463         LeaveCriticalSection( &pdh_handle_cs );
464         return PDH_NO_DATA;
465     }
466
467     collect_query_data( query );
468
469     LeaveCriticalSection( &pdh_handle_cs );
470     return ERROR_SUCCESS;
471 }
472
473 static DWORD CALLBACK collect_query_thread( void *arg )
474 {
475     struct query *query = arg;
476     DWORD interval = query->interval;
477     HANDLE stop = query->stop;
478
479     SetEvent( stop );
480     for (;;)
481     {
482         if (WaitForSingleObject( stop, interval ) != WAIT_TIMEOUT) ExitThread( 0 );
483
484         EnterCriticalSection( &pdh_handle_cs );
485         if (query->magic != PDH_MAGIC_QUERY)
486         {
487             LeaveCriticalSection( &pdh_handle_cs );
488             ExitThread( PDH_INVALID_HANDLE );
489         }
490
491         collect_query_data( query );
492
493         if (!SetEvent( query->wait ))
494         {
495             LeaveCriticalSection( &pdh_handle_cs );
496             ExitThread( 0 );
497         }
498         LeaveCriticalSection( &pdh_handle_cs );
499     }
500 }
501
502 /***********************************************************************
503  *              PdhCollectQueryDataEx   (PDH.@)
504  */
505 PDH_STATUS WINAPI PdhCollectQueryDataEx( PDH_HQUERY handle, DWORD interval, HANDLE event )
506 {
507     PDH_STATUS ret;
508     struct query *query = handle;
509
510     TRACE("%p %d %p\n", handle, interval, event);
511
512     EnterCriticalSection( &pdh_handle_cs );
513     if (!query || query->magic != PDH_MAGIC_QUERY)
514     {
515         LeaveCriticalSection( &pdh_handle_cs );
516         return PDH_INVALID_HANDLE;
517     }
518     if (list_empty( &query->counters ))
519     {
520         LeaveCriticalSection( &pdh_handle_cs );
521         return PDH_NO_DATA;
522     }
523     if (query->thread) shutdown_query_thread( query );
524     if (!(query->stop = CreateEventW( NULL, FALSE, FALSE, NULL )))
525     {
526         ret = GetLastError();
527         LeaveCriticalSection( &pdh_handle_cs );
528         return ret;
529     }
530     query->wait = event;
531     query->interval = interval * 1000;
532     if (!(query->thread = CreateThread( NULL, 0, collect_query_thread, query, 0, NULL )))
533     {
534         ret = GetLastError();
535         CloseHandle( query->stop );
536
537         LeaveCriticalSection( &pdh_handle_cs );
538         return ret;
539     }
540     WaitForSingleObject( query->stop, INFINITE );
541
542     LeaveCriticalSection( &pdh_handle_cs );
543     return ERROR_SUCCESS;
544 }
545
546 /***********************************************************************
547  *              PdhCollectQueryDataWithTime   (PDH.@)
548  */
549 PDH_STATUS WINAPI PdhCollectQueryDataWithTime( PDH_HQUERY handle, LONGLONG *timestamp )
550 {
551     struct query *query = handle;
552     struct counter *counter;
553     struct list *item;
554
555     TRACE("%p %p\n", handle, timestamp);
556
557     if (!timestamp) return PDH_INVALID_ARGUMENT;
558
559     EnterCriticalSection( &pdh_handle_cs );
560     if (!query || query->magic != PDH_MAGIC_QUERY)
561     {
562         LeaveCriticalSection( &pdh_handle_cs );
563         return PDH_INVALID_HANDLE;
564     }
565     if (list_empty( &query->counters ))
566     {
567         LeaveCriticalSection( &pdh_handle_cs );
568         return PDH_NO_DATA;
569     }
570
571     collect_query_data( query );
572
573     item = list_head( &query->counters );
574     counter = LIST_ENTRY( item, struct counter, entry );
575
576     *timestamp = ((LONGLONG)counter->stamp.dwHighDateTime << 32) | counter->stamp.dwLowDateTime;
577
578     LeaveCriticalSection( &pdh_handle_cs );
579     return ERROR_SUCCESS;
580 }
581
582 /***********************************************************************
583  *              PdhGetCounterInfoA   (PDH.@)
584  */
585 PDH_STATUS WINAPI PdhGetCounterInfoA( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_A info )
586 {
587     struct counter *counter = handle;
588
589     TRACE("%p %d %p %p\n", handle, text, size, info);
590
591     EnterCriticalSection( &pdh_handle_cs );
592     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
593     {
594         LeaveCriticalSection( &pdh_handle_cs );
595         return PDH_INVALID_HANDLE;
596     }
597     if (!size)
598     {
599         LeaveCriticalSection( &pdh_handle_cs );
600         return PDH_INVALID_ARGUMENT;
601     }
602     if (*size < sizeof(PDH_COUNTER_INFO_A))
603     {
604         *size = sizeof(PDH_COUNTER_INFO_A);
605         LeaveCriticalSection( &pdh_handle_cs );
606         return PDH_MORE_DATA;
607     }
608
609     memset( info, 0, sizeof(PDH_COUNTER_INFO_A) );
610
611     info->dwType          = counter->type;
612     info->CStatus         = counter->status;
613     info->lScale          = counter->scale;
614     info->lDefaultScale   = counter->defaultscale;
615     info->dwUserData      = counter->user;
616     info->dwQueryUserData = counter->queryuser;
617
618     *size = sizeof(PDH_COUNTER_INFO_A);
619
620     LeaveCriticalSection( &pdh_handle_cs );
621     return ERROR_SUCCESS;
622 }
623
624 /***********************************************************************
625  *              PdhGetCounterInfoW   (PDH.@)
626  */
627 PDH_STATUS WINAPI PdhGetCounterInfoW( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_W info )
628 {
629     struct counter *counter = handle;
630
631     TRACE("%p %d %p %p\n", handle, text, size, info);
632
633     EnterCriticalSection( &pdh_handle_cs );
634     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
635     {
636         LeaveCriticalSection( &pdh_handle_cs );
637         return PDH_INVALID_HANDLE;
638     }
639     if (!size)
640     {
641         LeaveCriticalSection( &pdh_handle_cs );
642         return PDH_INVALID_ARGUMENT;
643     }
644     if (*size < sizeof(PDH_COUNTER_INFO_W))
645     {
646         *size = sizeof(PDH_COUNTER_INFO_W);
647         LeaveCriticalSection( &pdh_handle_cs );
648         return PDH_MORE_DATA;
649     }
650
651     memset( info, 0, sizeof(PDH_COUNTER_INFO_W) );
652
653     info->dwType          = counter->type;
654     info->CStatus         = counter->status;
655     info->lScale          = counter->scale;
656     info->lDefaultScale   = counter->defaultscale;
657     info->dwUserData      = counter->user;
658     info->dwQueryUserData = counter->queryuser;
659
660     *size = sizeof(PDH_COUNTER_INFO_W);
661
662     LeaveCriticalSection( &pdh_handle_cs );
663     return ERROR_SUCCESS;
664 }
665
666 /***********************************************************************
667  *              PdhGetCounterTimeBase   (PDH.@)
668  */
669 PDH_STATUS WINAPI PdhGetCounterTimeBase( PDH_HCOUNTER handle, LONGLONG *base )
670 {
671     struct counter *counter = handle;
672
673     TRACE("%p %p\n", handle, base);
674
675     if (!base) return PDH_INVALID_ARGUMENT;
676
677     EnterCriticalSection( &pdh_handle_cs );
678     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
679     {
680         LeaveCriticalSection( &pdh_handle_cs );
681         return PDH_INVALID_HANDLE;
682     }
683
684     *base = counter->base;
685
686     LeaveCriticalSection( &pdh_handle_cs );
687     return ERROR_SUCCESS;
688 }
689
690 /***********************************************************************
691  *              PdhGetFormattedCounterValue   (PDH.@)
692  */
693 PDH_STATUS WINAPI PdhGetFormattedCounterValue( PDH_HCOUNTER handle, DWORD format,
694                                                LPDWORD type, PPDH_FMT_COUNTERVALUE value )
695 {
696     PDH_STATUS ret;
697     struct counter *counter = handle;
698
699     TRACE("%p %x %p %p\n", handle, format, type, value);
700
701     if (!value) return PDH_INVALID_ARGUMENT;
702
703     EnterCriticalSection( &pdh_handle_cs );
704     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
705     {
706         LeaveCriticalSection( &pdh_handle_cs );
707         return PDH_INVALID_HANDLE;
708     }
709     if (counter->status)
710     {
711         LeaveCriticalSection( &pdh_handle_cs );
712         return PDH_INVALID_DATA;
713     }
714     if (!(ret = format_value( counter, format, &counter->one, &counter->two, value )))
715     {
716         value->CStatus = ERROR_SUCCESS;
717         if (type) *type = counter->type;
718     }
719
720     LeaveCriticalSection( &pdh_handle_cs );
721     return ret;
722 }
723
724 /***********************************************************************
725  *              PdhGetRawCounterValue   (PDH.@)
726  */
727 PDH_STATUS WINAPI PdhGetRawCounterValue( PDH_HCOUNTER handle, LPDWORD type,
728                                          PPDH_RAW_COUNTER value )
729 {
730     struct counter *counter = handle;
731
732     TRACE("%p %p %p\n", handle, type, value);
733
734     if (!value) return PDH_INVALID_ARGUMENT;
735
736     EnterCriticalSection( &pdh_handle_cs );
737     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
738     {
739         LeaveCriticalSection( &pdh_handle_cs );
740         return PDH_INVALID_HANDLE;
741     }
742
743     value->CStatus                  = counter->status;
744     value->TimeStamp.dwLowDateTime  = counter->stamp.dwLowDateTime;
745     value->TimeStamp.dwHighDateTime = counter->stamp.dwHighDateTime;
746     value->FirstValue               = counter->one.largevalue;
747     value->SecondValue              = counter->two.largevalue;
748     value->MultiCount               = 1; /* FIXME */
749
750     if (type) *type = counter->type;
751
752     LeaveCriticalSection( &pdh_handle_cs );
753     return ERROR_SUCCESS;
754 }
755
756 /***********************************************************************
757  *              PdhLookupPerfIndexByNameA   (PDH.@)
758  */
759 PDH_STATUS WINAPI PdhLookupPerfIndexByNameA( LPCSTR machine, LPCSTR name, LPDWORD index )
760 {
761     PDH_STATUS ret;
762     WCHAR *nameW;
763
764     TRACE("%s %s %p\n", debugstr_a(machine), debugstr_a(name), index);
765
766     if (!name || !index) return PDH_INVALID_ARGUMENT;
767
768     if (machine)
769     {
770         FIXME("remote machine not supported\n");
771         return PDH_CSTATUS_NO_MACHINE;
772     }
773     if (!(nameW = pdh_strdup_aw( name )))
774         return PDH_MEMORY_ALLOCATION_FAILURE;
775
776     ret = PdhLookupPerfIndexByNameW( NULL, nameW, index );
777
778     pdh_free( nameW );
779     return ret;
780 }
781
782 /***********************************************************************
783  *              PdhLookupPerfIndexByNameW   (PDH.@)
784  */
785 PDH_STATUS WINAPI PdhLookupPerfIndexByNameW( LPCWSTR machine, LPCWSTR name, LPDWORD index )
786 {
787     unsigned int i;
788
789     TRACE("%s %s %p\n", debugstr_w(machine), debugstr_w(name), index);
790
791     if (!name || !index) return PDH_INVALID_ARGUMENT;
792
793     if (machine)
794     {
795         FIXME("remote machine not supported\n");
796         return PDH_CSTATUS_NO_MACHINE;
797     }
798     for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
799     {
800         if (pdh_match_path( counter_sources[i].path, name ))
801         {
802             *index = counter_sources[i].index;
803             return ERROR_SUCCESS;
804         }
805     }
806     return PDH_STRING_NOT_FOUND;
807 }
808
809 /***********************************************************************
810  *              PdhLookupPerfNameByIndexA   (PDH.@)
811  */
812 PDH_STATUS WINAPI PdhLookupPerfNameByIndexA( LPCSTR machine, DWORD index, LPSTR buffer, LPDWORD size )
813 {
814     PDH_STATUS ret;
815     WCHAR bufferW[PDH_MAX_COUNTER_NAME];
816     DWORD sizeW = sizeof(bufferW) / sizeof(WCHAR);
817
818     TRACE("%s %d %p %p\n", debugstr_a(machine), index, buffer, size);
819
820     if (machine)
821     {
822         FIXME("remote machine not supported\n");
823         return PDH_CSTATUS_NO_MACHINE;
824     }
825
826     if (!buffer && !size) return PDH_INVALID_ARGUMENT;
827     if (!index) return ERROR_SUCCESS;
828
829     if (!(ret = PdhLookupPerfNameByIndexW( NULL, index, bufferW, &sizeW )))
830     {
831         int required = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
832
833         if (size && *size < required) ret = PDH_MORE_DATA;
834         else WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, required, NULL, NULL );
835         if (size) *size = required;
836     }
837     return ret;
838 }
839
840 /***********************************************************************
841  *              PdhLookupPerfNameByIndexW   (PDH.@)
842  */
843 PDH_STATUS WINAPI PdhLookupPerfNameByIndexW( LPCWSTR machine, DWORD index, LPWSTR buffer, LPDWORD size )
844 {
845     PDH_STATUS ret;
846     unsigned int i;
847
848     TRACE("%s %d %p %p\n", debugstr_w(machine), index, buffer, size);
849
850     if (machine)
851     {
852         FIXME("remote machine not supported\n");
853         return PDH_CSTATUS_NO_MACHINE;
854     }
855
856     if (!buffer && !size) return PDH_INVALID_ARGUMENT;
857     if (!index) return ERROR_SUCCESS;
858
859     for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
860     {
861         if (counter_sources[i].index == index)
862         {
863             WCHAR *p = strrchrW( counter_sources[i].path, '\\' ) + 1;
864             unsigned int required = strlenW( p ) + 1;
865
866             if (*size < required) ret = PDH_MORE_DATA;
867             else
868             {
869                 strcpyW( buffer, p );
870                 ret = ERROR_SUCCESS;
871             }
872             *size = required;
873             return ret;
874         }
875     }
876     return PDH_INVALID_ARGUMENT;
877 }
878
879 /***********************************************************************
880  *              PdhOpenQueryA   (PDH.@)
881  */
882 PDH_STATUS WINAPI PdhOpenQueryA( LPCSTR source, DWORD_PTR userdata, PDH_HQUERY *query )
883 {
884     PDH_STATUS ret;
885     WCHAR *sourceW = NULL;
886
887     TRACE("%s %lx %p\n", debugstr_a(source), userdata, query);
888
889     if (source && !(sourceW = pdh_strdup_aw( source ))) return PDH_MEMORY_ALLOCATION_FAILURE;
890
891     ret = PdhOpenQueryW( sourceW, userdata, query );
892     pdh_free( sourceW );
893
894     return ret;
895 }
896
897 /***********************************************************************
898  *              PdhOpenQueryW   (PDH.@)
899  */
900 PDH_STATUS WINAPI PdhOpenQueryW( LPCWSTR source, DWORD_PTR userdata, PDH_HQUERY *handle )
901 {
902     struct query *query;
903
904     TRACE("%s %lx %p\n", debugstr_w(source), userdata, handle);
905
906     if (!handle) return PDH_INVALID_ARGUMENT;
907
908     if (source)
909     {
910         FIXME("log file data source not supported\n");
911         return PDH_INVALID_ARGUMENT;
912     }
913     if ((query = create_query()))
914     {
915         query->user = userdata;
916         *handle = query;
917
918         return ERROR_SUCCESS;
919     }
920     return PDH_MEMORY_ALLOCATION_FAILURE;
921 }
922
923 /***********************************************************************
924  *              PdhRemoveCounter   (PDH.@)
925  */
926 PDH_STATUS WINAPI PdhRemoveCounter( PDH_HCOUNTER handle )
927 {
928     struct counter *counter = handle;
929
930     TRACE("%p\n", handle);
931
932     EnterCriticalSection( &pdh_handle_cs );
933     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
934     {
935         LeaveCriticalSection( &pdh_handle_cs );
936         return PDH_INVALID_HANDLE;
937     }
938
939     list_remove( &counter->entry );
940     destroy_counter( counter );
941
942     LeaveCriticalSection( &pdh_handle_cs );
943     return ERROR_SUCCESS;
944 }
945
946 /***********************************************************************
947  *              PdhSetCounterScaleFactor   (PDH.@)
948  */
949 PDH_STATUS WINAPI PdhSetCounterScaleFactor( PDH_HCOUNTER handle, LONG factor )
950 {
951     struct counter *counter = handle;
952
953     TRACE("%p\n", handle);
954
955     EnterCriticalSection( &pdh_handle_cs );
956     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
957     {
958         LeaveCriticalSection( &pdh_handle_cs );
959         return PDH_INVALID_HANDLE;
960     }
961     if (factor < PDH_MIN_SCALE || factor > PDH_MAX_SCALE)
962     {
963         LeaveCriticalSection( &pdh_handle_cs );
964         return PDH_INVALID_ARGUMENT;
965     }
966
967     counter->scale = factor;
968
969     LeaveCriticalSection( &pdh_handle_cs );
970     return ERROR_SUCCESS;
971 }
972
973 /***********************************************************************
974  *              PdhValidatePathA   (PDH.@)
975  */
976 PDH_STATUS WINAPI PdhValidatePathA( LPCSTR path )
977 {
978     PDH_STATUS ret;
979     WCHAR *pathW;
980
981     TRACE("%s\n", debugstr_a(path));
982
983     if (!path) return PDH_INVALID_ARGUMENT;
984     if (!(pathW = pdh_strdup_aw( path ))) return PDH_MEMORY_ALLOCATION_FAILURE;
985
986     ret = PdhValidatePathW( pathW );
987
988     pdh_free( pathW );
989     return ret;
990 }
991
992 static PDH_STATUS validate_path( LPCWSTR path )
993 {
994     if (!path || !*path) return PDH_INVALID_ARGUMENT;
995     if (*path++ != '\\' || !strchrW( path, '\\' )) return PDH_CSTATUS_BAD_COUNTERNAME;
996     return ERROR_SUCCESS;
997  }
998
999 /***********************************************************************
1000  *              PdhValidatePathW   (PDH.@)
1001  */
1002 PDH_STATUS WINAPI PdhValidatePathW( LPCWSTR path )
1003 {
1004     PDH_STATUS ret;
1005     unsigned int i;
1006
1007     TRACE("%s\n", debugstr_w(path));
1008
1009     if ((ret = validate_path( path ))) return ret;
1010
1011     for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
1012         if (pdh_match_path( counter_sources[i].path, path )) return ERROR_SUCCESS;
1013
1014     return PDH_CSTATUS_NO_COUNTER;
1015 }
1016
1017 /***********************************************************************
1018  *              PdhValidatePathExA   (PDH.@)
1019  */
1020 PDH_STATUS WINAPI PdhValidatePathExA( PDH_HLOG source, LPCSTR path )
1021 {
1022     TRACE("%p %s\n", source, debugstr_a(path));
1023
1024     if (source)
1025     {
1026         FIXME("log file data source not supported\n");
1027         return ERROR_SUCCESS;
1028     }
1029     return PdhValidatePathA( path );
1030 }
1031
1032 /***********************************************************************
1033  *              PdhValidatePathExW   (PDH.@)
1034  */
1035 PDH_STATUS WINAPI PdhValidatePathExW( PDH_HLOG source, LPCWSTR path )
1036 {
1037     TRACE("%p %s\n", source, debugstr_w(path));
1038
1039     if (source)
1040     {
1041         FIXME("log file data source not supported\n");
1042         return ERROR_SUCCESS;
1043     }
1044     return PdhValidatePathW( path );
1045 }