~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/pdh/pdh_main.c

Version: ~ [ wine-1.5.30 ] ~ [ wine-1.5.29 ] ~ [ wine-1.5.28 ] ~ [ wine-1.5.27 ] ~ [ wine-1.5.26 ] ~ [ wine-1.5.25 ] ~ [ wine-1.5.24 ] ~ [ wine-1.5.23 ] ~ [ wine-1.5.22 ] ~ [ wine-1.5.21 ] ~ [ wine-1.5.20 ] ~ [ wine-1.5.19 ] ~ [ wine-1.5.18 ] ~ [ wine-1.5.17 ] ~ [ wine-1.5.16 ] ~ [ wine-1.5.15 ] ~ [ wine-1.5.14 ] ~ [ wine-1.5.13 ] ~ [ wine-1.5.12 ] ~ [ wine-1.5.11 ] ~ [ wine-1.5.10 ] ~ [ wine-1.5.9 ] ~ [ wine-1.5.8 ] ~ [ wine-1.5.7 ] ~ [ wine-1.4.1 ] ~ [ wine-1.5.6 ] ~ [ wine-1.5.5 ] ~ [ wine-1.5.4 ] ~ [ wine-1.5.3 ] ~ [ wine-1.5.2 ] ~ [ wine-1.5.1 ] ~ [ wine-1.5.0 ] ~ [ wine-1.4 ] ~ [ wine-1.4-rc6 ] ~ [ wine-1.4-rc5 ] ~ [ wine-1.4-rc4 ] ~ [ wine-1.4-rc3 ] ~ [ wine-1.4-rc2 ] ~ [ wine-1.4-rc1 ] ~ [ wine-1.3.37 ] ~ [ wine-1.3.36 ] ~ [ wine-1.3.35 ] ~ [ wine-1.3.34 ] ~ [ wine-1.3.33 ] ~ [ wine-1.3.32 ] ~ [ wine-1.3.31 ] ~ [ wine-1.3.30 ] ~ [ wine-1.3.29 ] ~ [ wine-1.3.28 ] ~ [ wine-1.3.27 ] ~ [ wine-1.3.26 ] ~ [ wine-1.3.25 ] ~ [ wine-1.3.24 ] ~ [ wine-1.3.23 ] ~ [ wine-1.3.22 ] ~ [ wine-1.3.21 ] ~ [ wine-1.3.20 ] ~ [ wine-1.3.19 ] ~ [ wine-1.3.18 ] ~ [ wine-1.2.3 ] ~ [ wine-1.3.17 ] ~ [ wine-1.3.16 ] ~ [ wine-1.3.15 ] ~ [ wine-1.3.14 ] ~ [ wine-1.3.13 ] ~ [ wine-1.3.12 ] ~ [ wine-1.3.11 ] ~ [ wine-1.3.10 ] ~ [ wine-1.3.9 ] ~ [ wine-1.2.2 ] ~ [ wine-1.3.8 ] ~ [ wine-1.3.7 ] ~ [ wine-1.3.6 ] ~ [ wine-1.3.5 ] ~ [ wine-1.2.1 ] ~ [ wine-1.3.4 ] ~ [ wine-1.3.3 ] ~ [ wine-1.3.2 ] ~ [ wine-1.3.1 ] ~ [ wine-1.3.0 ] ~ [ wine-1.2 ] ~ [ wine-1.2-rc7 ] ~ [ wine-1.2-rc6 ] ~ [ wine-1.2-rc5 ] ~ [ wine-1.2-rc4 ] ~ [ wine-1.2-rc3 ] ~ [ wine-1.2-rc2 ] ~ [ wine-1.2-rc1 ] ~ [ wine-1.1.44 ] ~ [ wine-1.1.43 ] ~ [ wine-1.1.42 ] ~ [ wine-1.1.41 ] ~ [ wine-1.1.40 ] ~ [ wine-1.1.39 ] ~ [ wine-1.1.38 ] ~ [ wine-1.1.37 ] ~ [ wine-1.1.36 ] ~ [ wine-1.1.35 ] ~ [ wine-1.1.34 ] ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  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 *heap_alloc( SIZE_T size )
 51 {
 52     return HeapAlloc( GetProcessHeap(), 0, size );
 53 }
 54 
 55 static inline void *heap_alloc_zero( SIZE_T size )
 56 {
 57     return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
 58 }
 59 
 60 static inline void heap_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 = heap_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 = heap_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 = heap_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     heap_free( counter->path );
