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 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/heap.h" 36 #include "wine/list.h" 37 #include "wine/unicode.h" 38 39 WINE_DEFAULT_DEBUG_CHANNEL(pdh); 40 41 static CRITICAL_SECTION pdh_handle_cs; 42 static CRITICAL_SECTION_DEBUG pdh_handle_cs_debug = 43 { 44 0, 0, &pdh_handle_cs, 45 { &pdh_handle_cs_debug.ProcessLocksList, 46 &pdh_handle_cs_debug.ProcessLocksList }, 47 0, 0, { (DWORD_PTR)(__FILE__ ": pdh_handle_cs") } 48 }; 49 static CRITICAL_SECTION pdh_handle_cs = { &pdh_handle_cs_debug, -1, 0, 0, 0, 0 }; 50 51 static inline WCHAR *pdh_strdup( const WCHAR *src ) 52 { 53 WCHAR *dst; 54 55 if (!src) return NULL; 56 if ((dst = heap_alloc( (strlenW( src ) + 1) * sizeof(WCHAR) ))) strcpyW( dst, src ); 57 return dst; 58 } 59 60 static inline WCHAR *pdh_strdup_aw( const char *src ) 61 { 62 int len; 63 WCHAR *dst; 64 65 if (!src) return NULL; 66 len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); 67 if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len ); 68 return dst; 69 } 70 71 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 72 { 73 TRACE("(0x%p, %d, %p)\n",hinstDLL,fdwReason,lpvReserved); 74 switch (fdwReason) 75 { 76 case DLL_WINE_PREATTACH: 77 return FALSE; /* prefer native version */ 78 case DLL_PROCESS_ATTACH: 79 DisableThreadLibraryCalls(hinstDLL); 80 break; 81 case DLL_PROCESS_DETACH: 82 if (lpvReserved) break; 83 DeleteCriticalSection(&pdh_handle_cs); 84 break; 85 } 86 87 return TRUE; 88 } 89 90 union value 91 { 92 LONG longvalue; 93 double doublevalue; 94 LONGLONG largevalue; 95 }; 96 97 struct counter 98 { 99 DWORD magic; /* signature */ 100 struct list entry; /* list entry */ 101 WCHAR *path; /* identifier */ 102 DWORD type; /* counter type */ 103 DWORD status; /* update status */ 104 LONG scale; /* scale factor */ 105 LONG defaultscale; /* default scale factor */ 106 DWORD_PTR user; /* user data */ 107 DWORD_PTR queryuser; /* query user data */ 108 LONGLONG base; /* samples per second */ 109 FILETIME stamp; /* time stamp */ 110 void (CALLBACK *collect)( struct counter * ); /* collect callback */ 111 union value one; /* first value */ 112 union value two; /* second value */ 113 }; 114 115 #define PDH_MAGIC_COUNTER 0x50444831 /* 'PDH1' */ 116 117 static struct counter *create_counter( void ) 118 { 119 struct counter *counter; 120 121 if ((counter = heap_alloc_zero( sizeof(struct counter) ))) 122 { 123 counter->magic = PDH_MAGIC_COUNTER; 124 return counter; 125 } 126 return NULL; 127 } 128 129 static void destroy_counter( struct counter *counter ) 130 { 131 counter->magic = 0; 132 heap_free( counter->path ); 133 heap_free( counter ); 134 } 135 136 #define PDH_MAGIC_QUERY 0x50444830 /* 'PDH0' */ 137 138 struct query 139 { 140 DWORD magic; /* signature */ 141 DWORD_PTR user; /* user data */ 142 HANDLE thread; /* collect thread */ 143 DWORD interval; /* collect interval */ 144 HANDLE wait; /* wait event */ 145 HANDLE stop; /* stop event */ 146 struct list counters; /* counter list */ 147 }; 148 149 static struct query *create_query( void ) 150 { 151 struct query *query; 152 153 if ((query = heap_alloc_zero( sizeof(struct query) ))) 154 { 155 query->magic = PDH_MAGIC_QUERY; 156 list_init( &query->counters ); 157 return query; 158 } 159 return NULL; 160 } 161 162 static void destroy_query( struct query *query ) 163 { 164 query->magic = 0; 165 heap_free( query ); 166 } 167 168 struct source 169 { 170 DWORD index; /* name index */ 171 const WCHAR *path; /* identifier */ 172 void (CALLBACK *collect)( struct counter * ); /* collect callback */ 173 DWORD type; /* counter type */ 174 LONG scale; /* default scale factor */ 175 LONGLONG base; /* samples per second */ 176 }; 177 178 static const WCHAR path_processor_time[] = 179 {'\\','P','r','o','c','e','s','s','o','r','(','_','T','o','t','a','l',')', 180 '\\','%',' ','P','r','o','c','e','s','s','o','r',' ','T','i','m','e',0}; 181 static const WCHAR path_uptime[] = 182 {'\\','S','y','s','t','e','m', '\\', 'S','y','s','t','e','m',' ','U','p',' ','T','i','m','e',0}; 183 184 static void CALLBACK collect_processor_time( struct counter *counter ) 185 { 186 counter->two.largevalue = 500000; /* FIXME */ 187 counter->status = PDH_CSTATUS_VALID_DATA; 188 } 189 190 static void CALLBACK collect_uptime( struct counter *counter ) 191 { 192 counter->two.largevalue = GetTickCount64(); 193 counter->status = PDH_CSTATUS_VALID_DATA; 194 } 195 196 #define TYPE_PROCESSOR_TIME \ 197 (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | \ 198 PERF_INVERSE_COUNTER | PERF_DISPLAY_PERCENT) 199 200 #define TYPE_UPTIME \ 201 (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_ELAPSED | PERF_OBJECT_TIMER | PERF_DISPLAY_SECONDS) 202 203 /* counter source registry */ 204 static const struct source counter_sources[] = 205 { 206 { 6, path_processor_time, collect_processor_time, TYPE_PROCESSOR_TIME, -5, 10000000 }, 207 { 674, path_uptime, collect_uptime, TYPE_UPTIME, -3, 1000 } 208 }; 209 210 static BOOL is_local_machine( const WCHAR *name, DWORD len ) 211 { 212 WCHAR buf[MAX_COMPUTERNAME_LENGTH + 1]; 213 DWORD buflen = ARRAY_SIZE(buf); 214 215 if (!GetComputerNameW( buf, &buflen )) return FALSE; 216 return len == buflen && !memicmpW( name, buf, buflen ); 217 } 218 219 static BOOL pdh_match_path( LPCWSTR fullpath, LPCWSTR path ) 220 { 221 const WCHAR *p; 222 223 if (path[0] == '\\' && path[1] == '\\' && (p = strchrW( path + 2, '\\' )) && 224 is_local_machine( path + 2, p - path - 2 )) 225 { 226 path += p - path; 227 } 228 if (strchrW( path, '\\' )) p = fullpath; 229 else p = strrchrW( fullpath, '\\' ) + 1; 230 return !strcmpW( p, path ); 231 } 232 233 /*********************************************************************** 234 * PdhAddCounterA (PDH.@) 235 */ 236 PDH_STATUS WINAPI PdhAddCounterA( PDH_HQUERY query, LPCSTR path, 237 DWORD_PTR userdata, PDH_HCOUNTER *counter ) 238 { 239 PDH_STATUS ret; 240 WCHAR *pathW; 241 242 TRACE("%p %s %lx %p\n", query, debugstr_a(path), userdata, counter); 243 244 if (!path) return PDH_INVALID_ARGUMENT; 245 246 if (!(pathW = pdh_strdup_aw( path ))) 247 return PDH_MEMORY_ALLOCATION_FAILURE; 248 249 ret = PdhAddCounterW( query, pathW, userdata, counter ); 250 251 heap_free( pathW ); 252 return ret; 253 } 254 255 /*********************************************************************** 256 * PdhAddCounterW (PDH.@) 257 */ 258 PDH_STATUS WINAPI PdhAddCounterW( PDH_HQUERY hquery, LPCWSTR path, 259 DWORD_PTR userdata, PDH_HCOUNTER *hcounter ) 260 { 261 struct query *query = hquery; 262 struct counter *counter; 263 unsigned int i; 264 265 TRACE("%p %s %lx %p\n", hquery, debugstr_w(path), userdata, hcounter); 266 267 if (!path || !hcounter) return PDH_INVALID_ARGUMENT; 268 269 EnterCriticalSection( &pdh_handle_cs ); 270 if (!query || query->magic != PDH_MAGIC_QUERY) 271 { 272 LeaveCriticalSection( &pdh_handle_cs ); 273 return PDH_INVALID_HANDLE; 274 } 275 276 *hcounter = NULL; 277 for (i = 0; i < ARRAY_SIZE(counter_sources); i++) 278 { 279 if (pdh_match_path( counter_sources[i].path, path )) 280 { 281 if ((counter = create_counter())) 282 { 283 counter->path = pdh_strdup( counter_sources[i].path ); 284 counter->collect = counter_sources[i].collect; 285 counter->type = counter_sources[i].type; 286 counter->defaultscale = counter_sources[i].scale; 287 counter->base = counter_sources[i].base; 288 counter->queryuser = query->user; 289 counter->user = userdata; 290 291 list_add_tail( &query->counters, &counter->entry ); 292 *hcounter = counter; 293 294 LeaveCriticalSection( &pdh_handle_cs ); 295 return ERROR_SUCCESS; 296 } 297 LeaveCriticalSection( &pdh_handle_cs ); 298 return PDH_MEMORY_ALLOCATION_FAILURE; 299 } 300 } 301 LeaveCriticalSection( &pdh_handle_cs ); 302 return PDH_CSTATUS_NO_COUNTER; 303 } 304 305 /*********************************************************************** 306 * PdhAddEnglishCounterA (PDH.@) 307 */ 308 PDH_STATUS WINAPI PdhAddEnglishCounterA( PDH_HQUERY query, LPCSTR path, 309 DWORD_PTR userdata, PDH_HCOUNTER *counter ) 310 { 311 TRACE("%p %s %lx %p\n", query, debugstr_a(path), userdata, counter); 312 313 if (!query) return PDH_INVALID_ARGUMENT; 314 return PdhAddCounterA( query, path, userdata, counter ); 315 } 316 317 /*********************************************************************** 318 * PdhAddEnglishCounterW (PDH.@) 319 */ 320 PDH_STATUS WINAPI PdhAddEnglishCounterW( PDH_HQUERY query, LPCWSTR path, 321 DWORD_PTR userdata, PDH_HCOUNTER *counter ) 322 { 323 TRACE("%p %s %lx %p\n", query, debugstr_w(path), userdata, counter); 324 325 if (!query) return PDH_INVALID_ARGUMENT; 326 return PdhAddCounterW( query, path, userdata, counter ); 327 } 328 329 /* caller must hold counter lock */ 330 static PDH_STATUS format_value( struct counter *counter, DWORD format, union value *raw1, 331 union value *raw2, PDH_FMT_COUNTERVALUE *value ) 332 { 333 LONG factor; 334 335 factor = counter->scale ? counter->scale : counter->defaultscale; 336 if (format & PDH_FMT_LONG) 337 { 338 if (format & PDH_FMT_1000) value->u.longValue = raw2->longvalue * 1000; 339 else value->u.longValue = raw2->longvalue * pow( 10, factor ); 340 } 341 else if (format & PDH_FMT_LARGE) 342 { 343 if (format & PDH_FMT_1000) value->u.largeValue = raw2->largevalue * 1000; 344 else value->u.largeValue = raw2->largevalue * pow( 10, factor ); 345 } 346 else if (format & PDH_FMT_DOUBLE) 347 { 348 if (format & PDH_FMT_1000) value->u.doubleValue = raw2->doublevalue * 1000; 349 else value->u.doubleValue = raw2->doublevalue * pow( 10, factor ); 350 } 351 else 352 { 353 WARN("unknown format %x\n", format); 354 return PDH_INVALID_ARGUMENT; 355 } 356 return ERROR_SUCCESS; 357 } 358 359 /*********************************************************************** 360 * PdhCalculateCounterFromRawValue (PDH.@) 361 */ 362 PDH_STATUS WINAPI PdhCalculateCounterFromRawValue( PDH_HCOUNTER handle, DWORD format, 363 PPDH_RAW_COUNTER raw1, PPDH_RAW_COUNTER raw2, 364 PPDH_FMT_COUNTERVALUE value ) 365 { 366 PDH_STATUS ret; 367 struct counter *counter = handle; 368 369 TRACE("%p 0x%08x %p %p %p\n", handle, format, raw1, raw2, value); 370 371 if (!value) return PDH_INVALID_ARGUMENT; 372 373 EnterCriticalSection( &pdh_handle_cs ); 374 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 375 { 376 LeaveCriticalSection( &pdh_handle_cs ); 377 return PDH_INVALID_HANDLE; 378 } 379 380 ret = format_value( counter, format, (union value *)&raw1->SecondValue, 381 (union value *)&raw2->SecondValue, value ); 382 383 LeaveCriticalSection( &pdh_handle_cs ); 384 return ret; 385 } 386 387 388 /*********************************************************************** 389 * PdhCloseQuery (PDH.@) 390 */ 391 PDH_STATUS WINAPI PdhCloseQuery( PDH_HQUERY handle ) 392 { 393 struct query *query = handle; 394 struct list *item, *next; 395 396 TRACE("%p\n", handle); 397 398 EnterCriticalSection( &pdh_handle_cs ); 399 if (!query || query->magic != PDH_MAGIC_QUERY) 400 { 401 LeaveCriticalSection( &pdh_handle_cs ); 402 return PDH_INVALID_HANDLE; 403 } 404 405 if (query->thread) 406 { 407 HANDLE thread = query->thread; 408 SetEvent( query->stop ); 409 LeaveCriticalSection( &pdh_handle_cs ); 410 411 WaitForSingleObject( thread, INFINITE ); 412 413 EnterCriticalSection( &pdh_handle_cs ); 414 if (query->magic != PDH_MAGIC_QUERY) 415 { 416 LeaveCriticalSection( &pdh_handle_cs ); 417 return ERROR_SUCCESS; 418 } 419 CloseHandle( query->stop ); 420 CloseHandle( query->thread ); 421 query->thread = NULL; 422 } 423 424 LIST_FOR_EACH_SAFE( item, next, &query->counters ) 425 { 426 struct counter *counter = LIST_ENTRY( item, struct counter, entry ); 427 428 list_remove( &counter->entry ); 429 destroy_counter( counter ); 430 } 431 432 destroy_query( query ); 433 434 LeaveCriticalSection( &pdh_handle_cs ); 435 return ERROR_SUCCESS; 436 } 437 438 /* caller must hold query lock */ 439 static void collect_query_data( struct query *query ) 440 { 441 struct list *item; 442 443 LIST_FOR_EACH( item, &query->counters ) 444 { 445 SYSTEMTIME time; 446 struct counter *counter = LIST_ENTRY( item, struct counter, entry ); 447 448 counter->collect( counter ); 449 450 GetLocalTime( &time ); 451 SystemTimeToFileTime( &time, &counter->stamp ); 452 } 453 } 454 455 /*********************************************************************** 456 * PdhCollectQueryData (PDH.@) 457 */ 458 PDH_STATUS WINAPI PdhCollectQueryData( PDH_HQUERY handle ) 459 { 460 struct query *query = handle; 461 462 TRACE("%p\n", handle); 463 464 EnterCriticalSection( &pdh_handle_cs ); 465 if (!query || query->magic != PDH_MAGIC_QUERY) 466 { 467 LeaveCriticalSection( &pdh_handle_cs ); 468 return PDH_INVALID_HANDLE; 469 } 470 471 if (list_empty( &query->counters )) 472 { 473 LeaveCriticalSection( &pdh_handle_cs ); 474 return PDH_NO_DATA; 475 } 476 477 collect_query_data( query ); 478 479 LeaveCriticalSection( &pdh_handle_cs ); 480 return ERROR_SUCCESS; 481 } 482 483 static DWORD CALLBACK collect_query_thread( void *arg ) 484 { 485 struct query *query = arg; 486 DWORD interval = query->interval; 487 HANDLE stop = query->stop; 488 489 for (;;) 490 { 491 if (WaitForSingleObject( stop, interval ) != WAIT_TIMEOUT) ExitThread( 0 ); 492 493 EnterCriticalSection( &pdh_handle_cs ); 494 if (query->magic != PDH_MAGIC_QUERY) 495 { 496 LeaveCriticalSection( &pdh_handle_cs ); 497 ExitThread( PDH_INVALID_HANDLE ); 498 } 499 500 collect_query_data( query ); 501 502 if (!SetEvent( query->wait )) 503 { 504 LeaveCriticalSection( &pdh_handle_cs ); 505 ExitThread( 0 ); 506 } 507 LeaveCriticalSection( &pdh_handle_cs ); 508 } 509 } 510 511 /*********************************************************************** 512 * PdhCollectQueryDataEx (PDH.@) 513 */ 514 PDH_STATUS WINAPI PdhCollectQueryDataEx( PDH_HQUERY handle, DWORD interval, HANDLE event ) 515 { 516 PDH_STATUS ret; 517 struct query *query = handle; 518 519 TRACE("%p %d %p\n", handle, interval, event); 520 521 EnterCriticalSection( &pdh_handle_cs ); 522 if (!query || query->magic != PDH_MAGIC_QUERY) 523 { 524 LeaveCriticalSection( &pdh_handle_cs ); 525 return PDH_INVALID_HANDLE; 526 } 527 if (list_empty( &query->counters )) 528 { 529 LeaveCriticalSection( &pdh_handle_cs ); 530 return PDH_NO_DATA; 531 } 532 if (query->thread) 533 { 534 HANDLE thread = query->thread; 535 SetEvent( query->stop ); 536 LeaveCriticalSection( &pdh_handle_cs ); 537 538 WaitForSingleObject( thread, INFINITE ); 539 540 EnterCriticalSection( &pdh_handle_cs ); 541 if (query->magic != PDH_MAGIC_QUERY) 542 { 543 LeaveCriticalSection( &pdh_handle_cs ); 544 return PDH_INVALID_HANDLE; 545 } 546 CloseHandle( query->thread ); 547 query->thread = NULL; 548 } 549 else if (!(query->stop = CreateEventW( NULL, FALSE, FALSE, NULL ))) 550 { 551 ret = GetLastError(); 552 LeaveCriticalSection( &pdh_handle_cs ); 553 return ret; 554 } 555 query->wait = event; 556 query->interval = interval * 1000; 557 if (!(query->thread = CreateThread( NULL, 0, collect_query_thread, query, 0, NULL ))) 558 { 559 ret = GetLastError(); 560 CloseHandle( query->stop ); 561 562 LeaveCriticalSection( &pdh_handle_cs ); 563 return ret; 564 } 565 566 LeaveCriticalSection( &pdh_handle_cs ); 567 return ERROR_SUCCESS; 568 } 569 570 /*********************************************************************** 571 * PdhCollectQueryDataWithTime (PDH.@) 572 */ 573 PDH_STATUS WINAPI PdhCollectQueryDataWithTime( PDH_HQUERY handle, LONGLONG *timestamp ) 574 { 575 struct query *query = handle; 576 struct counter *counter; 577 struct list *item; 578 579 TRACE("%p %p\n", handle, timestamp); 580 581 if (!timestamp) return PDH_INVALID_ARGUMENT; 582 583 EnterCriticalSection( &pdh_handle_cs ); 584 if (!query || query->magic != PDH_MAGIC_QUERY) 585 { 586 LeaveCriticalSection( &pdh_handle_cs ); 587 return PDH_INVALID_HANDLE; 588 } 589 if (list_empty( &query->counters )) 590 { 591 LeaveCriticalSection( &pdh_handle_cs ); 592 return PDH_NO_DATA; 593 } 594 595 collect_query_data( query ); 596 597 item = list_head( &query->counters ); 598 counter = LIST_ENTRY( item, struct counter, entry ); 599 600 *timestamp = ((LONGLONG)counter->stamp.dwHighDateTime << 32) | counter->stamp.dwLowDateTime; 601 602 LeaveCriticalSection( &pdh_handle_cs ); 603 return ERROR_SUCCESS; 604 } 605 606 /*********************************************************************** 607 * PdhExpandWildCardPathA (PDH.@) 608 */ 609 PDH_STATUS WINAPI PdhExpandWildCardPathA( LPCSTR szDataSource, LPCSTR szWildCardPath, LPSTR mszExpandedPathList, LPDWORD pcchPathListLength, DWORD dwFlags ) 610 { 611 FIXME("%s, %s, %p, %p, 0x%x: stub\n", debugstr_a(szDataSource), debugstr_a(szWildCardPath), mszExpandedPathList, pcchPathListLength, dwFlags); 612 return PDH_NOT_IMPLEMENTED; 613 } 614 615 /*********************************************************************** 616 * PdhExpandWildCardPathW (PDH.@) 617 */ 618 PDH_STATUS WINAPI PdhExpandWildCardPathW( LPCWSTR szDataSource, LPCWSTR szWildCardPath, LPWSTR mszExpandedPathList, LPDWORD pcchPathListLength, DWORD dwFlags ) 619 { 620 FIXME("%s, %s, %p, %p, 0x%x: stub\n", debugstr_w(szDataSource), debugstr_w(szWildCardPath), mszExpandedPathList, pcchPathListLength, dwFlags); 621 return PDH_NOT_IMPLEMENTED; 622 } 623 624 /*********************************************************************** 625 * PdhExpandCounterPathA (PDH.@) 626 */ 627 PDH_STATUS WINAPI PdhExpandCounterPathA( LPCSTR szWildCardPath, LPSTR mszExpandedPathList, LPDWORD pcchPathListLength ) 628 { 629 FIXME("%s, %p, %p: stub\n", debugstr_a(szWildCardPath), mszExpandedPathList, pcchPathListLength); 630 return PdhExpandWildCardPathA(NULL, szWildCardPath, mszExpandedPathList, pcchPathListLength, 0); 631 } 632 633 /*********************************************************************** 634 * PdhExpandCounterPathW (PDH.@) 635 */ 636 PDH_STATUS WINAPI PdhExpandCounterPathW( LPCWSTR szWildCardPath, LPWSTR mszExpandedPathList, LPDWORD pcchPathListLength ) 637 { 638 FIXME("%s, %p, %p: stub\n", debugstr_w(szWildCardPath), mszExpandedPathList, pcchPathListLength); 639 return PdhExpandWildCardPathW(NULL, szWildCardPath, mszExpandedPathList, pcchPathListLength, 0); 640 } 641 642 /*********************************************************************** 643 * PdhGetCounterInfoA (PDH.@) 644 */ 645 PDH_STATUS WINAPI PdhGetCounterInfoA( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_A info ) 646 { 647 struct counter *counter = handle; 648 649 TRACE("%p %d %p %p\n", handle, text, size, info); 650 651 EnterCriticalSection( &pdh_handle_cs ); 652 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 653 { 654 LeaveCriticalSection( &pdh_handle_cs ); 655 return PDH_INVALID_HANDLE; 656 } 657 if (!size) 658 { 659 LeaveCriticalSection( &pdh_handle_cs ); 660 return PDH_INVALID_ARGUMENT; 661 } 662 if (*size < sizeof(PDH_COUNTER_INFO_A)) 663 { 664 *size = sizeof(PDH_COUNTER_INFO_A); 665 LeaveCriticalSection( &pdh_handle_cs ); 666 return PDH_MORE_DATA; 667 } 668 669 memset( info, 0, sizeof(PDH_COUNTER_INFO_A) ); 670 671 info->dwType = counter->type; 672 info->CStatus = counter->status; 673 info->lScale = counter->scale; 674 info->lDefaultScale = counter->defaultscale; 675 info->dwUserData = counter->user; 676 info->dwQueryUserData = counter->queryuser; 677 678 *size = sizeof(PDH_COUNTER_INFO_A); 679 680 LeaveCriticalSection( &pdh_handle_cs ); 681 return ERROR_SUCCESS; 682 } 683 684 /*********************************************************************** 685 * PdhGetCounterInfoW (PDH.@) 686 */ 687 PDH_STATUS WINAPI PdhGetCounterInfoW( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_W info ) 688 { 689 struct counter *counter = handle; 690 691 TRACE("%p %d %p %p\n", handle, text, size, info); 692 693 EnterCriticalSection( &pdh_handle_cs ); 694 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 695 { 696 LeaveCriticalSection( &pdh_handle_cs ); 697 return PDH_INVALID_HANDLE; 698 } 699 if (!size) 700 { 701 LeaveCriticalSection( &pdh_handle_cs ); 702 return PDH_INVALID_ARGUMENT; 703 } 704 if (*size < sizeof(PDH_COUNTER_INFO_W)) 705 { 706 *size = sizeof(PDH_COUNTER_INFO_W); 707 LeaveCriticalSection( &pdh_handle_cs ); 708 return PDH_MORE_DATA; 709 } 710 711 memset( info, 0, sizeof(PDH_COUNTER_INFO_W) ); 712 713 info->dwType = counter->type; 714 info->CStatus = counter->status; 715 info->lScale = counter->scale; 716 info->lDefaultScale = counter->defaultscale; 717 info->dwUserData = counter->user; 718 info->dwQueryUserData = counter->queryuser; 719 720 *size = sizeof(PDH_COUNTER_INFO_W); 721 722 LeaveCriticalSection( &pdh_handle_cs ); 723 return ERROR_SUCCESS; 724 } 725 726 /*********************************************************************** 727 * PdhGetCounterTimeBase (PDH.@) 728 */ 729 PDH_STATUS WINAPI PdhGetCounterTimeBase( PDH_HCOUNTER handle, LONGLONG *base ) 730 { 731 struct counter *counter = handle; 732 733 TRACE("%p %p\n", handle, base); 734 735 if (!base) return PDH_INVALID_ARGUMENT; 736 737 EnterCriticalSection( &pdh_handle_cs ); 738 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 739 { 740 LeaveCriticalSection( &pdh_handle_cs ); 741 return PDH_INVALID_HANDLE; 742 } 743 744 *base = counter->base; 745 746 LeaveCriticalSection( &pdh_handle_cs ); 747 return ERROR_SUCCESS; 748 } 749 750 /*********************************************************************** 751 * PdhGetDllVersion (PDH.@) 752 */ 753 PDH_STATUS WINAPI PdhGetDllVersion( LPDWORD version ) 754 { 755 if (!version) 756 return PDH_INVALID_ARGUMENT; 757 758 *version = PDH_VERSION; 759 760 return ERROR_SUCCESS; 761 } 762 763 /*********************************************************************** 764 * PdhGetFormattedCounterValue (PDH.@) 765 */ 766 PDH_STATUS WINAPI PdhGetFormattedCounterValue( PDH_HCOUNTER handle, DWORD format, 767 LPDWORD type, PPDH_FMT_COUNTERVALUE value ) 768 { 769 PDH_STATUS ret; 770 struct counter *counter = handle; 771 772 TRACE("%p %x %p %p\n", handle, format, type, value); 773 774 if (!value) return PDH_INVALID_ARGUMENT; 775 776 EnterCriticalSection( &pdh_handle_cs ); 777 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 778 { 779 LeaveCriticalSection( &pdh_handle_cs ); 780 return PDH_INVALID_HANDLE; 781 } 782 if (counter->status) 783 { 784 LeaveCriticalSection( &pdh_handle_cs ); 785 return PDH_INVALID_DATA; 786 } 787 if (!(ret = format_value( counter, format, &counter->one, &counter->two, value ))) 788 { 789 value->CStatus = ERROR_SUCCESS; 790 if (type) *type = counter->type; 791 } 792 793 LeaveCriticalSection( &pdh_handle_cs ); 794 return ret; 795 } 796 797 /*********************************************************************** 798 * PdhGetRawCounterValue (PDH.@) 799 */ 800 PDH_STATUS WINAPI PdhGetRawCounterValue( PDH_HCOUNTER handle, LPDWORD type, 801 PPDH_RAW_COUNTER value ) 802 { 803 struct counter *counter = handle; 804 805 TRACE("%p %p %p\n", handle, type, value); 806 807 if (!value) return PDH_INVALID_ARGUMENT; 808 809 EnterCriticalSection( &pdh_handle_cs ); 810 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 811 { 812 LeaveCriticalSection( &pdh_handle_cs ); 813 return PDH_INVALID_HANDLE; 814 } 815 816 value->CStatus = counter->status; 817 value->TimeStamp.dwLowDateTime = counter->stamp.dwLowDateTime; 818 value->TimeStamp.dwHighDateTime = counter->stamp.dwHighDateTime; 819 value->FirstValue = counter->one.largevalue; 820 value->SecondValue = counter->two.largevalue; 821 value->MultiCount = 1; /* FIXME */ 822 823 if (type) *type = counter->type; 824 825 LeaveCriticalSection( &pdh_handle_cs ); 826 return ERROR_SUCCESS; 827 } 828 829 /*********************************************************************** 830 * PdhLookupPerfIndexByNameA (PDH.@) 831 */ 832 PDH_STATUS WINAPI PdhLookupPerfIndexByNameA( LPCSTR machine, LPCSTR name, LPDWORD index ) 833 { 834 PDH_STATUS ret; 835 WCHAR *machineW = NULL; 836 WCHAR *nameW; 837 838 TRACE("%s %s %p\n", debugstr_a(machine), debugstr_a(name), index); 839 840 if (!name) return PDH_INVALID_ARGUMENT; 841 842 if (machine && !(machineW = pdh_strdup_aw( machine ))) return PDH_MEMORY_ALLOCATION_FAILURE; 843 844 if (!(nameW = pdh_strdup_aw( name ))) 845 return PDH_MEMORY_ALLOCATION_FAILURE; 846 847 ret = PdhLookupPerfIndexByNameW( machineW, nameW, index ); 848 849 heap_free( nameW ); 850 heap_free( machineW ); 851 return ret; 852 } 853 854 /*********************************************************************** 855 * PdhLookupPerfIndexByNameW (PDH.@) 856 */ 857 PDH_STATUS WINAPI PdhLookupPerfIndexByNameW( LPCWSTR machine, LPCWSTR name, LPDWORD index ) 858 { 859 unsigned int i; 860 861 TRACE("%s %s %p\n", debugstr_w(machine), debugstr_w(name), index); 862 863 if (!name || !index) return PDH_INVALID_ARGUMENT; 864 865 if (machine) 866 { 867 FIXME("remote machine not supported\n"); 868 return PDH_CSTATUS_NO_MACHINE; 869 } 870 for (i = 0; i < ARRAY_SIZE(counter_sources); i++) 871 { 872 if (pdh_match_path( counter_sources[i].path, name )) 873 { 874 *index = counter_sources[i].index; 875 return ERROR_SUCCESS; 876 } 877 } 878 return PDH_STRING_NOT_FOUND; 879 } 880 881 /*********************************************************************** 882 * PdhLookupPerfNameByIndexA (PDH.@) 883 */ 884 PDH_STATUS WINAPI PdhLookupPerfNameByIndexA( LPCSTR machine, DWORD index, LPSTR buffer, LPDWORD size ) 885 { 886 PDH_STATUS ret; 887 WCHAR *machineW = NULL; 888 WCHAR bufferW[PDH_MAX_COUNTER_NAME]; 889 DWORD sizeW = ARRAY_SIZE(bufferW); 890 891 TRACE("%s %d %p %p\n", debugstr_a(machine), index, buffer, size); 892 893 if (!buffer || !size) return PDH_INVALID_ARGUMENT; 894 895 if (machine && !(machineW = pdh_strdup_aw( machine ))) return PDH_MEMORY_ALLOCATION_FAILURE; 896 897 if (!(ret = PdhLookupPerfNameByIndexW( machineW, index, bufferW, &sizeW ))) 898 { 899 int required = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL ); 900 901 if (size && *size < required) ret = PDH_MORE_DATA; 902 else WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, required, NULL, NULL ); 903 if (size) *size = required; 904 } 905 heap_free( machineW ); 906 return ret; 907 } 908 909 /*********************************************************************** 910 * PdhLookupPerfNameByIndexW (PDH.@) 911 */ 912 PDH_STATUS WINAPI PdhLookupPerfNameByIndexW( LPCWSTR machine, DWORD index, LPWSTR buffer, LPDWORD size ) 913 { 914 PDH_STATUS ret; 915 unsigned int i; 916 917 TRACE("%s %d %p %p\n", debugstr_w(machine), index, buffer, size); 918 919 if (machine) 920 { 921 FIXME("remote machine not supported\n"); 922 return PDH_CSTATUS_NO_MACHINE; 923 } 924 925 if (!buffer || !size) return PDH_INVALID_ARGUMENT; 926 if (!index) return ERROR_SUCCESS; 927 928 for (i = 0; i < ARRAY_SIZE(counter_sources); i++) 929 { 930 if (counter_sources[i].index == index) 931 { 932 WCHAR *p = strrchrW( counter_sources[i].path, '\\' ) + 1; 933 unsigned int required = strlenW( p ) + 1; 934 935 if (*size < required) ret = PDH_MORE_DATA; 936 else 937 { 938 strcpyW( buffer, p ); 939 ret = ERROR_SUCCESS; 940 } 941 *size = required; 942 return ret; 943 } 944 } 945 return PDH_INVALID_ARGUMENT; 946 } 947 948 /*********************************************************************** 949 * PdhOpenQueryA (PDH.@) 950 */ 951 PDH_STATUS WINAPI PdhOpenQueryA( LPCSTR source, DWORD_PTR userdata, PDH_HQUERY *query ) 952 { 953 PDH_STATUS ret; 954 WCHAR *sourceW = NULL; 955 956 TRACE("%s %lx %p\n", debugstr_a(source), userdata, query); 957 958 if (source && !(sourceW = pdh_strdup_aw( source ))) return PDH_MEMORY_ALLOCATION_FAILURE; 959 960 ret = PdhOpenQueryW( sourceW, userdata, query ); 961 heap_free( sourceW ); 962 963 return ret; 964 } 965 966 /*********************************************************************** 967 * PdhOpenQueryW (PDH.@) 968 */ 969 PDH_STATUS WINAPI PdhOpenQueryW( LPCWSTR source, DWORD_PTR userdata, PDH_HQUERY *handle ) 970 { 971 struct query *query; 972 973 TRACE("%s %lx %p\n", debugstr_w(source), userdata, handle); 974 975 if (!handle) return PDH_INVALID_ARGUMENT; 976 977 if (source) 978 { 979 FIXME("log file data source not supported\n"); 980 return PDH_INVALID_ARGUMENT; 981 } 982 if ((query = create_query())) 983 { 984 query->user = userdata; 985 *handle = query; 986 987 return ERROR_SUCCESS; 988 } 989 return PDH_MEMORY_ALLOCATION_FAILURE; 990 } 991 992 /*********************************************************************** 993 * PdhRemoveCounter (PDH.@) 994 */ 995 PDH_STATUS WINAPI PdhRemoveCounter( PDH_HCOUNTER handle ) 996 { 997 struct counter *counter = handle; 998 999 TRACE("%p\n", handle); 1000 1001 EnterCriticalSection( &pdh_handle_cs ); 1002 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 1003 { 1004 LeaveCriticalSection( &pdh_handle_cs ); 1005 return PDH_INVALID_HANDLE; 1006 } 1007 1008 list_remove( &counter->entry ); 1009 destroy_counter( counter ); 1010 1011 LeaveCriticalSection( &pdh_handle_cs ); 1012 return ERROR_SUCCESS; 1013 } 1014 1015 /*********************************************************************** 1016 * PdhSetCounterScaleFactor (PDH.@) 1017 */ 1018 PDH_STATUS WINAPI PdhSetCounterScaleFactor( PDH_HCOUNTER handle, LONG factor ) 1019 { 1020 struct counter *counter = handle; 1021 1022 TRACE("%p\n", handle); 1023 1024 EnterCriticalSection( &pdh_handle_cs ); 1025 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 1026 { 1027 LeaveCriticalSection( &pdh_handle_cs ); 1028 return PDH_INVALID_HANDLE; 1029 } 1030 if (factor < PDH_MIN_SCALE || factor > PDH_MAX_SCALE) 1031 { 1032 LeaveCriticalSection( &pdh_handle_cs ); 1033 return PDH_INVALID_ARGUMENT; 1034 } 1035 1036 counter->scale = factor; 1037 1038 LeaveCriticalSection( &pdh_handle_cs ); 1039 return ERROR_SUCCESS; 1040 } 1041 1042 /*********************************************************************** 1043 * PdhValidatePathA (PDH.@) 1044 */ 1045 PDH_STATUS WINAPI PdhValidatePathA( LPCSTR path ) 1046 { 1047 PDH_STATUS ret; 1048 WCHAR *pathW; 1049 1050 TRACE("%s\n", debugstr_a(path)); 1051 1052 if (!path) return PDH_INVALID_ARGUMENT; 1053 if (!(pathW = pdh_strdup_aw( path ))) return PDH_MEMORY_ALLOCATION_FAILURE; 1054 1055 ret = PdhValidatePathW( pathW ); 1056 1057 heap_free( pathW ); 1058 return ret; 1059 } 1060 1061 static PDH_STATUS validate_path( LPCWSTR path ) 1062 { 1063 if (!path || !*path) return PDH_INVALID_ARGUMENT; 1064 if (*path++ != '\\' || !strchrW( path, '\\' )) return PDH_CSTATUS_BAD_COUNTERNAME; 1065 return ERROR_SUCCESS; 1066 } 1067 1068 /*********************************************************************** 1069 * PdhValidatePathW (PDH.@) 1070 */ 1071 PDH_STATUS WINAPI PdhValidatePathW( LPCWSTR path ) 1072 { 1073 PDH_STATUS ret; 1074 unsigned int i; 1075 1076 TRACE("%s\n", debugstr_w(path)); 1077 1078 if ((ret = validate_path( path ))) return ret; 1079 1080 for (i = 0; i < ARRAY_SIZE(counter_sources); i++) 1081 if (pdh_match_path( counter_sources[i].path, path )) return ERROR_SUCCESS; 1082 1083 return PDH_CSTATUS_NO_COUNTER; 1084 } 1085 1086 /*********************************************************************** 1087 * PdhVbAddCounter (PDH.@) 1088 */ 1089 PDH_STATUS WINAPI PdhVbAddCounter( PDH_HQUERY query, LPCSTR path, PDH_HCOUNTER *counter ) 1090 { 1091 FIXME("%p, %s, %p: stub!\n", query, debugstr_a(path), counter); 1092 1093 if (!path) return PDH_INVALID_ARGUMENT; 1094 1095 return PDH_NOT_IMPLEMENTED; 1096 } 1097 1098 /*********************************************************************** 1099 * PdhValidatePathExA (PDH.@) 1100 */ 1101 PDH_STATUS WINAPI PdhValidatePathExA( PDH_HLOG source, LPCSTR path ) 1102 { 1103 TRACE("%p %s\n", source, debugstr_a(path)); 1104 1105 if (source) 1106 { 1107 FIXME("log file data source not supported\n"); 1108 return ERROR_SUCCESS; 1109 } 1110 return PdhValidatePathA( path ); 1111 } 1112 1113 /*********************************************************************** 1114 * PdhValidatePathExW (PDH.@) 1115 */ 1116 PDH_STATUS WINAPI PdhValidatePathExW( PDH_HLOG source, LPCWSTR path ) 1117 { 1118 TRACE("%p %s\n", source, debugstr_w(path)); 1119 1120 if (source) 1121 { 1122 FIXME("log file data source not supported\n"); 1123 return ERROR_SUCCESS; 1124 } 1125 return PdhValidatePathW( path ); 1126 } 1127 1128 /*********************************************************************** 1129 * PdhMakeCounterPathA (PDH.@) 1130 */ 1131 PDH_STATUS WINAPI PdhMakeCounterPathA( PDH_COUNTER_PATH_ELEMENTS_A *e, LPSTR buffer, 1132 LPDWORD buflen, DWORD flags ) 1133 { 1134 PDH_STATUS ret = PDH_MEMORY_ALLOCATION_FAILURE; 1135 PDH_COUNTER_PATH_ELEMENTS_W eW; 1136 WCHAR *bufferW; 1137 DWORD buflenW; 1138 1139 TRACE("%p %p %p 0x%08x\n", e, buffer, buflen, flags); 1140 1141 if (!e || !buflen) return PDH_INVALID_ARGUMENT; 1142 1143 memset( &eW, 0, sizeof(eW) ); 1144 if (e->szMachineName && !(eW.szMachineName = pdh_strdup_aw( e->szMachineName ))) goto done; 1145 if (e->szObjectName && !(eW.szObjectName = pdh_strdup_aw( e->szObjectName ))) goto done; 1146 if (e->szInstanceName && !(eW.szInstanceName = pdh_strdup_aw( e->szInstanceName ))) goto done; 1147 if (e->szParentInstance && !(eW.szParentInstance = pdh_strdup_aw( e->szParentInstance ))) goto done; 1148 if (e->szCounterName && !(eW.szCounterName = pdh_strdup_aw( e->szCounterName ))) goto done; 1149 eW.dwInstanceIndex = e->dwInstanceIndex; 1150 1151 buflenW = 0; 1152 ret = PdhMakeCounterPathW( &eW, NULL, &buflenW, flags ); 1153 if (ret == PDH_MORE_DATA) 1154 { 1155 if ((bufferW = heap_alloc( buflenW * sizeof(WCHAR) ))) 1156 { 1157 if (!(ret = PdhMakeCounterPathW( &eW, bufferW, &buflenW, flags ))) 1158 { 1159 int len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL); 1160 if (*buflen >= len) WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, *buflen, NULL, NULL); 1161 else ret = PDH_MORE_DATA; 1162 *buflen = len; 1163 } 1164 heap_free( bufferW ); 1165 } 1166 else 1167 ret = PDH_MEMORY_ALLOCATION_FAILURE; 1168 } 1169 1170 done: 1171 heap_free( eW.szMachineName ); 1172 heap_free( eW.szObjectName ); 1173 heap_free( eW.szInstanceName ); 1174 heap_free( eW.szParentInstance ); 1175 heap_free( eW.szCounterName ); 1176 return ret; 1177 } 1178 1179 /*********************************************************************** 1180 * PdhMakeCounterPathW (PDH.@) 1181 */ 1182 PDH_STATUS WINAPI PdhMakeCounterPathW( PDH_COUNTER_PATH_ELEMENTS_W *e, LPWSTR buffer, 1183 LPDWORD buflen, DWORD flags ) 1184 { 1185 static const WCHAR bslash[] = {'\\',0}; 1186 static const WCHAR fslash[] = {'/',0}; 1187 static const WCHAR lparen[] = {'(',0}; 1188 static const WCHAR rparen[] = {')',0}; 1189 static const WCHAR fmt[] = {'#','%','u',0}; 1190 1191 WCHAR path[PDH_MAX_COUNTER_NAME], instance[12]; 1192 PDH_STATUS ret = ERROR_SUCCESS; 1193 DWORD len; 1194 1195 TRACE("%p %p %p 0x%08x\n", e, buffer, buflen, flags); 1196 1197 if (flags) FIXME("unimplemented flags 0x%08x\n", flags); 1198 1199 if (!e || !e->szCounterName || !e->szObjectName || !buflen) 1200 return PDH_INVALID_ARGUMENT; 1201 1202 path[0] = 0; 1203 if (e->szMachineName) 1204 { 1205 strcatW(path, bslash); 1206 strcatW(path, bslash); 1207 strcatW(path, e->szMachineName); 1208 } 1209 strcatW(path, bslash); 1210 strcatW(path, e->szObjectName); 1211 if (e->szInstanceName) 1212 { 1213 strcatW(path, lparen); 1214 if (e->szParentInstance) 1215 { 1216 strcatW(path, e->szParentInstance); 1217 strcatW(path, fslash); 1218 } 1219 strcatW(path, e->szInstanceName); 1220 sprintfW(instance, fmt, e->dwInstanceIndex); 1221 strcatW(path, instance); 1222 strcatW(path, rparen); 1223 } 1224 strcatW(path, bslash); 1225 strcatW(path, e->szCounterName); 1226 1227 len = strlenW(path) + 1; 1228 if (*buflen >= len) strcpyW(buffer, path); 1229 else ret = PDH_MORE_DATA; 1230 *buflen = len; 1231 return ret; 1232 } 1233 1234 /*********************************************************************** 1235 * PdhEnumObjectItemsA (PDH.@) 1236 */ 1237 PDH_STATUS WINAPI PdhEnumObjectItemsA(LPCSTR szDataSource, LPCSTR szMachineName, LPCSTR szObjectName, 1238 LPSTR mszCounterList, LPDWORD pcchCounterListLength, LPSTR mszInstanceList, 1239 LPDWORD pcchInstanceListLength, DWORD dwDetailLevel, DWORD dwFlags) 1240 { 1241 FIXME("%s, %s, %s, %p, %p, %p, %p, %d, 0x%x: stub\n", debugstr_a(szDataSource), debugstr_a(szMachineName), 1242 debugstr_a(szObjectName), mszCounterList, pcchCounterListLength, mszInstanceList, 1243 pcchInstanceListLength, dwDetailLevel, dwFlags); 1244 1245 return PDH_NOT_IMPLEMENTED; 1246 } 1247 1248 /*********************************************************************** 1249 * PdhEnumObjectItemsW (PDH.@) 1250 */ 1251 PDH_STATUS WINAPI PdhEnumObjectItemsW(LPCWSTR szDataSource, LPCWSTR szMachineName, LPCWSTR szObjectName, 1252 LPWSTR mszCounterList, LPDWORD pcchCounterListLength, LPWSTR mszInstanceList, 1253 LPDWORD pcchInstanceListLength, DWORD dwDetailLevel, DWORD dwFlags) 1254 { 1255 FIXME("%s, %s, %s, %p, %p, %p, %p, %d, 0x%x: stub\n", debugstr_w(szDataSource), debugstr_w(szMachineName), 1256 debugstr_w(szObjectName), mszCounterList, pcchCounterListLength, mszInstanceList, 1257 pcchInstanceListLength, dwDetailLevel, dwFlags); 1258 1259 return PDH_NOT_IMPLEMENTED; 1260 } 1261 1262 /*********************************************************************** 1263 * PdhSetDefaultRealTimeDataSource (PDH.@) 1264 */ 1265 PDH_STATUS WINAPI PdhSetDefaultRealTimeDataSource( DWORD source ) 1266 { 1267 FIXME("%u\n", source); 1268 return ERROR_SUCCESS; 1269 } 1270 1271 /*********************************************************************** 1272 * PdhGetLogFileTypeA (PDH.@) 1273 */ 1274 PDH_STATUS WINAPI PdhGetLogFileTypeA(const char *log, DWORD *type) 1275 { 1276 FIXME("%s, %p: stub\n", debugstr_a(log), type); 1277 return PDH_NOT_IMPLEMENTED; 1278 } 1279 1280 /*********************************************************************** 1281 * PdhGetLogFileTypeW (PDH.@) 1282 */ 1283 PDH_STATUS WINAPI PdhGetLogFileTypeW(const WCHAR *log, DWORD *type) 1284 { 1285 FIXME("%s, %p: stub\n", debugstr_w(log), type); 1286 return PDH_NOT_IMPLEMENTED; 1287 } 1288 1289 /*********************************************************************** 1290 * PdhBindInputDataSourceA (PDH.@) 1291 */ 1292 PDH_STATUS WINAPI PdhBindInputDataSourceA(PDH_HLOG *source, const char *filenamelist) 1293 { 1294 FIXME("%p %s: stub\n", source, debugstr_a(filenamelist)); 1295 return PDH_NOT_IMPLEMENTED; 1296 } 1297 1298 /*********************************************************************** 1299 * PdhBindInputDataSourceW (PDH.@) 1300 */ 1301 PDH_STATUS WINAPI PdhBindInputDataSourceW(PDH_HLOG *source, const WCHAR *filenamelist) 1302 { 1303 FIXME("%p %s: stub\n", source, debugstr_w(filenamelist)); 1304 return PDH_NOT_IMPLEMENTED; 1305 } 1306