Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpdh_main.c
Go to the documentation of this file.
00001 /* 00002 * Performance Data Helper (pdh.dll) 00003 * 00004 * Copyright 2007 Andrey Turkin 00005 * Copyright 2007 Hans Leidekker 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include <stdarg.h> 00023 #include <math.h> 00024 00025 #define NONAMELESSUNION 00026 #define NONAMELESSSTRUCT 00027 #include "windef.h" 00028 #include "winbase.h" 00029 00030 #include "pdh.h" 00031 #include "pdhmsg.h" 00032 #include "winperf.h" 00033 00034 #include "wine/debug.h" 00035 #include "wine/list.h" 00036 #include "wine/unicode.h" 00037 00038 WINE_DEFAULT_DEBUG_CHANNEL(pdh); 00039 00040 static CRITICAL_SECTION pdh_handle_cs; 00041 static CRITICAL_SECTION_DEBUG pdh_handle_cs_debug = 00042 { 00043 0, 0, &pdh_handle_cs, 00044 { &pdh_handle_cs_debug.ProcessLocksList, 00045 &pdh_handle_cs_debug.ProcessLocksList }, 00046 0, 0, { (DWORD_PTR)(__FILE__ ": pdh_handle_cs") } 00047 }; 00048 static CRITICAL_SECTION pdh_handle_cs = { &pdh_handle_cs_debug, -1, 0, 0, 0, 0 }; 00049 00050 static inline void *heap_alloc( SIZE_T size ) 00051 { 00052 return HeapAlloc( GetProcessHeap(), 0, size ); 00053 } 00054 00055 static inline void *heap_alloc_zero( SIZE_T size ) 00056 { 00057 return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); 00058 } 00059 00060 static inline void heap_free( LPVOID mem ) 00061 { 00062 HeapFree( GetProcessHeap(), 0, mem ); 00063 } 00064 00065 static inline WCHAR *pdh_strdup( const WCHAR *src ) 00066 { 00067 WCHAR *dst; 00068 00069 if (!src) return NULL; 00070 if ((dst = heap_alloc( (strlenW( src ) + 1) * sizeof(WCHAR) ))) strcpyW( dst, src ); 00071 return dst; 00072 } 00073 00074 static inline WCHAR *pdh_strdup_aw( const char *src ) 00075 { 00076 int len; 00077 WCHAR *dst; 00078 00079 if (!src) return NULL; 00080 len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); 00081 if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len ); 00082 return dst; 00083 } 00084 00085 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 00086 { 00087 TRACE("(0x%p, %d, %p)\n",hinstDLL,fdwReason,lpvReserved); 00088 00089 if (fdwReason == DLL_WINE_PREATTACH) return FALSE; /* prefer native version */ 00090 00091 if (fdwReason == DLL_PROCESS_ATTACH) 00092 { 00093 DisableThreadLibraryCalls( hinstDLL ); 00094 } 00095 00096 return TRUE; 00097 } 00098 00099 union value 00100 { 00101 LONG longvalue; 00102 double doublevalue; 00103 LONGLONG largevalue; 00104 }; 00105 00106 struct counter 00107 { 00108 DWORD magic; /* signature */ 00109 struct list entry; /* list entry */ 00110 WCHAR *path; /* identifier */ 00111 DWORD type; /* counter type */ 00112 DWORD status; /* update status */ 00113 LONG scale; /* scale factor */ 00114 LONG defaultscale; /* default scale factor */ 00115 DWORD_PTR user; /* user data */ 00116 DWORD_PTR queryuser; /* query user data */ 00117 LONGLONG base; /* samples per second */ 00118 FILETIME stamp; /* time stamp */ 00119 void (CALLBACK *collect)( struct counter * ); /* collect callback */ 00120 union value one; /* first value */ 00121 union value two; /* second value */ 00122 }; 00123 00124 #define PDH_MAGIC_COUNTER 0x50444831 /* 'PDH1' */ 00125 00126 static struct counter *create_counter( void ) 00127 { 00128 struct counter *counter; 00129 00130 if ((counter = heap_alloc_zero( sizeof(struct counter) ))) 00131 { 00132 counter->magic = PDH_MAGIC_COUNTER; 00133 return counter; 00134 } 00135 return NULL; 00136 } 00137 00138 static void destroy_counter( struct counter *counter ) 00139 { 00140 counter->magic = 0; 00141 heap_free( counter->path ); 00142 heap_free( counter ); 00143 } 00144 00145 #define PDH_MAGIC_QUERY 0x50444830 /* 'PDH0' */ 00146 00147 struct query 00148 { 00149 DWORD magic; /* signature */ 00150 DWORD_PTR user; /* user data */ 00151 HANDLE thread; /* collect thread */ 00152 DWORD interval; /* collect interval */ 00153 HANDLE wait; /* wait event */ 00154 HANDLE stop; /* stop event */ 00155 struct list counters; /* counter list */ 00156 }; 00157 00158 static struct query *create_query( void ) 00159 { 00160 struct query *query; 00161 00162 if ((query = heap_alloc_zero( sizeof(struct query) ))) 00163 { 00164 query->magic = PDH_MAGIC_QUERY; 00165 list_init( &query->counters ); 00166 return query; 00167 } 00168 return NULL; 00169 } 00170 00171 static void destroy_query( struct query *query ) 00172 { 00173 query->magic = 0; 00174 heap_free( query ); 00175 } 00176 00177 struct source 00178 { 00179 DWORD index; /* name index */ 00180 const WCHAR *path; /* identifier */ 00181 void (CALLBACK *collect)( struct counter * ); /* collect callback */ 00182 DWORD type; /* counter type */ 00183 LONG scale; /* default scale factor */ 00184 LONGLONG base; /* samples per second */ 00185 }; 00186 00187 static const WCHAR path_processor_time[] = 00188 {'\\','P','r','o','c','e','s','s','o','r','(','_','T','o','t','a','l',')', 00189 '\\','%',' ','P','r','o','c','e','s','s','o','r',' ','T','i','m','e',0}; 00190 static const WCHAR path_uptime[] = 00191 {'\\','S','y','s','t','e','m', '\\', 'S','y','s','t','e','m',' ','U','p',' ','T','i','m','e',0}; 00192 00193 static void CALLBACK collect_processor_time( struct counter *counter ) 00194 { 00195 counter->two.largevalue = 500000; /* FIXME */ 00196 counter->status = PDH_CSTATUS_VALID_DATA; 00197 } 00198 00199 static void CALLBACK collect_uptime( struct counter *counter ) 00200 { 00201 counter->two.largevalue = GetTickCount64(); 00202 counter->status = PDH_CSTATUS_VALID_DATA; 00203 } 00204 00205 #define TYPE_PROCESSOR_TIME \ 00206 (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | \ 00207 PERF_INVERSE_COUNTER | PERF_DISPLAY_PERCENT) 00208 00209 #define TYPE_UPTIME \ 00210 (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_ELAPSED | PERF_OBJECT_TIMER | PERF_DISPLAY_SECONDS) 00211 00212 /* counter source registry */ 00213 static const struct source counter_sources[] = 00214 { 00215 { 6, path_processor_time, collect_processor_time, TYPE_PROCESSOR_TIME, -5, 10000000 }, 00216 { 674, path_uptime, collect_uptime, TYPE_UPTIME, -3, 1000 } 00217 }; 00218 00219 static BOOL pdh_match_path( LPCWSTR fullpath, LPCWSTR path ) 00220 { 00221 const WCHAR *p; 00222 00223 if (strchrW( path, '\\')) p = fullpath; 00224 else p = strrchrW( fullpath, '\\' ) + 1; 00225 if (strcmpW( p, path )) return FALSE; 00226 return TRUE; 00227 } 00228 00229 /*********************************************************************** 00230 * PdhAddCounterA (PDH.@) 00231 */ 00232 PDH_STATUS WINAPI PdhAddCounterA( PDH_HQUERY query, LPCSTR path, 00233 DWORD_PTR userdata, PDH_HCOUNTER *counter ) 00234 { 00235 PDH_STATUS ret; 00236 WCHAR *pathW; 00237 00238 TRACE("%p %s %lx %p\n", query, debugstr_a(path), userdata, counter); 00239 00240 if (!path) return PDH_INVALID_ARGUMENT; 00241 00242 if (!(pathW = pdh_strdup_aw( path ))) 00243 return PDH_MEMORY_ALLOCATION_FAILURE; 00244 00245 ret = PdhAddCounterW( query, pathW, userdata, counter ); 00246 00247 heap_free( pathW ); 00248 return ret; 00249 } 00250 00251 /*********************************************************************** 00252 * PdhAddCounterW (PDH.@) 00253 */ 00254 PDH_STATUS WINAPI PdhAddCounterW( PDH_HQUERY hquery, LPCWSTR path, 00255 DWORD_PTR userdata, PDH_HCOUNTER *hcounter ) 00256 { 00257 struct query *query = hquery; 00258 struct counter *counter; 00259 unsigned int i; 00260 00261 TRACE("%p %s %lx %p\n", hquery, debugstr_w(path), userdata, hcounter); 00262 00263 if (!path || !hcounter) return PDH_INVALID_ARGUMENT; 00264 00265 EnterCriticalSection( &pdh_handle_cs ); 00266 if (!query || query->magic != PDH_MAGIC_QUERY) 00267 { 00268 LeaveCriticalSection( &pdh_handle_cs ); 00269 return PDH_INVALID_HANDLE; 00270 } 00271 00272 *hcounter = NULL; 00273 for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++) 00274 { 00275 if (pdh_match_path( counter_sources[i].path, path )) 00276 { 00277 if ((counter = create_counter())) 00278 { 00279 counter->path = pdh_strdup( counter_sources[i].path ); 00280 counter->collect = counter_sources[i].collect; 00281 counter->type = counter_sources[i].type; 00282 counter->defaultscale = counter_sources[i].scale; 00283 counter->base = counter_sources[i].base; 00284 counter->queryuser = query->user; 00285 counter->user = userdata; 00286 00287 list_add_tail( &query->counters, &counter->entry ); 00288 *hcounter = counter; 00289 00290 LeaveCriticalSection( &pdh_handle_cs ); 00291 return ERROR_SUCCESS; 00292 } 00293 LeaveCriticalSection( &pdh_handle_cs ); 00294 return PDH_MEMORY_ALLOCATION_FAILURE; 00295 } 00296 } 00297 LeaveCriticalSection( &pdh_handle_cs ); 00298 return PDH_CSTATUS_NO_COUNTER; 00299 } 00300 00301 /*********************************************************************** 00302 * PdhAddEnglishCounterA (PDH.@) 00303 */ 00304 PDH_STATUS WINAPI PdhAddEnglishCounterA( PDH_HQUERY query, LPCSTR path, 00305 DWORD_PTR userdata, PDH_HCOUNTER *counter ) 00306 { 00307 TRACE("%p %s %lx %p\n", query, debugstr_a(path), userdata, counter); 00308 00309 if (!query) return PDH_INVALID_ARGUMENT; 00310 return PdhAddCounterA( query, path, userdata, counter ); 00311 } 00312 00313 /*********************************************************************** 00314 * PdhAddEnglishCounterW (PDH.@) 00315 */ 00316 PDH_STATUS WINAPI PdhAddEnglishCounterW( PDH_HQUERY query, LPCWSTR path, 00317 DWORD_PTR userdata, PDH_HCOUNTER *counter ) 00318 { 00319 TRACE("%p %s %lx %p\n", query, debugstr_w(path), userdata, counter); 00320 00321 if (!query) return PDH_INVALID_ARGUMENT; 00322 return PdhAddCounterW( query, path, userdata, counter ); 00323 } 00324 00325 /* caller must hold counter lock */ 00326 static PDH_STATUS format_value( struct counter *counter, DWORD format, union value *raw1, 00327 union value *raw2, PDH_FMT_COUNTERVALUE *value ) 00328 { 00329 LONG factor; 00330 00331 factor = counter->scale ? counter->scale : counter->defaultscale; 00332 if (format & PDH_FMT_LONG) 00333 { 00334 if (format & PDH_FMT_1000) value->u.longValue = raw2->longvalue * 1000; 00335 else value->u.longValue = raw2->longvalue * pow( 10, factor ); 00336 } 00337 else if (format & PDH_FMT_LARGE) 00338 { 00339 if (format & PDH_FMT_1000) value->u.largeValue = raw2->largevalue * 1000; 00340 else value->u.largeValue = raw2->largevalue * pow( 10, factor ); 00341 } 00342 else if (format & PDH_FMT_DOUBLE) 00343 { 00344 if (format & PDH_FMT_1000) value->u.doubleValue = raw2->doublevalue * 1000; 00345 else value->u.doubleValue = raw2->doublevalue * pow( 10, factor ); 00346 } 00347 else 00348 { 00349 WARN("unknown format %x\n", format); 00350 return PDH_INVALID_ARGUMENT; 00351 } 00352 return ERROR_SUCCESS; 00353 } 00354 00355 /*********************************************************************** 00356 * PdhCalculateCounterFromRawValue (PDH.@) 00357 */ 00358 PDH_STATUS WINAPI PdhCalculateCounterFromRawValue( PDH_HCOUNTER handle, DWORD format, 00359 PPDH_RAW_COUNTER raw1, PPDH_RAW_COUNTER raw2, 00360 PPDH_FMT_COUNTERVALUE value ) 00361 { 00362 PDH_STATUS ret; 00363 struct counter *counter = handle; 00364 00365 TRACE("%p 0x%08x %p %p %p\n", handle, format, raw1, raw2, value); 00366 00367 if (!value) return PDH_INVALID_ARGUMENT; 00368 00369 EnterCriticalSection( &pdh_handle_cs ); 00370 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 00371 { 00372 LeaveCriticalSection( &pdh_handle_cs ); 00373 return PDH_INVALID_HANDLE; 00374 } 00375 00376 ret = format_value( counter, format, (union value *)&raw1->SecondValue, 00377 (union value *)&raw2->SecondValue, value ); 00378 00379 LeaveCriticalSection( &pdh_handle_cs ); 00380 return ret; 00381 } 00382 00383 00384 /*********************************************************************** 00385 * PdhCloseQuery (PDH.@) 00386 */ 00387 PDH_STATUS WINAPI PdhCloseQuery( PDH_HQUERY handle ) 00388 { 00389 struct query *query = handle; 00390 struct list *item, *next; 00391 00392 TRACE("%p\n", handle); 00393 00394 EnterCriticalSection( &pdh_handle_cs ); 00395 if (!query || query->magic != PDH_MAGIC_QUERY) 00396 { 00397 LeaveCriticalSection( &pdh_handle_cs ); 00398 return PDH_INVALID_HANDLE; 00399 } 00400 00401 if (query->thread) 00402 { 00403 HANDLE thread = query->thread; 00404 SetEvent( query->stop ); 00405 LeaveCriticalSection( &pdh_handle_cs ); 00406 00407 WaitForSingleObject( thread, INFINITE ); 00408 00409 EnterCriticalSection( &pdh_handle_cs ); 00410 if (query->magic != PDH_MAGIC_QUERY) 00411 { 00412 LeaveCriticalSection( &pdh_handle_cs ); 00413 return ERROR_SUCCESS; 00414 } 00415 CloseHandle( query->stop ); 00416 CloseHandle( query->thread ); 00417 query->thread = NULL; 00418 } 00419 00420 LIST_FOR_EACH_SAFE( item, next, &query->counters ) 00421 { 00422 struct counter *counter = LIST_ENTRY( item, struct counter, entry ); 00423 00424 list_remove( &counter->entry ); 00425 destroy_counter( counter ); 00426 } 00427 00428 destroy_query( query ); 00429 00430 LeaveCriticalSection( &pdh_handle_cs ); 00431 return ERROR_SUCCESS; 00432 } 00433 00434 /* caller must hold query lock */ 00435 static void collect_query_data( struct query *query ) 00436 { 00437 struct list *item; 00438 00439 LIST_FOR_EACH( item, &query->counters ) 00440 { 00441 SYSTEMTIME time; 00442 struct counter *counter = LIST_ENTRY( item, struct counter, entry ); 00443 00444 counter->collect( counter ); 00445 00446 GetLocalTime( &time ); 00447 SystemTimeToFileTime( &time, &counter->stamp ); 00448 } 00449 } 00450 00451 /*********************************************************************** 00452 * PdhCollectQueryData (PDH.@) 00453 */ 00454 PDH_STATUS WINAPI PdhCollectQueryData( PDH_HQUERY handle ) 00455 { 00456 struct query *query = handle; 00457 00458 TRACE("%p\n", handle); 00459 00460 EnterCriticalSection( &pdh_handle_cs ); 00461 if (!query || query->magic != PDH_MAGIC_QUERY) 00462 { 00463 LeaveCriticalSection( &pdh_handle_cs ); 00464 return PDH_INVALID_HANDLE; 00465 } 00466 00467 if (list_empty( &query->counters )) 00468 { 00469 LeaveCriticalSection( &pdh_handle_cs ); 00470 return PDH_NO_DATA; 00471 } 00472 00473 collect_query_data( query ); 00474 00475 LeaveCriticalSection( &pdh_handle_cs ); 00476 return ERROR_SUCCESS; 00477 } 00478 00479 static DWORD CALLBACK collect_query_thread( void *arg ) 00480 { 00481 struct query *query = arg; 00482 DWORD interval = query->interval; 00483 HANDLE stop = query->stop; 00484 00485 for (;;) 00486 { 00487 if (WaitForSingleObject( stop, interval ) != WAIT_TIMEOUT) ExitThread( 0 ); 00488 00489 EnterCriticalSection( &pdh_handle_cs ); 00490 if (query->magic != PDH_MAGIC_QUERY) 00491 { 00492 LeaveCriticalSection( &pdh_handle_cs ); 00493 ExitThread( PDH_INVALID_HANDLE ); 00494 } 00495 00496 collect_query_data( query ); 00497 00498 if (!SetEvent( query->wait )) 00499 { 00500 LeaveCriticalSection( &pdh_handle_cs ); 00501 ExitThread( 0 ); 00502 } 00503 LeaveCriticalSection( &pdh_handle_cs ); 00504 } 00505 } 00506 00507 /*********************************************************************** 00508 * PdhCollectQueryDataEx (PDH.@) 00509 */ 00510 PDH_STATUS WINAPI PdhCollectQueryDataEx( PDH_HQUERY handle, DWORD interval, HANDLE event ) 00511 { 00512 PDH_STATUS ret; 00513 struct query *query = handle; 00514 00515 TRACE("%p %d %p\n", handle, interval, event); 00516 00517 EnterCriticalSection( &pdh_handle_cs ); 00518 if (!query || query->magic != PDH_MAGIC_QUERY) 00519 { 00520 LeaveCriticalSection( &pdh_handle_cs ); 00521 return PDH_INVALID_HANDLE; 00522 } 00523 if (list_empty( &query->counters )) 00524 { 00525 LeaveCriticalSection( &pdh_handle_cs ); 00526 return PDH_NO_DATA; 00527 } 00528 if (query->thread) 00529 { 00530 HANDLE thread = query->thread; 00531 SetEvent( query->stop ); 00532 LeaveCriticalSection( &pdh_handle_cs ); 00533 00534 WaitForSingleObject( thread, INFINITE ); 00535 00536 EnterCriticalSection( &pdh_handle_cs ); 00537 if (query->magic != PDH_MAGIC_QUERY) 00538 { 00539 LeaveCriticalSection( &pdh_handle_cs ); 00540 return PDH_INVALID_HANDLE; 00541 } 00542 CloseHandle( query->thread ); 00543 query->thread = NULL; 00544 } 00545 else if (!(query->stop = CreateEventW( NULL, FALSE, FALSE, NULL ))) 00546 { 00547 ret = GetLastError(); 00548 LeaveCriticalSection( &pdh_handle_cs ); 00549 return ret; 00550 } 00551 query->wait = event; 00552 query->interval = interval * 1000; 00553 if (!(query->thread = CreateThread( NULL, 0, collect_query_thread, query, 0, NULL ))) 00554 { 00555 ret = GetLastError(); 00556 CloseHandle( query->stop ); 00557 00558 LeaveCriticalSection( &pdh_handle_cs ); 00559 return ret; 00560 } 00561 00562 LeaveCriticalSection( &pdh_handle_cs ); 00563 return ERROR_SUCCESS; 00564 } 00565 00566 /*********************************************************************** 00567 * PdhCollectQueryDataWithTime (PDH.@) 00568 */ 00569 PDH_STATUS WINAPI PdhCollectQueryDataWithTime( PDH_HQUERY handle, LONGLONG *timestamp ) 00570 { 00571 struct query *query = handle; 00572 struct counter *counter; 00573 struct list *item; 00574 00575 TRACE("%p %p\n", handle, timestamp); 00576 00577 if (!timestamp) return PDH_INVALID_ARGUMENT; 00578 00579 EnterCriticalSection( &pdh_handle_cs ); 00580 if (!query || query->magic != PDH_MAGIC_QUERY) 00581 { 00582 LeaveCriticalSection( &pdh_handle_cs ); 00583 return PDH_INVALID_HANDLE; 00584 } 00585 if (list_empty( &query->counters )) 00586 { 00587 LeaveCriticalSection( &pdh_handle_cs ); 00588 return PDH_NO_DATA; 00589 } 00590 00591 collect_query_data( query ); 00592 00593 item = list_head( &query->counters ); 00594 counter = LIST_ENTRY( item, struct counter, entry ); 00595 00596 *timestamp = ((LONGLONG)counter->stamp.dwHighDateTime << 32) | counter->stamp.dwLowDateTime; 00597 00598 LeaveCriticalSection( &pdh_handle_cs ); 00599 return ERROR_SUCCESS; 00600 } 00601 00602 /*********************************************************************** 00603 * PdhExpandWildCardPathA (PDH.@) 00604 */ 00605 PDH_STATUS WINAPI PdhExpandWildCardPathA( LPCSTR szDataSource, LPCSTR szWildCardPath, LPSTR mszExpandedPathList, LPDWORD pcchPathListLength, DWORD dwFlags ) 00606 { 00607 FIXME("%s, %s, %p, %p, 0x%x: stub\n", debugstr_a(szDataSource), debugstr_a(szWildCardPath), mszExpandedPathList, pcchPathListLength, dwFlags); 00608 return PDH_NOT_IMPLEMENTED; 00609 } 00610 00611 /*********************************************************************** 00612 * PdhExpandWildCardPathW (PDH.@) 00613 */ 00614 PDH_STATUS WINAPI PdhExpandWildCardPathW( LPCWSTR szDataSource, LPCWSTR szWildCardPath, LPWSTR mszExpandedPathList, LPDWORD pcchPathListLength, DWORD dwFlags ) 00615 { 00616 FIXME("%s, %s, %p, %p, 0x%x: stub\n", debugstr_w(szDataSource), debugstr_w(szWildCardPath), mszExpandedPathList, pcchPathListLength, dwFlags); 00617 return PDH_NOT_IMPLEMENTED; 00618 } 00619 00620 /*********************************************************************** 00621 * PdhGetCounterInfoA (PDH.@) 00622 */ 00623 PDH_STATUS WINAPI PdhGetCounterInfoA( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_A info ) 00624 { 00625 struct counter *counter = handle; 00626 00627 TRACE("%p %d %p %p\n", handle, text, size, info); 00628 00629 EnterCriticalSection( &pdh_handle_cs ); 00630 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 00631 { 00632 LeaveCriticalSection( &pdh_handle_cs ); 00633 return PDH_INVALID_HANDLE; 00634 } 00635 if (!size) 00636 { 00637 LeaveCriticalSection( &pdh_handle_cs ); 00638 return PDH_INVALID_ARGUMENT; 00639 } 00640 if (*size < sizeof(PDH_COUNTER_INFO_A)) 00641 { 00642 *size = sizeof(PDH_COUNTER_INFO_A); 00643 LeaveCriticalSection( &pdh_handle_cs ); 00644 return PDH_MORE_DATA; 00645 } 00646 00647 memset( info, 0, sizeof(PDH_COUNTER_INFO_A) ); 00648 00649 info->dwType = counter->type; 00650 info->CStatus = counter->status; 00651 info->lScale = counter->scale; 00652 info->lDefaultScale = counter->defaultscale; 00653 info->dwUserData = counter->user; 00654 info->dwQueryUserData = counter->queryuser; 00655 00656 *size = sizeof(PDH_COUNTER_INFO_A); 00657 00658 LeaveCriticalSection( &pdh_handle_cs ); 00659 return ERROR_SUCCESS; 00660 } 00661 00662 /*********************************************************************** 00663 * PdhGetCounterInfoW (PDH.@) 00664 */ 00665 PDH_STATUS WINAPI PdhGetCounterInfoW( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_W info ) 00666 { 00667 struct counter *counter = handle; 00668 00669 TRACE("%p %d %p %p\n", handle, text, size, info); 00670 00671 EnterCriticalSection( &pdh_handle_cs ); 00672 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 00673 { 00674 LeaveCriticalSection( &pdh_handle_cs ); 00675 return PDH_INVALID_HANDLE; 00676 } 00677 if (!size) 00678 { 00679 LeaveCriticalSection( &pdh_handle_cs ); 00680 return PDH_INVALID_ARGUMENT; 00681 } 00682 if (*size < sizeof(PDH_COUNTER_INFO_W)) 00683 { 00684 *size = sizeof(PDH_COUNTER_INFO_W); 00685 LeaveCriticalSection( &pdh_handle_cs ); 00686 return PDH_MORE_DATA; 00687 } 00688 00689 memset( info, 0, sizeof(PDH_COUNTER_INFO_W) ); 00690 00691 info->dwType = counter->type; 00692 info->CStatus = counter->status; 00693 info->lScale = counter->scale; 00694 info->lDefaultScale = counter->defaultscale; 00695 info->dwUserData = counter->user; 00696 info->dwQueryUserData = counter->queryuser; 00697 00698 *size = sizeof(PDH_COUNTER_INFO_W); 00699 00700 LeaveCriticalSection( &pdh_handle_cs ); 00701 return ERROR_SUCCESS; 00702 } 00703 00704 /*********************************************************************** 00705 * PdhGetCounterTimeBase (PDH.@) 00706 */ 00707 PDH_STATUS WINAPI PdhGetCounterTimeBase( PDH_HCOUNTER handle, LONGLONG *base ) 00708 { 00709 struct counter *counter = handle; 00710 00711 TRACE("%p %p\n", handle, base); 00712 00713 if (!base) return PDH_INVALID_ARGUMENT; 00714 00715 EnterCriticalSection( &pdh_handle_cs ); 00716 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 00717 { 00718 LeaveCriticalSection( &pdh_handle_cs ); 00719 return PDH_INVALID_HANDLE; 00720 } 00721 00722 *base = counter->base; 00723 00724 LeaveCriticalSection( &pdh_handle_cs ); 00725 return ERROR_SUCCESS; 00726 } 00727 00728 /*********************************************************************** 00729 * PdhGetDllVersion (PDH.@) 00730 */ 00731 PDH_STATUS WINAPI PdhGetDllVersion( LPDWORD version ) 00732 { 00733 if (!version) 00734 return PDH_INVALID_ARGUMENT; 00735 00736 *version = PDH_VERSION; 00737 00738 return ERROR_SUCCESS; 00739 } 00740 00741 /*********************************************************************** 00742 * PdhGetFormattedCounterValue (PDH.@) 00743 */ 00744 PDH_STATUS WINAPI PdhGetFormattedCounterValue( PDH_HCOUNTER handle, DWORD format, 00745 LPDWORD type, PPDH_FMT_COUNTERVALUE value ) 00746 { 00747 PDH_STATUS ret; 00748 struct counter *counter = handle; 00749 00750 TRACE("%p %x %p %p\n", handle, format, type, value); 00751 00752 if (!value) return PDH_INVALID_ARGUMENT; 00753 00754 EnterCriticalSection( &pdh_handle_cs ); 00755 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 00756 { 00757 LeaveCriticalSection( &pdh_handle_cs ); 00758 return PDH_INVALID_HANDLE; 00759 } 00760 if (counter->status) 00761 { 00762 LeaveCriticalSection( &pdh_handle_cs ); 00763 return PDH_INVALID_DATA; 00764 } 00765 if (!(ret = format_value( counter, format, &counter->one, &counter->two, value ))) 00766 { 00767 value->CStatus = ERROR_SUCCESS; 00768 if (type) *type = counter->type; 00769 } 00770 00771 LeaveCriticalSection( &pdh_handle_cs ); 00772 return ret; 00773 } 00774 00775 /*********************************************************************** 00776 * PdhGetRawCounterValue (PDH.@) 00777 */ 00778 PDH_STATUS WINAPI PdhGetRawCounterValue( PDH_HCOUNTER handle, LPDWORD type, 00779 PPDH_RAW_COUNTER value ) 00780 { 00781 struct counter *counter = handle; 00782 00783 TRACE("%p %p %p\n", handle, type, value); 00784 00785 if (!value) return PDH_INVALID_ARGUMENT; 00786 00787 EnterCriticalSection( &pdh_handle_cs ); 00788 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 00789 { 00790 LeaveCriticalSection( &pdh_handle_cs ); 00791 return PDH_INVALID_HANDLE; 00792 } 00793 00794 value->CStatus = counter->status; 00795 value->TimeStamp.dwLowDateTime = counter->stamp.dwLowDateTime; 00796 value->TimeStamp.dwHighDateTime = counter->stamp.dwHighDateTime; 00797 value->FirstValue = counter->one.largevalue; 00798 value->SecondValue = counter->two.largevalue; 00799 value->MultiCount = 1; /* FIXME */ 00800 00801 if (type) *type = counter->type; 00802 00803 LeaveCriticalSection( &pdh_handle_cs ); 00804 return ERROR_SUCCESS; 00805 } 00806 00807 /*********************************************************************** 00808 * PdhLookupPerfIndexByNameA (PDH.@) 00809 */ 00810 PDH_STATUS WINAPI PdhLookupPerfIndexByNameA( LPCSTR machine, LPCSTR name, LPDWORD index ) 00811 { 00812 PDH_STATUS ret; 00813 WCHAR *machineW = NULL; 00814 WCHAR *nameW; 00815 00816 TRACE("%s %s %p\n", debugstr_a(machine), debugstr_a(name), index); 00817 00818 if (!name) return PDH_INVALID_ARGUMENT; 00819 00820 if (machine && !(machineW = pdh_strdup_aw( machine ))) return PDH_MEMORY_ALLOCATION_FAILURE; 00821 00822 if (!(nameW = pdh_strdup_aw( name ))) 00823 return PDH_MEMORY_ALLOCATION_FAILURE; 00824 00825 ret = PdhLookupPerfIndexByNameW( machineW, nameW, index ); 00826 00827 heap_free( nameW ); 00828 heap_free( machineW ); 00829 return ret; 00830 } 00831 00832 /*********************************************************************** 00833 * PdhLookupPerfIndexByNameW (PDH.@) 00834 */ 00835 PDH_STATUS WINAPI PdhLookupPerfIndexByNameW( LPCWSTR machine, LPCWSTR name, LPDWORD index ) 00836 { 00837 unsigned int i; 00838 00839 TRACE("%s %s %p\n", debugstr_w(machine), debugstr_w(name), index); 00840 00841 if (!name || !index) return PDH_INVALID_ARGUMENT; 00842 00843 if (machine) 00844 { 00845 FIXME("remote machine not supported\n"); 00846 return PDH_CSTATUS_NO_MACHINE; 00847 } 00848 for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++) 00849 { 00850 if (pdh_match_path( counter_sources[i].path, name )) 00851 { 00852 *index = counter_sources[i].index; 00853 return ERROR_SUCCESS; 00854 } 00855 } 00856 return PDH_STRING_NOT_FOUND; 00857 } 00858 00859 /*********************************************************************** 00860 * PdhLookupPerfNameByIndexA (PDH.@) 00861 */ 00862 PDH_STATUS WINAPI PdhLookupPerfNameByIndexA( LPCSTR machine, DWORD index, LPSTR buffer, LPDWORD size ) 00863 { 00864 PDH_STATUS ret; 00865 WCHAR *machineW = NULL; 00866 WCHAR bufferW[PDH_MAX_COUNTER_NAME]; 00867 DWORD sizeW = sizeof(bufferW) / sizeof(WCHAR); 00868 00869 TRACE("%s %d %p %p\n", debugstr_a(machine), index, buffer, size); 00870 00871 if (!buffer || !size) return PDH_INVALID_ARGUMENT; 00872 00873 if (machine && !(machineW = pdh_strdup_aw( machine ))) return PDH_MEMORY_ALLOCATION_FAILURE; 00874 00875 if (!(ret = PdhLookupPerfNameByIndexW( machineW, index, bufferW, &sizeW ))) 00876 { 00877 int required = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL ); 00878 00879 if (size && *size < required) ret = PDH_MORE_DATA; 00880 else WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, required, NULL, NULL ); 00881 if (size) *size = required; 00882 } 00883 heap_free( machineW ); 00884 return ret; 00885 } 00886 00887 /*********************************************************************** 00888 * PdhLookupPerfNameByIndexW (PDH.@) 00889 */ 00890 PDH_STATUS WINAPI PdhLookupPerfNameByIndexW( LPCWSTR machine, DWORD index, LPWSTR buffer, LPDWORD size ) 00891 { 00892 PDH_STATUS ret; 00893 unsigned int i; 00894 00895 TRACE("%s %d %p %p\n", debugstr_w(machine), index, buffer, size); 00896 00897 if (machine) 00898 { 00899 FIXME("remote machine not supported\n"); 00900 return PDH_CSTATUS_NO_MACHINE; 00901 } 00902 00903 if (!buffer || !size) return PDH_INVALID_ARGUMENT; 00904 if (!index) return ERROR_SUCCESS; 00905 00906 for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++) 00907 { 00908 if (counter_sources[i].index == index) 00909 { 00910 WCHAR *p = strrchrW( counter_sources[i].path, '\\' ) + 1; 00911 unsigned int required = strlenW( p ) + 1; 00912 00913 if (*size < required) ret = PDH_MORE_DATA; 00914 else 00915 { 00916 strcpyW( buffer, p ); 00917 ret = ERROR_SUCCESS; 00918 } 00919 *size = required; 00920 return ret; 00921 } 00922 } 00923 return PDH_INVALID_ARGUMENT; 00924 } 00925 00926 /*********************************************************************** 00927 * PdhOpenQueryA (PDH.@) 00928 */ 00929 PDH_STATUS WINAPI PdhOpenQueryA( LPCSTR source, DWORD_PTR userdata, PDH_HQUERY *query ) 00930 { 00931 PDH_STATUS ret; 00932 WCHAR *sourceW = NULL; 00933 00934 TRACE("%s %lx %p\n", debugstr_a(source), userdata, query); 00935 00936 if (source && !(sourceW = pdh_strdup_aw( source ))) return PDH_MEMORY_ALLOCATION_FAILURE; 00937 00938 ret = PdhOpenQueryW( sourceW, userdata, query ); 00939 heap_free( sourceW ); 00940 00941 return ret; 00942 } 00943 00944 /*********************************************************************** 00945 * PdhOpenQueryW (PDH.@) 00946 */ 00947 PDH_STATUS WINAPI PdhOpenQueryW( LPCWSTR source, DWORD_PTR userdata, PDH_HQUERY *handle ) 00948 { 00949 struct query *query; 00950 00951 TRACE("%s %lx %p\n", debugstr_w(source), userdata, handle); 00952 00953 if (!handle) return PDH_INVALID_ARGUMENT; 00954 00955 if (source) 00956 { 00957 FIXME("log file data source not supported\n"); 00958 return PDH_INVALID_ARGUMENT; 00959 } 00960 if ((query = create_query())) 00961 { 00962 query->user = userdata; 00963 *handle = query; 00964 00965 return ERROR_SUCCESS; 00966 } 00967 return PDH_MEMORY_ALLOCATION_FAILURE; 00968 } 00969 00970 /*********************************************************************** 00971 * PdhRemoveCounter (PDH.@) 00972 */ 00973 PDH_STATUS WINAPI PdhRemoveCounter( PDH_HCOUNTER handle ) 00974 { 00975 struct counter *counter = handle; 00976 00977 TRACE("%p\n", handle); 00978 00979 EnterCriticalSection( &pdh_handle_cs ); 00980 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 00981 { 00982 LeaveCriticalSection( &pdh_handle_cs ); 00983 return PDH_INVALID_HANDLE; 00984 } 00985 00986 list_remove( &counter->entry ); 00987 destroy_counter( counter ); 00988 00989 LeaveCriticalSection( &pdh_handle_cs ); 00990 return ERROR_SUCCESS; 00991 } 00992 00993 /*********************************************************************** 00994 * PdhSetCounterScaleFactor (PDH.@) 00995 */ 00996 PDH_STATUS WINAPI PdhSetCounterScaleFactor( PDH_HCOUNTER handle, LONG factor ) 00997 { 00998 struct counter *counter = handle; 00999 01000 TRACE("%p\n", handle); 01001 01002 EnterCriticalSection( &pdh_handle_cs ); 01003 if (!counter || counter->magic != PDH_MAGIC_COUNTER) 01004 { 01005 LeaveCriticalSection( &pdh_handle_cs ); 01006 return PDH_INVALID_HANDLE; 01007 } 01008 if (factor < PDH_MIN_SCALE || factor > PDH_MAX_SCALE) 01009 { 01010 LeaveCriticalSection( &pdh_handle_cs ); 01011 return PDH_INVALID_ARGUMENT; 01012 } 01013 01014 counter->scale = factor; 01015 01016 LeaveCriticalSection( &pdh_handle_cs ); 01017 return ERROR_SUCCESS; 01018 } 01019 01020 /*********************************************************************** 01021 * PdhValidatePathA (PDH.@) 01022 */ 01023 PDH_STATUS WINAPI PdhValidatePathA( LPCSTR path ) 01024 { 01025 PDH_STATUS ret; 01026 WCHAR *pathW; 01027 01028 TRACE("%s\n", debugstr_a(path)); 01029 01030 if (!path) return PDH_INVALID_ARGUMENT; 01031 if (!(pathW = pdh_strdup_aw( path ))) return PDH_MEMORY_ALLOCATION_FAILURE; 01032 01033 ret = PdhValidatePathW( pathW ); 01034 01035 heap_free( pathW ); 01036 return ret; 01037 } 01038 01039 static PDH_STATUS validate_path( LPCWSTR path ) 01040 { 01041 if (!path || !*path) return PDH_INVALID_ARGUMENT; 01042 if (*path++ != '\\' || !strchrW( path, '\\' )) return PDH_CSTATUS_BAD_COUNTERNAME; 01043 return ERROR_SUCCESS; 01044 } 01045 01046 /*********************************************************************** 01047 * PdhValidatePathW (PDH.@) 01048 */ 01049 PDH_STATUS WINAPI PdhValidatePathW( LPCWSTR path ) 01050 { 01051 PDH_STATUS ret; 01052 unsigned int i; 01053 01054 TRACE("%s\n", debugstr_w(path)); 01055 01056 if ((ret = validate_path( path ))) return ret; 01057 01058 for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++) 01059 if (pdh_match_path( counter_sources[i].path, path )) return ERROR_SUCCESS; 01060 01061 return PDH_CSTATUS_NO_COUNTER; 01062 } 01063 01064 /*********************************************************************** 01065 * PdhValidatePathExA (PDH.@) 01066 */ 01067 PDH_STATUS WINAPI PdhValidatePathExA( PDH_HLOG source, LPCSTR path ) 01068 { 01069 TRACE("%p %s\n", source, debugstr_a(path)); 01070 01071 if (source) 01072 { 01073 FIXME("log file data source not supported\n"); 01074 return ERROR_SUCCESS; 01075 } 01076 return PdhValidatePathA( path ); 01077 } 01078 01079 /*********************************************************************** 01080 * PdhValidatePathExW (PDH.@) 01081 */ 01082 PDH_STATUS WINAPI PdhValidatePathExW( PDH_HLOG source, LPCWSTR path ) 01083 { 01084 TRACE("%p %s\n", source, debugstr_w(path)); 01085 01086 if (source) 01087 { 01088 FIXME("log file data source not supported\n"); 01089 return ERROR_SUCCESS; 01090 } 01091 return PdhValidatePathW( path ); 01092 } 01093 01094 /*********************************************************************** 01095 * PdhMakeCounterPathA (PDH.@) 01096 */ 01097 PDH_STATUS WINAPI PdhMakeCounterPathA( PDH_COUNTER_PATH_ELEMENTS_A *e, LPSTR buffer, 01098 LPDWORD buflen, DWORD flags ) 01099 { 01100 PDH_STATUS ret = PDH_MEMORY_ALLOCATION_FAILURE; 01101 PDH_COUNTER_PATH_ELEMENTS_W eW; 01102 WCHAR *bufferW; 01103 DWORD buflenW; 01104 01105 TRACE("%p %p %p 0x%08x\n", e, buffer, buflen, flags); 01106 01107 if (!e || !buflen) return PDH_INVALID_ARGUMENT; 01108 01109 memset( &eW, 0, sizeof(eW) ); 01110 if (e->szMachineName && !(eW.szMachineName = pdh_strdup_aw( e->szMachineName ))) goto done; 01111 if (e->szObjectName && !(eW.szObjectName = pdh_strdup_aw( e->szObjectName ))) goto done; 01112 if (e->szInstanceName && !(eW.szInstanceName = pdh_strdup_aw( e->szInstanceName ))) goto done; 01113 if (e->szParentInstance && !(eW.szParentInstance = pdh_strdup_aw( e->szParentInstance ))) goto done; 01114 if (e->szCounterName && !(eW.szCounterName = pdh_strdup_aw( e->szCounterName ))) goto done; 01115 eW.dwInstanceIndex = e->dwInstanceIndex; 01116 01117 buflenW = 0; 01118 ret = PdhMakeCounterPathW( &eW, NULL, &buflenW, flags ); 01119 if (ret == PDH_MORE_DATA) 01120 { 01121 if ((bufferW = heap_alloc( buflenW * sizeof(WCHAR) ))) 01122 { 01123 if (!(ret = PdhMakeCounterPathW( &eW, bufferW, &buflenW, flags ))) 01124 { 01125 int len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL); 01126 if (*buflen >= len) WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, *buflen, NULL, NULL); 01127 else ret = PDH_MORE_DATA; 01128 *buflen = len; 01129 } 01130 heap_free( bufferW ); 01131 } 01132 else 01133 ret = PDH_MEMORY_ALLOCATION_FAILURE; 01134 } 01135 01136 done: 01137 heap_free( eW.szMachineName ); 01138 heap_free( eW.szObjectName ); 01139 heap_free( eW.szInstanceName ); 01140 heap_free( eW.szParentInstance ); 01141 heap_free( eW.szCounterName ); 01142 return ret; 01143 } 01144 01145 /*********************************************************************** 01146 * PdhMakeCounterPathW (PDH.@) 01147 */ 01148 PDH_STATUS WINAPI PdhMakeCounterPathW( PDH_COUNTER_PATH_ELEMENTS_W *e, LPWSTR buffer, 01149 LPDWORD buflen, DWORD flags ) 01150 { 01151 static const WCHAR bslash[] = {'\\',0}; 01152 static const WCHAR fslash[] = {'/',0}; 01153 static const WCHAR lparen[] = {'(',0}; 01154 static const WCHAR rparen[] = {')',0}; 01155 static const WCHAR fmt[] = {'#','%','u',0}; 01156 01157 WCHAR path[PDH_MAX_COUNTER_NAME], instance[12]; 01158 PDH_STATUS ret = ERROR_SUCCESS; 01159 DWORD len; 01160 01161 TRACE("%p %p %p 0x%08x\n", e, buffer, buflen, flags); 01162 01163 if (flags) FIXME("unimplemented flags 0x%08x\n", flags); 01164 01165 if (!e || !e->szCounterName || !e->szObjectName || !buflen) 01166 return PDH_INVALID_ARGUMENT; 01167 01168 path[0] = 0; 01169 if (e->szMachineName) 01170 { 01171 strcatW(path, bslash); 01172 strcatW(path, bslash); 01173 strcatW(path, e->szMachineName); 01174 } 01175 strcatW(path, bslash); 01176 strcatW(path, e->szObjectName); 01177 if (e->szInstanceName) 01178 { 01179 strcatW(path, lparen); 01180 if (e->szParentInstance) 01181 { 01182 strcatW(path, e->szParentInstance); 01183 strcatW(path, fslash); 01184 } 01185 strcatW(path, e->szInstanceName); 01186 sprintfW(instance, fmt, e->dwInstanceIndex); 01187 strcatW(path, instance); 01188 strcatW(path, rparen); 01189 } 01190 strcatW(path, bslash); 01191 strcatW(path, e->szCounterName); 01192 01193 len = strlenW(path) + 1; 01194 if (*buflen >= len) strcpyW(buffer, path); 01195 else ret = PDH_MORE_DATA; 01196 *buflen = len; 01197 return ret; 01198 } 01199 01200 /*********************************************************************** 01201 * PdhEnumObjectItemsA (PDH.@) 01202 */ 01203 PDH_STATUS WINAPI PdhEnumObjectItemsA(LPCSTR szDataSource, LPCSTR szMachineName, LPCSTR szObjectName, 01204 LPSTR mszCounterList, LPDWORD pcchCounterListLength, LPSTR mszInstanceList, 01205 LPDWORD pcchInstanceListLength, DWORD dwDetailLevel, DWORD dwFlags) 01206 { 01207 FIXME("%s, %s, %s, %p, %p, %p, %p, %d, 0x%x: stub\n", debugstr_a(szDataSource), debugstr_a(szMachineName), 01208 debugstr_a(szObjectName), mszCounterList, pcchCounterListLength, mszInstanceList, 01209 pcchInstanceListLength, dwDetailLevel, dwFlags); 01210 01211 return PDH_NOT_IMPLEMENTED; 01212 } 01213 01214 /*********************************************************************** 01215 * PdhEnumObjectItemsW (PDH.@) 01216 */ 01217 PDH_STATUS WINAPI PdhEnumObjectItemsW(LPCWSTR szDataSource, LPCWSTR szMachineName, LPCWSTR szObjectName, 01218 LPWSTR mszCounterList, LPDWORD pcchCounterListLength, LPWSTR mszInstanceList, 01219 LPDWORD pcchInstanceListLength, DWORD dwDetailLevel, DWORD dwFlags) 01220 { 01221 FIXME("%s, %s, %s, %p, %p, %p, %p, %d, 0x%x: stub\n", debugstr_w(szDataSource), debugstr_w(szMachineName), 01222 debugstr_w(szObjectName), mszCounterList, pcchCounterListLength, mszInstanceList, 01223 pcchInstanceListLength, dwDetailLevel, dwFlags); 01224 01225 return PDH_NOT_IMPLEMENTED; 01226 } 01227 01228 /*********************************************************************** 01229 * PdhSetDefaultRealTimeDataSource (PDH.@) 01230 */ 01231 PDH_STATUS WINAPI PdhSetDefaultRealTimeDataSource( DWORD source ) 01232 { 01233 FIXME("%u\n", source); 01234 return ERROR_SUCCESS; 01235 } Generated on Sat May 26 2012 04:24:28 for ReactOS by
1.7.6.1
|