142     heap_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 = heap_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     heap_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     heap_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 
384 /***********************************************************************
385  *              PdhCloseQuery   (PDH.@)
386  */
387 PDH_STATUS WINAPI PdhCloseQuery( PDH_HQUERY handle )
388 {
389     struct query *query = handle;
390     struct list *item, *next;
391 
392     TRACE("%p\n", handle);
393 
394     EnterCriticalSection( &pdh_handle_cs );
395     if (!query || query->magic != PDH_MAGIC_QUERY)
396     {
397         LeaveCriticalSection( &pdh_handle_cs );
398         return PDH_INVALID_HANDLE;
399     }
400 
401     if (query->thread)
402     {
403         HANDLE thread = query->thread;
404         SetEvent( query->stop );
405         LeaveCriticalSection( &pdh_handle_cs );
406 
407         WaitForSingleObject( thread, INFINITE );
408 
409         EnterCriticalSection( &pdh_handle_cs );
410         if (query->magic != PDH_MAGIC_QUERY)
411         {
412             LeaveCriticalSection( &pdh_handle_cs );
413             return ERROR_SUCCESS;
414         }
415         CloseHandle( query->stop );
416         CloseHandle( query->thread );
417         query->thread = NULL;
418     }
419 
420     LIST_FOR_EACH_SAFE( item, next, &query->counters )
421     {
422         struct counter *counter = LIST_ENTRY( item, struct counter, entry );
423 
424         list_remove( &counter->entry );
425         destroy_counter( counter );
426     }
427 
428     destroy_query( query );
429 
430     LeaveCriticalSection( &pdh_handle_cs );
431     return ERROR_SUCCESS;
432 }
433 
434 /* caller must hold query lock */
435 static void collect_query_data( struct query *query )
436 {
437     struct list *item;
438 
439     LIST_FOR_EACH( item, &query->counters )
440     {
441         SYSTEMTIME time;
442         struct counter *counter = LIST_ENTRY( item, struct counter, entry );
443 
444         counter->collect( counter );
445 
446         GetLocalTime( &time );
447         SystemTimeToFileTime( &time, &counter->stamp );
448     }
449 }
450 
451 /***********************************************************************
452  *              PdhCollectQueryData   (PDH.@)
453  */
454 PDH_STATUS WINAPI PdhCollectQueryData( PDH_HQUERY handle )
455 {
456     struct query *query = handle;
457 
458     TRACE("%p\n", handle);
459 
460     EnterCriticalSection( &pdh_handle_cs );
461     if (!query || query->magic != PDH_MAGIC_QUERY)
462     {
463         LeaveCriticalSection( &pdh_handle_cs );
464         return PDH_INVALID_HANDLE;
465     }
466 
467     if (list_empty( &query->counters ))
468     {
469         LeaveCriticalSection( &pdh_handle_cs );
470         return PDH_NO_DATA;
471     }
472 
473     collect_query_data( query );
474 
475     LeaveCriticalSection( &pdh_handle_cs );
476     return ERROR_SUCCESS;
477 }
478 
479 static DWORD CALLBACK collect_query_thread( void *arg )
480 {
481     struct query *query = arg;
482     DWORD interval = query->interval;
483     HANDLE stop = query->stop;
484 
485     for (;;)
486     {
487         if (WaitForSingleObject( stop, interval ) != WAIT_TIMEOUT) ExitThread( 0 );
488 
489         EnterCriticalSection( &pdh_handle_cs );
490         if (query->magic != PDH_MAGIC_QUERY)
491         {
492             LeaveCriticalSection( &pdh_handle_cs );
493             ExitThread( PDH_INVALID_HANDLE );
494         }
495 
496         collect_query_data( query );
497 
498         if (!SetEvent( query->wait ))
499         {
500             LeaveCriticalSection( &pdh_handle_cs );
501             ExitThread( 0 );
502         }
503         LeaveCriticalSection( &pdh_handle_cs );
504     }
505 }
506 
507 /***********************************************************************
508  *              PdhCollectQueryDataEx   (PDH.@)
509  */
510 PDH_STATUS WINAPI PdhCollectQueryDataEx( PDH_HQUERY handle, DWORD interval, HANDLE event )
511 {
512     PDH_STATUS ret;
513     struct query *query = handle;
514 
515     TRACE("%p %d %p\n", handle, interval, event);
516 
517     EnterCriticalSection( &pdh_handle_cs );
518     if (!query || query->magic != PDH_MAGIC_QUERY)
519     {
520         LeaveCriticalSection( &pdh_handle_cs );
521         return PDH_INVALID_HANDLE;
522     }
523     if (list_empty( &query->counters ))
524     {
525         LeaveCriticalSection( &pdh_handle_cs );
526         return PDH_NO_DATA;
527     }
528     if (query->thread)
529     {
530         HANDLE thread = query->thread;
531         SetEvent( query->stop );
532         LeaveCriticalSection( &pdh_handle_cs );
533 
534         WaitForSingleObject( thread, INFINITE );
535 
536         EnterCriticalSection( &pdh_handle_cs );
537         if (query->magic != PDH_MAGIC_QUERY)
538         {
539             LeaveCriticalSection( &pdh_handle_cs );
540             return PDH_INVALID_HANDLE;
541         }
542         CloseHandle( query->thread );
543         query->thread = NULL;
544     }
545     else if (!(query->stop = CreateEventW( NULL, FALSE, FALSE, NULL )))
546     {
547         ret = GetLastError();
548         LeaveCriticalSection( &pdh_handle_cs );
549         return ret;
550     }
551     query->wait = event;
552     query->interval = interval * 1000;
553     if (!(query->thread = CreateThread( NULL, 0, collect_query_thread, query, 0, NULL )))
554     {
555         ret = GetLastError();
556         CloseHandle( query->stop );
557 
558         LeaveCriticalSection( &pdh_handle_cs );
559         return ret;
560     }
561 
562     LeaveCriticalSection( &pdh_handle_cs );
563     return ERROR_SUCCESS;
564 }
565 
566 /***********************************************************************
567  *              PdhCollectQueryDataWithTime   (PDH.@)
568  */
569 PDH_STATUS WINAPI PdhCollectQueryDataWithTime( PDH_HQUERY handle, LONGLONG *timestamp )
570 {
571     struct query *query = handle;
572     struct counter *counter;
573     struct list *item;
574 
575     TRACE("%p %p\n", handle, timestamp);
576 
577     if (!timestamp) return PDH_INVALID_ARGUMENT;
578 
579     EnterCriticalSection( &pdh_handle_cs );
580     if (!query || query->magic != PDH_MAGIC_QUERY)
581     {
582         LeaveCriticalSection( &pdh_handle_cs );
583         return PDH_INVALID_HANDLE;
584     }
585     if (list_empty( &query->counters ))
586     {
587         LeaveCriticalSection( &pdh_handle_cs );
588         return PDH_NO_DATA;
589     }
590 
591     collect_query_data( query );
592 
593     item = list_head( &query->counters );
594     counter = LIST_ENTRY( item, struct counter, entry );
595 
596     *timestamp = ((LONGLONG)counter->stamp.dwHighDateTime << 32) | counter->stamp.dwLowDateTime;
597 
598     LeaveCriticalSection( &pdh_handle_cs );
599     return ERROR_SUCCESS;
600 }
601 
602 /***********************************************************************
603  *              PdhExpandWildCardPathA   (PDH.@)
604  */
605 PDH_STATUS WINAPI PdhExpandWildCardPathA( LPCSTR szDataSource, LPCSTR szWildCardPath, LPSTR mszExpandedPathList, LPDWORD pcchPathListLength, DWORD dwFlags )
606 {
607     FIXME("%s, %s, %p, %p, 0x%x: stub\n", debugstr_a(szDataSource), debugstr_a(szWildCardPath), mszExpandedPathList, pcchPathListLength, dwFlags);
608     return PDH_NOT_IMPLEMENTED;
609 }
610 
611 /***********************************************************************
612  *              PdhExpandWildCardPathW   (PDH.@)
613  */
614 PDH_STATUS WINAPI PdhExpandWildCardPathW( LPCWSTR szDataSource, LPCWSTR szWildCardPath, LPWSTR mszExpandedPathList, LPDWORD pcchPathListLength, DWORD dwFlags )
615 {
616     FIXME("%s, %s, %p, %p, 0x%x: stub\n", debugstr_w(szDataSource), debugstr_w(szWildCardPath), mszExpandedPathList, pcchPathListLength, dwFlags);
617     return PDH_NOT_IMPLEMENTED;
618 }
619 
620 /***********************************************************************
621  *              PdhGetCounterInfoA   (PDH.@)
622  */
623 PDH_STATUS WINAPI PdhGetCounterInfoA( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_A info )
624 {
625     struct counter *counter = handle;
626 
627     TRACE("%p %d %p %p\n", handle, text, size, info);
628 
629     EnterCriticalSection( &pdh_handle_cs );
630     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
631     {
632         LeaveCriticalSection( &pdh_handle_cs );
633         return PDH_INVALID_HANDLE;
634     }
635     if (!size)
636     {
637         LeaveCriticalSection( &pdh_handle_cs );
638         return PDH_INVALID_ARGUMENT;
639     }
640     if (*size < sizeof(PDH_COUNTER_INFO_A))
641     {
642         *size = sizeof(PDH_COUNTER_INFO_A);
643         LeaveCriticalSection( &pdh_handle_cs );
644         return PDH_MORE_DATA;
645     }
646 
647     memset( info, 0, sizeof(PDH_COUNTER_INFO_A) );
648 
649     info->dwType          = counter->type;
650     info->CStatus         = counter->status;
651     info->lScale          = counter->scale;
652     info->lDefaultScale   = counter->defaultscale;
653     info->dwUserData      = counter->user;
654     info->dwQueryUserData = counter->queryuser;
655 
656     *size = sizeof(PDH_COUNTER_INFO_A);
657 
658     LeaveCriticalSection( &pdh_handle_cs );
659     return ERROR_SUCCESS;
660 }
661 
662 /***********************************************************************
663  *              PdhGetCounterInfoW   (PDH.@)
664  */
665 PDH_STATUS WINAPI PdhGetCounterInfoW( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_W info )
666 {
667     struct counter *counter = handle;
668 
669     TRACE("%p %d %p %p\n", handle, text, size, info);
670 
671     EnterCriticalSection( &pdh_handle_cs );
672     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
673     {
674         LeaveCriticalSection( &pdh_handle_cs );
675         return PDH_INVALID_HANDLE;
676     }
677     if (!size)
678     {
679         LeaveCriticalSection( &pdh_handle_cs );
680         return PDH_INVALID_ARGUMENT;
681     }
682     if (*size < sizeof(PDH_COUNTER_INFO_W))
683     {
684         *size = sizeof(PDH_COUNTER_INFO_W);
685         LeaveCriticalSection( &pdh_handle_cs );
686         return PDH_MORE_DATA;
687     }
688 
689     memset( info, 0, sizeof(PDH_COUNTER_INFO_W) );
690 
691     info->dwType          = counter->type;
692     info->CStatus         = counter->status;
693     info->lScale          = counter->scale;
694     info->lDefaultScale   = counter->defaultscale;
695     info->dwUserData      = counter->user;
696     info->dwQueryUserData = counter->queryuser;
697 
698     *size = sizeof(PDH_COUNTER_INFO_W);
699 
700     LeaveCriticalSection( &pdh_handle_cs );
701     return ERROR_SUCCESS;
702 }
703 
704 /***********************************************************************
705  *              PdhGetCounterTimeBase   (PDH.@)
706  */
707 PDH_STATUS WINAPI PdhGetCounterTimeBase( PDH_HCOUNTER handle, LONGLONG *base )
708 {
709     struct counter *counter = handle;
710 
711     TRACE("%p %p\n", handle, base);
712 
713     if (!base) return PDH_INVALID_ARGUMENT;
714 
715     EnterCriticalSection( &pdh_handle_cs );
716     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
717     {
718         LeaveCriticalSection( &pdh_handle_cs );
719         return PDH_INVALID_HANDLE;
720     }
721 
722     *base = counter->base;
723 
724     LeaveCriticalSection( &pdh_handle_cs );
725     return ERROR_SUCCESS;
726 }
727 
728 /***********************************************************************
729  *              PdhGetDllVersion   (PDH.@)
730  */
731 PDH_STATUS WINAPI PdhGetDllVersion( LPDWORD version )
732 {
733     if (!version)
734         return PDH_INVALID_ARGUMENT;
735 
736     *version = PDH_VERSION;
737 
738     return ERROR_SUCCESS;
739 }
740 
741 /***********************************************************************
742  *              PdhGetFormattedCounterValue   (PDH.@)
743  */
744 PDH_STATUS WINAPI PdhGetFormattedCounterValue( PDH_HCOUNTER handle, DWORD format,
745                                                LPDWORD type, PPDH_FMT_COUNTERVALUE value )
746 {
747     PDH_STATUS ret;
748     struct counter *counter = handle;
749 
750     TRACE("%p %x %p %p\n", handle, format, type, value);
751 
752     if (!value) return PDH_INVALID_ARGUMENT;
753 
754     EnterCriticalSection( &pdh_handle_cs );
755     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
756     {
757         LeaveCriticalSection( &pdh_handle_cs );
758         return PDH_INVALID_HANDLE;
759     }
760     if (counter->status)
761     {
762         LeaveCriticalSection( &pdh_handle_cs );
763         return PDH_INVALID_DATA;
764     }
765     if (!(ret = format_value( counter, format, &counter->one, &counter->two, value )))
766     {
767         value->CStatus = ERROR_SUCCESS;
768         if (type) *type = counter->type;
769     }
770 
771     LeaveCriticalSection( &pdh_handle_cs );
772     return ret;
773 }
774 
775 /***********************************************************************
776  *              PdhGetRawCounterValue   (PDH.@)
777  */
778 PDH_STATUS WINAPI PdhGetRawCounterValue( PDH_HCOUNTER handle, LPDWORD type,
779                                          PPDH_RAW_COUNTER value )
780 {
781     struct counter *counter = handle;
782 
783     TRACE("%p %p %p\n", handle, type, value);
784 
785     if (!value) return PDH_INVALID_ARGUMENT;
786 
787     EnterCriticalSection( &pdh_handle_cs );
788     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
789     {
790         LeaveCriticalSection( &pdh_handle_cs );
791         return PDH_INVALID_HANDLE;
792     }
793 
794     value->CStatus                  = counter->status;
795     value->TimeStamp.dwLowDateTime  = counter->stamp.dwLowDateTime;
796     value->TimeStamp.dwHighDateTime = counter->stamp.dwHighDateTime;
797     value->FirstValue               = counter->one.largevalue;
798     value->SecondValue              = counter->two.largevalue;
799     value->MultiCount               = 1; /* FIXME */
800 
801     if (type) *type = counter->type;
802 
803     LeaveCriticalSection( &pdh_handle_cs );
804     return ERROR_SUCCESS;
805 }
806 
807 /***********************************************************************
808  *              PdhLookupPerfIndexByNameA   (PDH.@)
809  */
810 PDH_STATUS WINAPI PdhLookupPerfIndexByNameA( LPCSTR machine, LPCSTR name, LPDWORD index )
811 {
812     PDH_STATUS ret;
813     WCHAR *machineW = NULL;
814     WCHAR *nameW;
815 
816     TRACE("%s %s %p\n", debugstr_a(machine), debugstr_a(name), index);
817 
818     if (!name) return PDH_INVALID_ARGUMENT;
819 
820     if (machine && !(machineW = pdh_strdup_aw( machine ))) return PDH_MEMORY_ALLOCATION_FAILURE;
821 
822     if (!(nameW = pdh_strdup_aw( name )))
823         return PDH_MEMORY_ALLOCATION_FAILURE;
824 
825     ret = PdhLookupPerfIndexByNameW( machineW, nameW, index );
826 
827     heap_free( nameW );
828     heap_free( machineW );
829     return ret;
830 }
831 
832 /***********************************************************************
833  *              PdhLookupPerfIndexByNameW   (PDH.@)
834  */
835 PDH_STATUS WINAPI PdhLookupPerfIndexByNameW( LPCWSTR machine, LPCWSTR name, LPDWORD index )
836 {
837     unsigned int i;
838 
839     TRACE("%s %s %p\n", debugstr_w(machine), debugstr_w(name), index);
840 
841     if (!name || !index) return PDH_INVALID_ARGUMENT;
842 
843     if (machine)
844     {
845         FIXME("remote machine not supported\n");
846         return PDH_CSTATUS_NO_MACHINE;
847     }
848     for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
849     {
850         if (pdh_match_path( counter_sources[i].path, name ))
851         {
852             *index = counter_sources[i].index;
853             return ERROR_SUCCESS;
854         }
855     }
856     return PDH_STRING_NOT_FOUND;
857 }
858 
859 /***********************************************************************
860  *              PdhLookupPerfNameByIndexA   (PDH.@)
861  */
862 PDH_STATUS WINAPI PdhLookupPerfNameByIndexA( LPCSTR machine, DWORD index, LPSTR buffer, LPDWORD size )
863 {
864     PDH_STATUS ret;
865     WCHAR *machineW = NULL;
866     WCHAR bufferW[PDH_MAX_COUNTER_NAME];
867     DWORD sizeW = sizeof(bufferW) / sizeof(WCHAR);
868 
869     TRACE("%s %d %p %p\n", debugstr_a(machine), index, buffer, size);
870 
871     if (!buffer || !size) return PDH_INVALID_ARGUMENT;
872 
873     if (machine && !(machineW = pdh_strdup_aw( machine ))) return PDH_MEMORY_ALLOCATION_FAILURE;
874 
875     if (!(ret = PdhLookupPerfNameByIndexW( machineW, index, bufferW, &sizeW )))
876     {
877         int required = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
878 
879         if (size && *size < required) ret = PDH_MORE_DATA;
880         else WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, required, NULL, NULL );
881         if (size) *size = required;
882     }
883     heap_free( machineW );
884     return ret;
885 }
886 
887 /***********************************************************************
888  *              PdhLookupPerfNameByIndexW   (PDH.@)
889  */
890 PDH_STATUS WINAPI PdhLookupPerfNameByIndexW( LPCWSTR machine, DWORD index, LPWSTR buffer, LPDWORD size )
891 {
892     PDH_STATUS ret;
893     unsigned int i;
894 
895     TRACE("%s %d %p %p\n", debugstr_w(machine), index, buffer, size);
896 
897     if (machine)
898     {
899         FIXME("remote machine not supported\n");
900         return PDH_CSTATUS_NO_MACHINE;
901     }
902 
903     if (!buffer || !size) return PDH_INVALID_ARGUMENT;
904     if (!index) return ERROR_SUCCESS;
905 
906     for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
907     {
908         if (counter_sources[i].index == index)
909         {
910             WCHAR *p = strrchrW( counter_sources[i].path, '\\' ) + 1;
911             unsigned int required = strlenW( p ) + 1;
912 
913             if (*size < required) ret = PDH_MORE_DATA;
914             else
915             {
916                 strcpyW( buffer, p );
917                 ret = ERROR_SUCCESS;
918             }
919             *size = required;
920             return ret;
921         }
922     }
923     return PDH_INVALID_ARGUMENT;
924 }
925 
926 /***********************************************************************
927  *              PdhOpenQueryA   (PDH.@)
928  */
929 PDH_STATUS WINAPI PdhOpenQueryA( LPCSTR source, DWORD_PTR userdata, PDH_HQUERY *query )
930 {
931     PDH_STATUS ret;
932     WCHAR *sourceW = NULL;
933 
934     TRACE("%s %lx %p\n", debugstr_a(source), userdata, query);
935 
936     if (source && !(sourceW = pdh_strdup_aw( source ))) return PDH_MEMORY_ALLOCATION_FAILURE;
937 
938     ret = PdhOpenQueryW( sourceW, userdata, query );
939     heap_free( sourceW );
940 
941     return ret;
942 }
943 
944 /***********************************************************************
945  *              PdhOpenQueryW   (PDH.@)
946  */
947 PDH_STATUS WINAPI PdhOpenQueryW( LPCWSTR source, DWORD_PTR userdata, PDH_HQUERY *handle )
948 {
949     struct query *query;
950 
951     TRACE("%s %lx %p\n", debugstr_w(source), userdata, handle);
952 
953     if (!handle) return PDH_INVALID_ARGUMENT;
954 
955     if (source)
956     {
957         FIXME("log file data source not supported\n");
958         return PDH_INVALID_ARGUMENT;
959     }
960     if ((query = create_query()))
961     {
962         query->user = userdata;
963         *handle = query;
964 
965         return ERROR_SUCCESS;
966     }
967     return PDH_MEMORY_ALLOCATION_FAILURE;
968 }
969 
970 /***********************************************************************
971  *              PdhRemoveCounter   (PDH.@)
972  */
973 PDH_STATUS WINAPI PdhRemoveCounter( PDH_HCOUNTER handle )
974 {
975     struct counter *counter = handle;
976 
977     TRACE("%p\n", handle);
978 
979     EnterCriticalSection( &pdh_handle_cs );
980     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
981     {
982         LeaveCriticalSection( &pdh_handle_cs );
983         return PDH_INVALID_HANDLE;
984     }
985 
986     list_remove( &counter->entry );
987     destroy_counter( counter );
988 
989     LeaveCriticalSection( &pdh_handle_cs );
990     return ERROR_SUCCESS;
991 }
992 
993 /***********************************************************************
994  *              PdhSetCounterScaleFactor   (PDH.@)
995  */
996 PDH_STATUS WINAPI PdhSetCounterScaleFactor( PDH_HCOUNTER handle, LONG factor )
997 {
998     struct counter *counter = handle;
999 
1000     TRACE("%p\n", handle);
1001 
1002     EnterCriticalSection( &pdh_handle_cs );
1003     if (!counter || counter->magic != PDH_MAGIC_COUNTER)
1004     {
1005         LeaveCriticalSection( &pdh_handle_cs );
1006         return PDH_INVALID_HANDLE;
1007     }
1008     if (factor < PDH_MIN_SCALE || factor > PDH_MAX_SCALE)
1009     {
1010         LeaveCriticalSection( &pdh_handle_cs );
1011         return PDH_INVALID_ARGUMENT;
1012     }
1013 
1014     counter->scale = factor;
1015 
1016     LeaveCriticalSection( &pdh_handle_cs );
1017     return ERROR_SUCCESS;
1018 }
1019 
1020 /***********************************************************************
1021  *              PdhValidatePathA   (PDH.@)
1022  */
1023 PDH_STATUS WINAPI PdhValidatePathA( LPCSTR path )
1024 {
1025     PDH_STATUS ret;
1026     WCHAR *pathW;
1027 
1028     TRACE("%s\n", debugstr_a(path));
1029 
1030     if (!path) return PDH_INVALID_ARGUMENT;
1031     if (!(pathW = pdh_strdup_aw( path ))) return PDH_MEMORY_ALLOCATION_FAILURE;
1032 
1033     ret = PdhValidatePathW( pathW );
1034 
1035     heap_free( pathW );
1036     return ret;
1037 }
1038 
1039 static PDH_STATUS validate_path( LPCWSTR path )
1040 {
1041     if (!path || !*path) return PDH_INVALID_ARGUMENT;
1042     if (*path++ != '\\' || !strchrW( path, '\\' )) return PDH_CSTATUS_BAD_COUNTERNAME;
1043     return ERROR_SUCCESS;
1044  }
1045 
1046 /***********************************************************************
1047  *              PdhValidatePathW   (PDH.@)
1048  */
1049 PDH_STATUS WINAPI PdhValidatePathW( LPCWSTR path )
1050 {
1051     PDH_STATUS ret;
1052     unsigned int i;
1053 
1054     TRACE("%s\n", debugstr_w(path));
1055 
1056     if ((ret = validate_path( path ))) return ret;
1057 
1058     for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
1059         if (pdh_match_path( counter_sources[i].path, path )) return ERROR_SUCCESS;
1060 
1061     return PDH_CSTATUS_NO_COUNTER;
1062 }
1063 
1064 /***********************************************************************
1065  *              PdhValidatePathExA   (PDH.@)
1066  */
1067 PDH_STATUS WINAPI PdhValidatePathExA( PDH_HLOG source, LPCSTR path )
1068 {
1069     TRACE("%p %s\n", source, debugstr_a(path));
1070 
1071     if (source)
1072     {
1073         FIXME("log file data source not supported\n");
1074         return ERROR_SUCCESS;
1075     }
1076     return PdhValidatePathA( path );
1077 }
1078 
1079 /***********************************************************************
1080  *              PdhValidatePathExW   (PDH.@)
1081  */
1082 PDH_STATUS WINAPI PdhValidatePathExW( PDH_HLOG source, LPCWSTR path )
1083 {
1084     TRACE("%p %s\n", source, debugstr_w(path));
1085 
1086     if (source)
1087     {
1088         FIXME("log file data source not supported\n");
1089         return ERROR_SUCCESS;
1090     }
1091     return PdhValidatePathW( path );
1092 }
1093 
1094 /***********************************************************************
1095  *              PdhMakeCounterPathA   (PDH.@)
1096  */
1097 PDH_STATUS WINAPI PdhMakeCounterPathA( PDH_COUNTER_PATH_ELEMENTS_A *e, LPSTR buffer,
1098                                        LPDWORD buflen, DWORD flags )
1099 {
1100     PDH_STATUS ret = PDH_MEMORY_ALLOCATION_FAILURE;
1101     PDH_COUNTER_PATH_ELEMENTS_W eW;
1102     WCHAR *bufferW;
1103     DWORD buflenW;
1104 
1105     TRACE("%p %p %p 0x%08x\n", e, buffer, buflen, flags);
1106 
1107     if (!e || !buflen) return PDH_INVALID_ARGUMENT;
1108 
1109     memset( &eW, 0, sizeof(eW) );
1110     if (e->szMachineName    && !(eW.szMachineName    = pdh_strdup_aw( e->szMachineName ))) goto done;
1111     if (e->szObjectName     && !(eW.szObjectName     = pdh_strdup_aw( e->szObjectName ))) goto done;
1112     if (e->szInstanceName   && !(eW.szInstanceName   = pdh_strdup_aw( e->szInstanceName ))) goto done;
1113     if (e->szParentInstance && !(eW.szParentInstance = pdh_strdup_aw( e->szParentInstance ))) goto done;
1114     if (e->szCounterName    && !(eW.szCounterName    = pdh_strdup_aw( e->szCounterName ))) goto done;
1115     eW.dwInstanceIndex = e->dwInstanceIndex;
1116 
1117     buflenW = 0;
1118     ret = PdhMakeCounterPathW( &eW, NULL, &buflenW, flags );
1119     if (ret == PDH_MORE_DATA)
1120     {
1121         if ((bufferW = heap_alloc( buflenW * sizeof(WCHAR) )))
1122         {
1123             if (!(ret = PdhMakeCounterPathW( &eW, bufferW, &buflenW, flags )))
1124             {
1125                 int len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
1126                 if (*buflen >= len) WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, *buflen, NULL, NULL);
1127                 else ret = PDH_MORE_DATA;
1128                 *buflen = len;
1129             }
1130             heap_free( bufferW );
1131         }
1132         else
1133             ret = PDH_MEMORY_ALLOCATION_FAILURE;
1134     }
1135 
1136 done:
1137     heap_free( eW.szMachineName );
1138     heap_free( eW.szObjectName );
1139     heap_free( eW.szInstanceName );
1140     heap_free( eW.szParentInstance );
1141     heap_free( eW.szCounterName );
1142     return ret;
1143 }
1144 
1145 /***********************************************************************
1146  *              PdhMakeCounterPathW   (PDH.@)
1147  */
1148 PDH_STATUS WINAPI PdhMakeCounterPathW( PDH_COUNTER_PATH_ELEMENTS_W *e, LPWSTR buffer,
1149                                        LPDWORD buflen, DWORD flags )
1150 {
1151     static const WCHAR bslash[] = {'\\',0};
1152     static const WCHAR fslash[] = {'/',0};
1153     static const WCHAR lparen[] = {'(',0};
1154     static const WCHAR rparen[] = {')',0};
1155     static const WCHAR fmt[]    = {'#','%','u',0};
1156 
1157     WCHAR path[PDH_MAX_COUNTER_NAME], instance[12];
1158     PDH_STATUS ret = ERROR_SUCCESS;
1159     DWORD len;
1160 
1161     TRACE("%p %p %p 0x%08x\n", e, buffer, buflen, flags);
1162 
1163     if (flags) FIXME("unimplemented flags 0x%08x\n", flags);
1164 
1165     if (!e || !e->szCounterName || !e->szObjectName || !buflen)
1166         return PDH_INVALID_ARGUMENT;
1167 
1168     path[0] = 0;
1169     if (e->szMachineName)
1170     {
1171         strcatW(path, bslash);
1172         strcatW(path, bslash);
1173         strcatW(path, e->szMachineName);
1174     }
1175     strcatW(path, bslash);
1176     strcatW(path, e->szObjectName);
1177     if (e->szInstanceName)
1178     {
1179         strcatW(path, lparen);
1180         if (e->szParentInstance)
1181         {
1182             strcatW(path, e->szParentInstance);
1183             strcatW(path, fslash);
1184         }
1185         strcatW(path, e->szInstanceName);
1186         sprintfW(instance, fmt, e->dwInstanceIndex);
1187         strcatW(path, instance);
1188         strcatW(path, rparen);
1189     }
1190     strcatW(path, bslash);
1191     strcatW(path, e->szCounterName);
1192 
1193     len = strlenW(path) + 1;
1194     if (*buflen >= len) strcpyW(buffer, path);
1195     else ret = PDH_MORE_DATA;
1196     *buflen = len;
1197     return ret;
1198 }
1199 
1200 /***********************************************************************
1201  *              PdhEnumObjectItemsA   (PDH.@)
1202  */
1203 PDH_STATUS WINAPI PdhEnumObjectItemsA(LPCSTR szDataSource, LPCSTR szMachineName, LPCSTR szObjectName,
1204                                       LPSTR mszCounterList, LPDWORD pcchCounterListLength, LPSTR mszInstanceList,
1205                                       LPDWORD pcchInstanceListLength, DWORD dwDetailLevel, DWORD dwFlags)
1206 {
1207     FIXME("%s, %s, %s, %p, %p, %p, %p, %d, 0x%x: stub\n", debugstr_a(szDataSource), debugstr_a(szMachineName),
1208          debugstr_a(szObjectName), mszCounterList, pcchCounterListLength, mszInstanceList,
1209          pcchInstanceListLength, dwDetailLevel, dwFlags);
1210 
1211     return PDH_NOT_IMPLEMENTED;
1212 }
1213 
1214 /***********************************************************************
1215  *              PdhEnumObjectItemsW   (PDH.@)
1216  */
1217 PDH_STATUS WINAPI PdhEnumObjectItemsW(LPCWSTR szDataSource, LPCWSTR szMachineName, LPCWSTR szObjectName,
1218                                       LPWSTR mszCounterList, LPDWORD pcchCounterListLength, LPWSTR mszInstanceList,
1219                                       LPDWORD pcchInstanceListLength, DWORD dwDetailLevel, DWORD dwFlags)
1220 {
1221     FIXME("%s, %s, %s, %p, %p, %p, %p, %d, 0x%x: stub\n", debugstr_w(szDataSource), debugstr_w(szMachineName),
1222          debugstr_w(szObjectName), mszCounterList, pcchCounterListLength, mszInstanceList,
1223          pcchInstanceListLength, dwDetailLevel, dwFlags);
1224 
1225     return PDH_NOT_IMPLEMENTED;
1226 }
1227 
1228 /***********************************************************************
1229  *              PdhSetDefaultRealTimeDataSource   (PDH.@)
1230  */
1231 PDH_STATUS WINAPI PdhSetDefaultRealTimeDataSource( DWORD source )
1232 {
1233     FIXME("%u\n", source);
1234     return ERROR_SUCCESS;
1235 }
1236 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.