Reactos
at master 1820 lines 61 kB view raw
1/* 2 * Win32 debugger functions 3 * 4 * Copyright (C) 1999 Alexandre Julliard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21#include <stdio.h> 22#include <string.h> 23#include <stdlib.h> 24 25#include "ntstatus.h" 26#define WIN32_NO_STATUS 27#include "windef.h" 28#include "winbase.h" 29#include "winternl.h" 30#include "winnls.h" 31#include "wingdi.h" 32#include "winuser.h" 33#define PSAPI_VERSION 1 /* avoid K32 function remapping */ 34#include "psapi.h" 35#include "werapi.h" 36 37#include "wine/exception.h" 38#include "wine/asm.h" 39#include "kernelbase.h" 40#include "wine/debug.h" 41 42WINE_DEFAULT_DEBUG_CHANNEL(seh); 43WINE_DECLARE_DEBUG_CHANNEL(winedbg); 44 45typedef INT (WINAPI *MessageBoxA_funcptr)(HWND,LPCSTR,LPCSTR,UINT); 46typedef INT (WINAPI *MessageBoxW_funcptr)(HWND,LPCWSTR,LPCWSTR,UINT); 47 48static PTOP_LEVEL_EXCEPTION_FILTER top_filter; 49 50void *dummy = RtlUnwind; /* force importing RtlUnwind from ntdll */ 51 52/*********************************************************************** 53 * CheckRemoteDebuggerPresent (kernelbase.@) 54 */ 55BOOL WINAPI DECLSPEC_HOTPATCH CheckRemoteDebuggerPresent( HANDLE process, BOOL *present ) 56{ 57 DWORD_PTR port; 58 59 if (!process || !present) 60 { 61 SetLastError( ERROR_INVALID_PARAMETER ); 62 return FALSE; 63 } 64 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessDebugPort, &port, sizeof(port), NULL ))) 65 return FALSE; 66 *present = !!port; 67 return TRUE; 68} 69 70 71/********************************************************************** 72 * ContinueDebugEvent (kernelbase.@) 73 */ 74BOOL WINAPI DECLSPEC_HOTPATCH ContinueDebugEvent( DWORD pid, DWORD tid, DWORD status ) 75{ 76 CLIENT_ID id; 77 78 id.UniqueProcess = ULongToHandle( pid ); 79 id.UniqueThread = ULongToHandle( tid ); 80 return set_ntstatus( DbgUiContinue( &id, status )); 81} 82 83 84/********************************************************************** 85 * DebugActiveProcess (kernelbase.@) 86 */ 87BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcess( DWORD pid ) 88{ 89 HANDLE process; 90 NTSTATUS status; 91 92 if (!set_ntstatus( DbgUiConnectToDbg() )) return FALSE; 93 if (!(process = OpenProcess( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_SUSPEND_RESUME | 94 PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD, FALSE, pid ))) 95 return FALSE; 96 status = DbgUiDebugActiveProcess( process ); 97 NtClose( process ); 98 return set_ntstatus( status ); 99} 100 101 102/********************************************************************** 103 * DebugActiveProcessStop (kernelbase.@) 104 */ 105BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcessStop( DWORD pid ) 106{ 107 HANDLE process; 108 NTSTATUS status; 109 110 if (!(process = OpenProcess( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_SUSPEND_RESUME, FALSE, pid ))) 111 return FALSE; 112 status = DbgUiStopDebugging( process ); 113 NtClose( process ); 114 return set_ntstatus( status ); 115} 116 117 118/*********************************************************************** 119 * DebugBreak (kernelbase.@) 120 */ 121#ifdef __i386__ 122__ASM_STDCALL_FUNC( DebugBreak, 0, "jmp " __ASM_STDCALL("DbgBreakPoint", 0) ) 123#elif defined(__aarch64__) 124__ASM_GLOBAL_FUNC( DebugBreak, "brk #0xf000; ret" ) 125#elif defined(__arm64ec__) 126void __attribute__((naked)) WINAPI DebugBreak(void) { asm( "brk #0xf000; ret" ); } 127#elif defined(__x86_64__) 128__ASM_GLOBAL_FUNC( DebugBreak, "jmp " __ASM_NAME("DbgBreakPoint") ) 129#elif defined(__arm__) 130__ASM_GLOBAL_FUNC( DebugBreak, "udf #0xfe; bx lr" ) 131#endif 132 133 134/************************************************************************** 135 * FatalAppExitA (kernelbase.@) 136 */ 137void WINAPI DECLSPEC_HOTPATCH FatalAppExitA( UINT action, LPCSTR str ) 138{ 139 HMODULE mod = GetModuleHandleA( "user32.dll" ); 140 MessageBoxA_funcptr pMessageBoxA = NULL; 141 142 if (mod) pMessageBoxA = (MessageBoxA_funcptr)GetProcAddress( mod, "MessageBoxA" ); 143 if (pMessageBoxA) pMessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK ); 144 else ERR( "%s\n", debugstr_a(str) ); 145 RtlExitUserProcess( 1 ); 146} 147 148 149/************************************************************************** 150 * FatalAppExitW (kernelbase.@) 151 */ 152void WINAPI DECLSPEC_HOTPATCH FatalAppExitW( UINT action, LPCWSTR str ) 153{ 154 HMODULE mod = GetModuleHandleW( L"user32.dll" ); 155 MessageBoxW_funcptr pMessageBoxW = NULL; 156 157 if (mod) pMessageBoxW = (MessageBoxW_funcptr)GetProcAddress( mod, "MessageBoxW" ); 158 if (pMessageBoxW) pMessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK ); 159 else ERR( "%s\n", debugstr_w(str) ); 160 RtlExitUserProcess( 1 ); 161} 162 163 164/*********************************************************************** 165 * IsDebuggerPresent (kernelbase.@) 166 */ 167BOOL WINAPI IsDebuggerPresent(void) 168{ 169 return NtCurrentTeb()->Peb->BeingDebugged; 170} 171 172 173static LONG WINAPI debug_exception_handler( EXCEPTION_POINTERS *eptr ) 174{ 175 EXCEPTION_RECORD *rec = eptr->ExceptionRecord; 176 return (rec->ExceptionCode == DBG_PRINTEXCEPTION_C) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; 177} 178 179/*********************************************************************** 180 * OutputDebugStringA (kernelbase.@) 181 */ 182void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str ) 183{ 184 static HANDLE DBWinMutex = NULL; 185 static BOOL mutex_inited = FALSE; 186 BOOL caught_by_dbg = TRUE; 187 188 if (!str) str = ""; 189 WARN( "%s\n", debugstr_a(str) ); 190 191 /* raise exception, WaitForDebugEvent() will generate a corresponding debug event */ 192 __TRY 193 { 194 ULONG_PTR args[2]; 195 args[0] = strlen(str) + 1; 196 args[1] = (ULONG_PTR)str; 197 RaiseException( DBG_PRINTEXCEPTION_C, 0, 2, args ); 198 } 199 __EXCEPT(debug_exception_handler) 200 { 201 caught_by_dbg = FALSE; 202 } 203 __ENDTRY 204 if (caught_by_dbg) return; 205 206 /* send string to a system-wide monitor */ 207 if (!mutex_inited) 208 { 209 /* first call to OutputDebugString, initialize mutex handle */ 210 HANDLE mutex = CreateMutexExW( NULL, L"DBWinMutex", 0, SYNCHRONIZE ); 211 if (mutex) 212 { 213 if (InterlockedCompareExchangePointer( &DBWinMutex, mutex, 0 ) != 0) 214 /* someone beat us here... */ 215 CloseHandle( mutex ); 216 } 217 mutex_inited = TRUE; 218 } 219 220 if (DBWinMutex) 221 { 222 HANDLE mapping; 223 224 mapping = OpenFileMappingW( FILE_MAP_WRITE, FALSE, L"DBWIN_BUFFER" ); 225 if (mapping) 226 { 227 LPVOID buffer; 228 HANDLE eventbuffer, eventdata; 229 230 buffer = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 ); 231 eventbuffer = OpenEventW( SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY" ); 232 eventdata = OpenEventW( EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY" ); 233 234 if (buffer && eventbuffer && eventdata) 235 { 236 /* monitor is present, synchronize with other OutputDebugString invocations */ 237 WaitForSingleObject( DBWinMutex, INFINITE ); 238 239 /* acquire control over the buffer */ 240 if (WaitForSingleObject( eventbuffer, 10000 ) == WAIT_OBJECT_0) 241 { 242 int str_len = strlen( str ); 243 struct _mon_buffer_t 244 { 245 DWORD pid; 246 char buffer[1]; 247 } *mon_buffer = (struct _mon_buffer_t*) buffer; 248 249 if (str_len > (4096 - sizeof(DWORD) - 1)) str_len = 4096 - sizeof(DWORD) - 1; 250 mon_buffer->pid = GetCurrentProcessId(); 251 memcpy( mon_buffer->buffer, str, str_len ); 252 mon_buffer->buffer[str_len] = 0; 253 254 /* signal data ready */ 255 SetEvent( eventdata ); 256 } 257 ReleaseMutex( DBWinMutex ); 258 } 259 260 if (buffer) UnmapViewOfFile( buffer ); 261 if (eventbuffer) CloseHandle( eventbuffer ); 262 if (eventdata) CloseHandle( eventdata ); 263 CloseHandle( mapping ); 264 } 265 } 266} 267 268static LONG WINAPI debug_exception_handler_wide( EXCEPTION_POINTERS *eptr ) 269{ 270 EXCEPTION_RECORD *rec = eptr->ExceptionRecord; 271 return (rec->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; 272} 273 274/*********************************************************************** 275 * OutputDebugStringW (kernelbase.@) 276 */ 277void WINAPI DECLSPEC_HOTPATCH OutputDebugStringW( LPCWSTR str ) 278{ 279 UNICODE_STRING strW; 280 STRING strA; 281 282 WARN( "%s\n", debugstr_w(str) ); 283 284 RtlInitUnicodeString( &strW, str ); 285 if (!RtlUnicodeStringToAnsiString( &strA, &strW, TRUE )) 286 { 287 BOOL exc_handled; 288 289 __TRY 290 { 291 ULONG_PTR args[4]; 292 args[0] = wcslen(str) + 1; 293 args[1] = (ULONG_PTR)str; 294 args[2] = strlen(strA.Buffer) + 1; 295 args[3] = (ULONG_PTR)strA.Buffer; 296 RaiseException( DBG_PRINTEXCEPTION_WIDE_C, 0, 4, args ); 297 exc_handled = TRUE; 298 } 299 __EXCEPT(debug_exception_handler_wide) 300 { 301 exc_handled = FALSE; 302 } 303 __ENDTRY 304 305 if (!exc_handled) 306 OutputDebugStringA( strA.Buffer ); 307 308 RtlFreeAnsiString( &strA ); 309 } 310} 311 312 313/******************************************************************* 314 * RaiseException (kernelbase.@) 315 */ 316#ifdef __x86_64__ 317#ifdef __arm64ec__ 318void __attribute__((naked)) RaiseException( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args ) 319{ 320 asm( ".seh_proc RaiseException\n\t" 321 "stp x29, x30, [sp, #-0xb0]!\n\t" 322 ".seh_save_fplr_x 0xb0\n\t" 323 ".seh_endprologue\n\t" 324 "and w1, w1, #0x01\n\t" /* EXCEPTION_NONCONTINUABLE */ 325 "stp w0, w1, [sp, #0x10]\n\t" /* ExceptionCode, ExceptionFlags */ 326 "adr x4, RaiseException\n\t" 327 "stp xzr, x4, [sp, #0x18]\n\t" /* ExceptionRecord, ExceptionAddress */ 328 "mov w5, #0x0f\n\t" /* EXCEPTION_MAXIMUM_PARAMETERS */ 329 "cmp w2, w5\n\t" 330 "csel w2, w2, w5, lo\n\t" 331 "str x2, [sp, #0x28]\n\t" /* NumberParameters */ 332 "cbz x3, 1f\n\t" 333 "lsl w2, w2, #3\n\t" 334 "add x0, sp, #0x30\n\t" /* ExceptionInformation */ 335 "mov x1, x3\n\t" /* args */ 336 "bl \"#memcpy\"\n" 337 "1:\tadd x0, sp, #0x10\n\t" /* rec */ 338 "bl \"#RtlRaiseException\"\n\t" 339 "ldp x29, x30, [sp], #0xb0\n\t" 340 "ret\n\t" 341 ".seh_endproc" ); 342} 343#else 344/* Some DRMs depend on RaiseException not altering non-volatile registers. */ 345__ASM_GLOBAL_FUNC( RaiseException, 346 ".byte 0x48,0x8d,0xa4,0x24,0x00,0x00,0x00,0x00\n\t" /* hotpatch prolog */ 347 "sub $0xc8,%rsp\n\t" 348 __ASM_SEH(".seh_stackalloc 0xc8\n\t") 349 __ASM_SEH(".seh_endprologue\n\t") 350 __ASM_CFI(".cfi_adjust_cfa_offset 0xc8\n\t") 351 "leaq 0x20(%rsp),%rax\n\t" 352 "movl %ecx,(%rax)\n\t" /* ExceptionCode */ 353 "and $1,%edx\n\t" 354 "movl %edx,4(%rax)\n\t" /* ExceptionFlags */ 355 "movq $0,8(%rax)\n\t" /* ExceptionRecord */ 356 "leaq " __ASM_NAME("RaiseException") "(%rip),%rcx\n\t" 357 "movq %rcx,0x10(%rax)\n\t" /* ExceptionAddress */ 358 "movq %rax,%rcx\n\t" 359 "movl $0,0x18(%rcx)\n\t" /* NumberParameters */ 360 "testl %r8d,%r8d\n\t" 361 "jz 2f\n\t" 362 "testq %r9,%r9\n\t" 363 "jz 2f\n\t" 364 "movl $15,%edx\n\t" 365 "cmp %edx,%r8d\n\t" 366 "cmovb %r8d,%edx\n\t" 367 "movl %edx,0x18(%rcx)\n\t" /* NumberParameters */ 368 "leaq 0x20(%rcx),%rax\n" /* ExceptionInformation */ 369 "1:\tmovq (%r9),%r8\n\t" 370 "movq %r8,(%rax)\n\t" 371 "decl %edx\n\t" 372 "jz 2f\n\t" 373 "addq $8,%rax\n\t" 374 "addq $8,%r9\n\t" 375 "jmp 1b\n" 376 "2:\tcall " __ASM_NAME("RtlRaiseException") "\n\t" 377 "add $0xc8,%rsp\n\t" 378 __ASM_CFI(".cfi_adjust_cfa_offset -0xc8\n\t") 379 "ret" ) 380#endif /* __arm64ec__ */ 381C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionCode) == 0 ); 382C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionFlags) == 4 ); 383C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionRecord) == 8 ); 384C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionAddress) == 0x10 ); 385C_ASSERT( offsetof(EXCEPTION_RECORD, NumberParameters) == 0x18 ); 386C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionInformation) == 0x20 ); 387#else /* __x86_64__ */ 388void WINAPI DECLSPEC_HOTPATCH RaiseException( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args ) 389{ 390 EXCEPTION_RECORD record; 391 392 record.ExceptionCode = code; 393 record.ExceptionFlags = flags & EXCEPTION_NONCONTINUABLE; 394 record.ExceptionRecord = NULL; 395 record.ExceptionAddress = RaiseException; 396 if (count && args) 397 { 398 if (count > EXCEPTION_MAXIMUM_PARAMETERS) count = EXCEPTION_MAXIMUM_PARAMETERS; 399 record.NumberParameters = count; 400 memcpy( record.ExceptionInformation, args, count * sizeof(*args) ); 401 } 402 else record.NumberParameters = 0; 403 404 RtlRaiseException( &record ); 405} 406#endif 407 408#ifdef __i386__ 409__ASM_STDCALL_IMPORT(RaiseException,16) 410#else 411__ASM_GLOBAL_IMPORT(RaiseException) 412#endif 413 414/******************************************************************* 415 * RaiseFailFastException (kernelbase.@) 416 */ 417void WINAPI DECLSPEC_HOTPATCH RaiseFailFastException( EXCEPTION_RECORD *record, CONTEXT *context, DWORD flags ) 418{ 419 FIXME( "(%p, %p, %ld) stub\n", record, context, flags ); 420 TerminateProcess( GetCurrentProcess(), STATUS_FAIL_FAST_EXCEPTION ); 421} 422 423/*********************************************************************** 424 * SetUnhandledExceptionFilter (kernelbase.@) 425 */ 426LPTOP_LEVEL_EXCEPTION_FILTER WINAPI DECLSPEC_HOTPATCH SetUnhandledExceptionFilter( 427 LPTOP_LEVEL_EXCEPTION_FILTER filter ) 428{ 429 return InterlockedExchangePointer( (void **)&top_filter, filter ); 430} 431 432 433/******************************************************************* 434 * format_exception_msg 435 */ 436static void format_exception_msg( const EXCEPTION_POINTERS *ptr, char *buffer, int size ) 437{ 438 const EXCEPTION_RECORD *rec = ptr->ExceptionRecord; 439 int len; 440 441 switch(rec->ExceptionCode) 442 { 443 case EXCEPTION_INT_DIVIDE_BY_ZERO: 444 len = snprintf( buffer, size, "Unhandled division by zero" ); 445 break; 446 case EXCEPTION_INT_OVERFLOW: 447 len = snprintf( buffer, size, "Unhandled overflow" ); 448 break; 449 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 450 len = snprintf( buffer, size, "Unhandled array bounds" ); 451 break; 452 case EXCEPTION_ILLEGAL_INSTRUCTION: 453 len = snprintf( buffer, size, "Unhandled illegal instruction" ); 454 break; 455 case EXCEPTION_STACK_OVERFLOW: 456 len = snprintf( buffer, size, "Unhandled stack overflow" ); 457 break; 458 case EXCEPTION_PRIV_INSTRUCTION: 459 len = snprintf( buffer, size, "Unhandled privileged instruction" ); 460 break; 461 case EXCEPTION_ACCESS_VIOLATION: 462 if (rec->NumberParameters == 2) 463 len = snprintf( buffer, size, "Unhandled page fault on %s access to %p", 464 rec->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT ? "write" : 465 rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT ? "execute" : "read", 466 (void *)rec->ExceptionInformation[1]); 467 else 468 len = snprintf( buffer, size, "Unhandled page fault"); 469 break; 470 case EXCEPTION_DATATYPE_MISALIGNMENT: 471 len = snprintf( buffer, size, "Unhandled alignment" ); 472 break; 473 case CONTROL_C_EXIT: 474 len = snprintf( buffer, size, "Unhandled ^C"); 475 break; 476 case STATUS_POSSIBLE_DEADLOCK: 477 len = snprintf( buffer, size, "Critical section %p wait failed", 478 (void *)rec->ExceptionInformation[0]); 479 break; 480 case EXCEPTION_WINE_STUB: 481 if ((ULONG_PTR)rec->ExceptionInformation[1] >> 16) 482 len = snprintf( buffer, size, "Unimplemented function %s.%s called", 483 (char *)rec->ExceptionInformation[0], (char *)rec->ExceptionInformation[1] ); 484 else 485 len = snprintf( buffer, size, "Unimplemented function %s.%Id called", 486 (char *)rec->ExceptionInformation[0], rec->ExceptionInformation[1] ); 487 break; 488 case EXCEPTION_WINE_ASSERTION: 489 len = snprintf( buffer, size, "Assertion failed" ); 490 break; 491 default: 492 len = snprintf( buffer, size, "Unhandled exception 0x%08lx in thread %lx", 493 rec->ExceptionCode, GetCurrentThreadId()); 494 break; 495 } 496 if (len < 0 || len >= size) return; 497 snprintf( buffer + len, size - len, " at address %p", ptr->ExceptionRecord->ExceptionAddress ); 498} 499 500 501/****************************************************************** 502 * start_debugger 503 * 504 * Does the effective debugger startup according to 'format' 505 */ 506static BOOL start_debugger( EXCEPTION_POINTERS *epointers, HANDLE event ) 507{ 508 OBJECT_ATTRIBUTES attr; 509 UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" ); 510 WCHAR *cmdline, *env, *p, *format = NULL; 511 HANDLE dbg_key; 512 DWORD autostart = TRUE; 513 PROCESS_INFORMATION info; 514 STARTUPINFOW startup; 515 BOOL ret = FALSE; 516 char buffer[256]; 517 518 format_exception_msg( epointers, buffer, sizeof(buffer) ); 519 MESSAGE( "wine: %s (thread %04lx), starting debugger...\n", buffer, GetCurrentThreadId() ); 520 521 attr.Length = sizeof(attr); 522 attr.RootDirectory = 0; 523 attr.ObjectName = &nameW; 524 attr.Attributes = 0; 525 attr.SecurityDescriptor = NULL; 526 attr.SecurityQualityOfService = NULL; 527 528 if (!NtOpenKey( &dbg_key, KEY_READ, &attr )) 529 { 530 KEY_VALUE_PARTIAL_INFORMATION *info; 531 DWORD format_size = 0; 532 533 RtlInitUnicodeString( &nameW, L"Debugger" ); 534 if (NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation, 535 NULL, 0, &format_size ) == STATUS_BUFFER_TOO_SMALL) 536 { 537 char *data = HeapAlloc( GetProcessHeap(), 0, format_size ); 538 NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation, 539 data, format_size, &format_size ); 540 info = (KEY_VALUE_PARTIAL_INFORMATION *)data; 541 format = HeapAlloc( GetProcessHeap(), 0, info->DataLength + sizeof(WCHAR) ); 542 memcpy( format, info->Data, info->DataLength ); 543 format[info->DataLength / sizeof(WCHAR)] = 0; 544 545 if (info->Type == REG_EXPAND_SZ) 546 { 547 WCHAR *tmp; 548 549 format_size = ExpandEnvironmentStringsW( format, NULL, 0 ); 550 tmp = HeapAlloc( GetProcessHeap(), 0, format_size * sizeof(WCHAR)); 551 ExpandEnvironmentStringsW( format, tmp, format_size ); 552 HeapFree( GetProcessHeap(), 0, format ); 553 format = tmp; 554 } 555 HeapFree( GetProcessHeap(), 0, data ); 556 } 557 558 RtlInitUnicodeString( &nameW, L"Auto" ); 559 if (!NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation, 560 buffer, sizeof(buffer)-sizeof(WCHAR), &format_size )) 561 { 562 info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; 563 if (info->Type == REG_DWORD) memcpy( &autostart, info->Data, sizeof(DWORD) ); 564 else if (info->Type == REG_SZ) 565 { 566 WCHAR *str = (WCHAR *)info->Data; 567 str[info->DataLength/sizeof(WCHAR)] = 0; 568 autostart = wcstol( str, NULL, 10 ); 569 } 570 } 571 572 NtClose( dbg_key ); 573 } 574 575 if (format) 576 { 577 size_t format_size = lstrlenW( format ) + 2*20; 578 cmdline = HeapAlloc( GetProcessHeap(), 0, format_size * sizeof(WCHAR) ); 579 swprintf( cmdline, format_size, format, GetCurrentProcessId(), HandleToLong(event) ); 580 HeapFree( GetProcessHeap(), 0, format ); 581 } 582 else 583 { 584 cmdline = HeapAlloc( GetProcessHeap(), 0, 80 * sizeof(WCHAR) ); 585 swprintf( cmdline, 80, L"winedbg --auto %ld %ld", GetCurrentProcessId(), HandleToLong(event) ); 586 } 587 588 if (!autostart) 589 { 590 HMODULE mod = GetModuleHandleA( "user32.dll" ); 591 MessageBoxA_funcptr pMessageBoxA = NULL; 592 593 if (mod) pMessageBoxA = (void *)GetProcAddress( mod, "MessageBoxA" ); 594 if (pMessageBoxA) 595 { 596 static const char msg[] = ".\nDo you wish to debug it?"; 597 598 format_exception_msg( epointers, buffer, sizeof(buffer) - sizeof(msg) ); 599 strcat( buffer, msg ); 600 if (pMessageBoxA( 0, buffer, "Exception raised", MB_YESNO | MB_ICONHAND ) == IDNO) 601 { 602 TRACE( "Killing process\n" ); 603 goto exit; 604 } 605 } 606 } 607 608 /* make WINEDEBUG empty in the environment */ 609 env = GetEnvironmentStringsW(); 610 if (!TRACE_ON(winedbg)) 611 { 612 for (p = env; *p; p += lstrlenW(p) + 1) 613 { 614 if (!wcsncmp( p, L"WINEDEBUG=", 10 )) 615 { 616 WCHAR *next = p + lstrlenW(p); 617 WCHAR *end = next + 1; 618 while (*end) end += lstrlenW(end) + 1; 619 memmove( p + 10, next, end + 1 - next ); 620 break; 621 } 622 } 623 } 624 625 TRACE( "Starting debugger %s\n", debugstr_w(cmdline) ); 626 memset( &startup, 0, sizeof(startup) ); 627 startup.cb = sizeof(startup); 628 startup.dwFlags = STARTF_USESHOWWINDOW; 629 startup.wShowWindow = SW_SHOWNORMAL; 630 ret = CreateProcessW( NULL, cmdline, NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, env, NULL, &startup, &info ); 631 FreeEnvironmentStringsW( env ); 632 633 if (ret) 634 { 635 /* wait for debugger to come up... */ 636 HANDLE handles[2]; 637 CloseHandle( info.hThread ); 638 handles[0] = event; 639 handles[1] = info.hProcess; 640 WaitForMultipleObjects( 2, handles, FALSE, INFINITE ); 641 CloseHandle( info.hProcess ); 642 } 643 else ERR( "Couldn't start debugger %s (%ld)\n" 644 "Read the Wine Developers Guide on how to set up winedbg or another debugger\n", 645 debugstr_w(cmdline), GetLastError() ); 646exit: 647 HeapFree(GetProcessHeap(), 0, cmdline); 648 return ret; 649} 650 651/****************************************************************** 652 * start_debugger_atomic 653 * 654 * starts the debugger in an atomic way: 655 * - either the debugger is not started and it is started 656 * - or the debugger has already been started by another thread 657 * - or the debugger couldn't be started 658 * 659 * returns TRUE for the two first conditions, FALSE for the last 660 */ 661static BOOL start_debugger_atomic( EXCEPTION_POINTERS *epointers ) 662{ 663 static HANDLE once; 664 665 if (once == 0) 666 { 667 OBJECT_ATTRIBUTES attr; 668 HANDLE event; 669 670 attr.Length = sizeof(attr); 671 attr.RootDirectory = 0; 672 attr.Attributes = OBJ_INHERIT; 673 attr.ObjectName = NULL; 674 attr.SecurityDescriptor = NULL; 675 attr.SecurityQualityOfService = NULL; 676 677 /* ask for manual reset, so that once the debugger is started, 678 * every thread will know it */ 679 NtCreateEvent( &event, EVENT_ALL_ACCESS, &attr, NotificationEvent, FALSE ); 680 if (InterlockedCompareExchangePointer( &once, event, 0 ) == 0) 681 { 682 /* ok, our event has been set... we're the winning thread */ 683 BOOL ret = start_debugger( epointers, once ); 684 685 if (!ret) 686 { 687 /* so that the other threads won't be stuck */ 688 NtSetEvent( once, NULL ); 689 } 690 return ret; 691 } 692 693 /* someone beat us here... */ 694 CloseHandle( event ); 695 } 696 697 /* and wait for the winner to have actually created the debugger */ 698 WaitForSingleObject( once, INFINITE ); 699 /* in fact, here, we only know that someone has tried to start the debugger, 700 * we'll know by reposting the exception if it has actually attached 701 * to the current process */ 702 return TRUE; 703} 704 705 706/******************************************************************* 707 * check_resource_write 708 * 709 * Check if the exception is a write attempt to the resource data. 710 * If yes, we unprotect the resources to let broken apps continue 711 * (Windows does this too). 712 */ 713static BOOL check_resource_write( void *addr ) 714{ 715 DWORD old_prot; 716 void *rsrc; 717 DWORD size; 718 MEMORY_BASIC_INFORMATION info; 719 720 if (!VirtualQuery( addr, &info, sizeof(info) )) return FALSE; 721 if (info.State == MEM_FREE || !(info.Type & MEM_IMAGE)) return FALSE; 722 if (!(rsrc = RtlImageDirectoryEntryToData( info.AllocationBase, TRUE, 723 IMAGE_DIRECTORY_ENTRY_RESOURCE, &size ))) 724 return FALSE; 725 if (addr < rsrc || (char *)addr >= (char *)rsrc + size) return FALSE; 726 TRACE( "Broken app is writing to the resource data, enabling work-around\n" ); 727 VirtualProtect( rsrc, size, PAGE_READWRITE, &old_prot ); 728 return TRUE; 729} 730 731 732/******************************************************************* 733 * UnhandledExceptionFilter (kernelbase.@) 734 */ 735LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS *epointers ) 736{ 737 const EXCEPTION_RECORD *rec = epointers->ExceptionRecord; 738 739 if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && rec->NumberParameters >= 2) 740 { 741 switch (rec->ExceptionInformation[0]) 742 { 743 case EXCEPTION_WRITE_FAULT: 744 if (check_resource_write( (void *)rec->ExceptionInformation[1] )) 745 return EXCEPTION_CONTINUE_EXECUTION; 746 break; 747 } 748 } 749 750 if (!NtCurrentTeb()->Peb->BeingDebugged) 751 { 752 if (rec->ExceptionCode == CONTROL_C_EXIT) 753 { 754 /* do not launch the debugger on ^C, simply terminate the process */ 755 TerminateProcess( GetCurrentProcess(), 1 ); 756 } 757 758 if (top_filter) 759 { 760 LONG ret = top_filter( epointers ); 761 if (ret != EXCEPTION_CONTINUE_SEARCH) return ret; 762 } 763 764 if ((GetErrorMode() & SEM_NOGPFAULTERRORBOX) || 765 !start_debugger_atomic( epointers ) || !NtCurrentTeb()->Peb->BeingDebugged) 766 return EXCEPTION_EXECUTE_HANDLER; 767 } 768 return EXCEPTION_CONTINUE_SEARCH; 769} 770 771 772/*********************************************************************** 773 * WerGetFlags (kernelbase.@) 774 */ 775HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerGetFlags( HANDLE process, DWORD *flags ) 776{ 777 FIXME( "(%p, %p) stub\n", process, flags ); 778 return E_NOTIMPL; 779} 780 781 782/*********************************************************************** 783 * WerRegisterFile (kernelbase.@) 784 */ 785HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterFile( const WCHAR *file, WER_REGISTER_FILE_TYPE type, 786 DWORD flags ) 787{ 788 FIXME( "(%s, %d, %ld) stub\n", debugstr_w(file), type, flags ); 789 return E_NOTIMPL; 790} 791 792 793/*********************************************************************** 794 * WerRegisterMemoryBlock (kernelbase.@) 795 */ 796HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterMemoryBlock( void *block, DWORD size ) 797{ 798 FIXME( "(%p %ld) stub\n", block, size ); 799 return E_NOTIMPL; 800} 801 802 803/*********************************************************************** 804 * WerRegisterRuntimeExceptionModule (kernelbase.@) 805 */ 806HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterRuntimeExceptionModule( const WCHAR *dll, void *context ) 807{ 808 FIXME( "(%s, %p) stub\n", debugstr_w(dll), context ); 809 return S_OK; 810} 811 812 813/*********************************************************************** 814 * WerSetFlags (kernelbase.@) 815 */ 816HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerSetFlags( DWORD flags ) 817{ 818 FIXME("(%ld) stub\n", flags); 819 return S_OK; 820} 821 822 823/*********************************************************************** 824 * WerUnregisterFile (kernelbase.@) 825 */ 826HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterFile( const WCHAR *file ) 827{ 828 FIXME( "(%s) stub\n", debugstr_w(file) ); 829 return E_NOTIMPL; 830} 831 832 833/*********************************************************************** 834 * WerUnregisterMemoryBlock (kernelbase.@) 835 */ 836HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterMemoryBlock( void *block ) 837{ 838 FIXME( "(%p) stub\n", block ); 839 return E_NOTIMPL; 840} 841 842 843/*********************************************************************** 844 * WerUnregisterRuntimeExceptionModule (kernelbase.@) 845 */ 846HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterRuntimeExceptionModule( const WCHAR *dll, void *context ) 847{ 848 FIXME( "(%s, %p) stub\n", debugstr_w(dll), context ); 849 return S_OK; 850} 851 852 853/*********************************************************************** 854 * psapi functions 855 ***********************************************************************/ 856 857 858typedef struct _LDR_DATA_TABLE_ENTRY32 859{ 860 LIST_ENTRY32 InLoadOrderModuleList; 861 LIST_ENTRY32 InMemoryOrderModuleList; 862 LIST_ENTRY32 InInitializationOrderModuleList; 863 DWORD BaseAddress; 864 DWORD EntryPoint; 865 ULONG SizeOfImage; 866 UNICODE_STRING32 FullDllName; 867 UNICODE_STRING32 BaseDllName; 868} LDR_DATA_TABLE_ENTRY32; 869 870struct module_iterator 871{ 872 HANDLE process; 873 LIST_ENTRY *head; 874 LIST_ENTRY *current; 875 BOOL wow64; 876 LDR_DATA_TABLE_ENTRY ldr_module; 877 LDR_DATA_TABLE_ENTRY32 ldr_module32; 878}; 879 880 881static BOOL init_module_iterator_wow64( struct module_iterator *iter, HANDLE process ) 882{ 883 PEB_LDR_DATA32 *ldr_data32_ptr; 884 DWORD ldr_data32, first_module; 885 PEB32 *peb32; 886 887 iter->wow64 = TRUE; 888 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessWow64Information, 889 &peb32, sizeof(peb32), NULL ))) 890 return FALSE; 891 if (!ReadProcessMemory( process, &peb32->LdrData, &ldr_data32, sizeof(ldr_data32), NULL )) 892 return FALSE; 893 ldr_data32_ptr = (PEB_LDR_DATA32 *)(DWORD_PTR) ldr_data32; 894 if (!ReadProcessMemory( process, &ldr_data32_ptr->InLoadOrderModuleList.Flink, 895 &first_module, sizeof(first_module), NULL )) 896 return FALSE; 897 iter->head = (LIST_ENTRY *)&ldr_data32_ptr->InLoadOrderModuleList; 898 iter->current = (LIST_ENTRY *)(DWORD_PTR)first_module; 899 iter->process = process; 900 return TRUE; 901} 902 903 904static BOOL init_module_iterator( struct module_iterator *iter, HANDLE process ) 905{ 906 PROCESS_BASIC_INFORMATION pbi; 907 PPEB_LDR_DATA ldr_data; 908 909 iter->wow64 = FALSE; 910 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation, 911 &pbi, sizeof(pbi), NULL ))) 912 return FALSE; 913 914 /* read address of LdrData from PEB */ 915 if (!ReadProcessMemory( process, &pbi.PebBaseAddress->LdrData, &ldr_data, sizeof(ldr_data), NULL )) 916 return FALSE; 917 918 /* This happens when running "old" wow64 configuration. Mark it as such. */ 919 if (!ldr_data) 920 { 921 SetLastError( ERROR_EMPTY ); 922 return FALSE; 923 } 924 /* read address of first module from LdrData */ 925 if (!ReadProcessMemory( process, &ldr_data->InLoadOrderModuleList.Flink, 926 &iter->current, sizeof(iter->current), NULL )) 927 return FALSE; 928 929 iter->head = &ldr_data->InLoadOrderModuleList; 930 iter->process = process; 931 return TRUE; 932} 933 934 935static int module_iterator_next( struct module_iterator *iter ) 936{ 937 if (iter->current == iter->head) return 0; 938 939 if (is_win64 && iter->wow64) 940 { 941 LIST_ENTRY32 *entry32 = (LIST_ENTRY32 *)iter->current; 942 943 if (!ReadProcessMemory( iter->process, 944 CONTAINING_RECORD(entry32, LDR_DATA_TABLE_ENTRY32, InLoadOrderModuleList), 945 &iter->ldr_module32, sizeof(iter->ldr_module32), NULL )) 946 return -1; 947 iter->current = (LIST_ENTRY *)(DWORD_PTR)iter->ldr_module32.InLoadOrderModuleList.Flink; 948 return 1; 949 } 950 951 if (!ReadProcessMemory( iter->process, 952 CONTAINING_RECORD(iter->current, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks), 953 &iter->ldr_module, sizeof(iter->ldr_module), NULL )) 954 return -1; 955 956 iter->current = iter->ldr_module.InLoadOrderLinks.Flink; 957 return 1; 958} 959 960 961static BOOL get_ldr_module( HANDLE process, HMODULE module, LDR_DATA_TABLE_ENTRY *ldr_module ) 962{ 963 struct module_iterator iter; 964 INT ret; 965 966 if (!init_module_iterator( &iter, process )) return FALSE; 967 968 while ((ret = module_iterator_next( &iter )) > 0) 969 /* When hModule is NULL we return the process image - which will be 970 * the first module since our iterator uses InLoadOrderModuleList */ 971 if (!module || module == iter.ldr_module.DllBase) 972 { 973 *ldr_module = iter.ldr_module; 974 return TRUE; 975 } 976 977 if (ret == 0) SetLastError( ERROR_INVALID_HANDLE ); 978 return FALSE; 979} 980 981 982static BOOL get_ldr_module32( HANDLE process, HMODULE module, LDR_DATA_TABLE_ENTRY32 *ldr_module ) 983{ 984 struct module_iterator iter; 985 INT ret; 986 987#ifdef _WIN64 988 if ((ULONG_PTR)module >> 32) 989 { 990 SetLastError( ERROR_INVALID_HANDLE ); 991 return FALSE; 992 } 993#endif 994 if (!init_module_iterator_wow64( &iter, process )) return FALSE; 995 996 while ((ret = module_iterator_next( &iter )) > 0) 997 /* When hModule is NULL we return the process image - which will be 998 * the first module since our iterator uses InLoadOrderModuleList */ 999 if (!module || (DWORD)(DWORD_PTR)module == iter.ldr_module32.BaseAddress) 1000 { 1001 *ldr_module = iter.ldr_module32; 1002 return TRUE; 1003 } 1004 1005 if (ret == 0) SetLastError( ERROR_INVALID_HANDLE ); 1006 return FALSE; 1007} 1008 1009 1010/*********************************************************************** 1011 * EmptyWorkingSet (kernelbase.@) 1012 * K32EmptyWorkingSet (kernelbase.@) 1013 */ 1014BOOL WINAPI DECLSPEC_HOTPATCH EmptyWorkingSet( HANDLE process ) 1015{ 1016 return SetProcessWorkingSetSizeEx( process, (SIZE_T)-1, (SIZE_T)-1, 0 ); 1017} 1018 1019 1020/*********************************************************************** 1021 * EnumDeviceDrivers (kernelbase.@) 1022 * K32EnumDeviceDrivers (kernelbase.@) 1023 */ 1024BOOL WINAPI EnumDeviceDrivers( void **image_base, DWORD count, DWORD *needed ) 1025{ 1026 FIXME( "(%p, %ld, %p): stub\n", image_base, count, needed ); 1027 if (needed) *needed = 0; 1028 return TRUE; 1029} 1030 1031 1032/*********************************************************************** 1033 * EnumPageFilesA (kernelbase.@) 1034 * K32EnumPageFilesA (kernelbase.@) 1035 */ 1036BOOL WINAPI /* DECLSPEC_HOTPATCH */ EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, void *context ) 1037{ 1038 FIXME( "(%p, %p) stub\n", callback, context ); 1039 return FALSE; 1040} 1041 1042 1043/*********************************************************************** 1044 * EnumPageFilesW (kernelbase.@) 1045 * K32EnumPageFilesW (kernelbase.@) 1046 */ 1047BOOL WINAPI /* DECLSPEC_HOTPATCH */ EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, void *context ) 1048{ 1049 FIXME( "(%p, %p) stub\n", callback, context ); 1050 return FALSE; 1051} 1052 1053 1054/*********************************************************************** 1055 * EnumProcessModules (kernelbase.@) 1056 * K32EnumProcessModules (kernelbase.@) 1057 */ 1058BOOL WINAPI DECLSPEC_HOTPATCH EnumProcessModules( HANDLE process, HMODULE *module, 1059 DWORD count, DWORD *needed ) 1060{ 1061 return EnumProcessModulesEx( process, module, count, needed, LIST_MODULES_DEFAULT ); 1062} 1063 1064 1065struct module_push 1066{ 1067 HMODULE *module; 1068 unsigned count; 1069 unsigned size; 1070}; 1071 1072static void module_push( struct module_push *mp, HMODULE module ) 1073{ 1074 if (mp->count >= sizeof(HMODULE)) 1075 { 1076 *mp->module++ = module; 1077 mp->count -= sizeof(HMODULE); 1078 } 1079 mp->size += sizeof(HMODULE); 1080} 1081 1082static void module_push_iter( struct module_push *mp, struct module_iterator *iter ) 1083{ 1084 if (is_win64 && iter->wow64) 1085 module_push( mp, (HMODULE) (DWORD_PTR)iter->ldr_module32.BaseAddress ); 1086 else 1087 module_push( mp, iter->ldr_module.DllBase ); 1088} 1089 1090static int module_push_all( struct module_push *mp, struct module_iterator *iter ) 1091{ 1092 int ret; 1093 1094 while ((ret = module_iterator_next( iter )) > 0) 1095 module_push_iter( mp, iter ); 1096 1097 return ret; 1098} 1099 1100/*********************************************************************** 1101 * EnumProcessModulesEx (kernelbase.@) 1102 * K32EnumProcessModulesEx (kernelbase.@) 1103 */ 1104BOOL WINAPI EnumProcessModulesEx( HANDLE process, HMODULE *module, DWORD count, 1105 DWORD *needed, DWORD filter ) 1106{ 1107 struct module_push mp = {module, count, 0}; 1108 unsigned list_mode; 1109 BOOL target_wow64; 1110 INT ret = 0; 1111 1112 TRACE( "(%p, %p, %ld, %p, %ld)\n", process, module, count, needed, filter ); 1113 1114 if (process != GetCurrentProcess()) 1115 { 1116 if (!IsWow64Process( process, &target_wow64 )) return FALSE; 1117 } 1118 else target_wow64 = is_wow64; 1119 1120 if (filter & ~LIST_MODULES_ALL) 1121 { 1122 SetLastError( ERROR_INVALID_PARAMETER ); 1123 return FALSE; 1124 } 1125 list_mode = filter & LIST_MODULES_ALL; 1126 /* Can't access 64bit process from (wow64) 32bit */ 1127 if (is_wow64 && !target_wow64) 1128 { 1129 SetLastError( ERROR_PARTIAL_COPY ); 1130 return FALSE; 1131 } 1132 if (count && !module) 1133 { 1134 SetLastError( ERROR_NOACCESS ); 1135 return FALSE; 1136 } 1137 1138 if (process == GetCurrentProcess()) 1139 { 1140 if (!(is_win64 && list_mode == LIST_MODULES_32BIT)) 1141 { 1142 PPEB_LDR_DATA ldr_data = NtCurrentTeb()->Peb->LdrData; 1143 PLIST_ENTRY head = &ldr_data->InLoadOrderModuleList; 1144 PLIST_ENTRY entry = head->Flink; 1145 1146 while (entry != head) 1147 { 1148 LDR_DATA_TABLE_ENTRY *ldr = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks ); 1149 module_push( &mp, ldr->DllBase ); 1150 entry = entry->Flink; 1151 } 1152 } 1153 } 1154 else 1155 { 1156 struct module_iterator iter; 1157 1158 if (is_win64 && target_wow64 && (list_mode & LIST_MODULES_32BIT)) 1159 { 1160 if (!init_module_iterator_wow64( &iter, process ) || module_push_all( &mp, &iter ) < 0) 1161 return FALSE; 1162 } 1163 if (!(is_win64 && list_mode == LIST_MODULES_32BIT)) 1164 { 1165 if (init_module_iterator( &iter, process )) 1166 { 1167 if (is_win64 && target_wow64 && (list_mode & LIST_MODULES_64BIT)) 1168 /* Don't add main module twice in _ALL mode */ 1169 ret = module_iterator_next( &iter ); 1170 if (ret >= 0) ret = module_push_all( &mp, &iter ); 1171 } 1172 else if (GetLastError() == ERROR_EMPTY) 1173 { 1174 /* We're running on "old" wow configuration. 1175 * Fallback to PEB32 to get at least main module if requested. 1176 */ 1177 if (list_mode == LIST_MODULES_DEFAULT) 1178 { 1179 if (init_module_iterator_wow64( &iter, process ) && module_iterator_next( &iter ) > 0) 1180 module_push_iter( &mp, &iter ); 1181 else 1182 ret = -1; 1183 } 1184 } 1185 else 1186 return FALSE; 1187 } 1188 } 1189 1190 if (!needed) 1191 { 1192 SetLastError( ERROR_NOACCESS ); 1193 return FALSE; 1194 } 1195 *needed = mp.size; 1196 return ret == 0; 1197} 1198 1199 1200/*********************************************************************** 1201 * EnumProcesses (kernelbase.@) 1202 * K32EnumProcesses (kernelbase.@) 1203 */ 1204BOOL WINAPI EnumProcesses( DWORD *ids, DWORD count, DWORD *used ) 1205{ 1206 SYSTEM_PROCESS_INFORMATION *spi; 1207 ULONG size = 0x4000; 1208 void *buf = NULL; 1209 NTSTATUS status; 1210 1211 do 1212 { 1213 size *= 2; 1214 HeapFree( GetProcessHeap(), 0, buf ); 1215 if (!(buf = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE; 1216 status = NtQuerySystemInformation( SystemProcessInformation, buf, size, NULL ); 1217 } while (status == STATUS_INFO_LENGTH_MISMATCH); 1218 1219 if (!set_ntstatus( status )) 1220 { 1221 HeapFree( GetProcessHeap(), 0, buf ); 1222 return FALSE; 1223 } 1224 spi = buf; 1225 for (*used = 0; count >= sizeof(DWORD); count -= sizeof(DWORD)) 1226 { 1227 *ids++ = HandleToUlong( spi->UniqueProcessId ); 1228 *used += sizeof(DWORD); 1229 if (spi->NextEntryOffset == 0) break; 1230 spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->NextEntryOffset); 1231 } 1232 HeapFree( GetProcessHeap(), 0, buf ); 1233 return TRUE; 1234} 1235 1236 1237/*********************************************************************** 1238 * GetDeviceDriverBaseNameA (kernelbase.@) 1239 * K32GetDeviceDriverBaseNameA (kernelbase.@) 1240 */ 1241DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverBaseNameA( void *image_base, char *name, DWORD size ) 1242{ 1243 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size ); 1244 if (name && size) name[0] = 0; 1245 return 0; 1246} 1247 1248 1249/*********************************************************************** 1250 * GetDeviceDriverBaseNameW (kernelbase.@) 1251 * K32GetDeviceDriverBaseNameW (kernelbase.@) 1252 */ 1253DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverBaseNameW( void *image_base, WCHAR *name, DWORD size ) 1254{ 1255 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size ); 1256 if (name && size) name[0] = 0; 1257 return 0; 1258} 1259 1260 1261/*********************************************************************** 1262 * GetDeviceDriverFileNameA (kernelbase.@) 1263 * K32GetDeviceDriverFileNameA (kernelbase.@) 1264 */ 1265DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverFileNameA( void *image_base, char *name, DWORD size ) 1266{ 1267 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size ); 1268 if (name && size) name[0] = 0; 1269 return 0; 1270} 1271 1272 1273/*********************************************************************** 1274 * GetDeviceDriverFileNameW (kernelbase.@) 1275 * K32GetDeviceDriverFileNameW (kernelbase.@) 1276 */ 1277DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverFileNameW( void *image_base, WCHAR *name, DWORD size ) 1278{ 1279 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size ); 1280 if (name && size) name[0] = 0; 1281 return 0; 1282} 1283 1284 1285/*********************************************************************** 1286 * GetMappedFileNameA (kernelbase.@) 1287 * K32GetMappedFileNameA (kernelbase.@) 1288 */ 1289DWORD WINAPI DECLSPEC_HOTPATCH GetMappedFileNameA( HANDLE process, void *addr, char *name, DWORD size ) 1290{ 1291 WCHAR nameW[MAX_PATH]; 1292 DWORD len; 1293 1294 if (size && !name) 1295 { 1296 SetLastError( ERROR_INVALID_PARAMETER ); 1297 return 0; 1298 } 1299 if (!GetMappedFileNameW( process, addr, nameW, MAX_PATH )) return 0; 1300 if (!size) 1301 { 1302 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 1303 return 0; 1304 } 1305 len = file_name_WtoA( nameW, wcslen(nameW), name, size ); 1306 name[min(len, size - 1)] = 0; 1307 return len; 1308} 1309 1310 1311/*********************************************************************** 1312 * GetMappedFileNameW (kernelbase.@) 1313 * K32GetMappedFileNameW (kernelbase.@) 1314 */ 1315DWORD WINAPI DECLSPEC_HOTPATCH GetMappedFileNameW( HANDLE process, void *addr, WCHAR *name, DWORD size ) 1316{ 1317 ULONG_PTR buffer[(sizeof(MEMORY_SECTION_NAME) + MAX_PATH * sizeof(WCHAR)) / sizeof(ULONG_PTR)]; 1318 MEMORY_SECTION_NAME *mem = (MEMORY_SECTION_NAME *)buffer; 1319 DWORD len; 1320 1321 if (size && !name) 1322 { 1323 SetLastError( ERROR_INVALID_PARAMETER ); 1324 return 0; 1325 } 1326 if (!set_ntstatus( NtQueryVirtualMemory( process, addr, MemoryMappedFilenameInformation, 1327 mem, sizeof(buffer), NULL ))) 1328 return 0; 1329 1330 len = mem->SectionFileName.Length / sizeof(WCHAR); 1331 memcpy( name, mem->SectionFileName.Buffer, min( mem->SectionFileName.Length, size * sizeof(WCHAR) )); 1332 if (len >= size) SetLastError( ERROR_INSUFFICIENT_BUFFER ); 1333 name[min(len, size - 1)] = 0; 1334 return len; 1335} 1336 1337 1338/*********************************************************************** 1339 * GetModuleBaseNameA (kernelbase.@) 1340 * K32GetModuleBaseNameA (kernelbase.@) 1341 */ 1342DWORD WINAPI DECLSPEC_HOTPATCH GetModuleBaseNameA( HANDLE process, HMODULE module, 1343 char *name, DWORD size ) 1344{ 1345 WCHAR *name_w; 1346 DWORD len, ret = 0; 1347 1348 if (!name || !size) 1349 { 1350 SetLastError( ERROR_INVALID_PARAMETER ); 1351 return 0; 1352 } 1353 if (!(name_w = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * size ))) return 0; 1354 1355 len = GetModuleBaseNameW( process, module, name_w, size ); 1356 TRACE( "%ld, %s\n", len, debugstr_w(name_w) ); 1357 if (len) 1358 { 1359 ret = WideCharToMultiByte( CP_ACP, 0, name_w, len, name, size, NULL, NULL ); 1360 if (ret < size) name[ret] = 0; 1361 } 1362 HeapFree( GetProcessHeap(), 0, name_w ); 1363 return ret; 1364} 1365 1366 1367/*********************************************************************** 1368 * GetModuleBaseNameW (kernelbase.@) 1369 * K32GetModuleBaseNameW (kernelbase.@) 1370 */ 1371DWORD WINAPI DECLSPEC_HOTPATCH GetModuleBaseNameW( HANDLE process, HMODULE module, 1372 WCHAR *name, DWORD size ) 1373{ 1374 BOOL wow64, found = FALSE; 1375 1376 if (!IsWow64Process( process, &wow64 )) return 0; 1377 1378 if (is_win64 && wow64) 1379 { 1380 LDR_DATA_TABLE_ENTRY32 ldr_module32; 1381 1382 if (get_ldr_module32(process, module, &ldr_module32)) 1383 { 1384 size = min( ldr_module32.BaseDllName.Length / sizeof(WCHAR), size ); 1385 if (ReadProcessMemory( process, (void *)(DWORD_PTR)ldr_module32.BaseDllName.Buffer, 1386 name, size * sizeof(WCHAR), NULL )) 1387 found = TRUE; 1388 } 1389 } 1390 if (!found) 1391 { 1392 LDR_DATA_TABLE_ENTRY ldr_module; 1393 1394 if (!get_ldr_module( process, module, &ldr_module )) return 0; 1395 size = min( ldr_module.BaseDllName.Length / sizeof(WCHAR), size ); 1396 if (!ReadProcessMemory( process, ldr_module.BaseDllName.Buffer, 1397 name, size * sizeof(WCHAR), NULL )) 1398 return 0; 1399 } 1400 name[size] = 0; 1401 return size; 1402} 1403 1404 1405/*********************************************************************** 1406 * GetModuleFileNameExA (kernelbase.@) 1407 * K32GetModuleFileNameExA (kernelbase.@) 1408 */ 1409DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameExA( HANDLE process, HMODULE module, 1410 char *name, DWORD size ) 1411{ 1412 WCHAR *ptr; 1413 DWORD len; 1414 1415 TRACE( "(process=%p, module=%p, %p, %ld)\n", process, module, name, size ); 1416 1417 if (!name || !size) 1418 { 1419 SetLastError( ERROR_INVALID_PARAMETER ); 1420 return 0; 1421 } 1422 if (process == GetCurrentProcess()) 1423 { 1424 len = GetModuleFileNameA( module, name, size ); 1425 name[size - 1] = '\0'; 1426 return len; 1427 } 1428 1429 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return 0; 1430 len = GetModuleFileNameExW( process, module, ptr, size ); 1431 if (!len) 1432 { 1433 name[0] = 0; 1434 } 1435 else 1436 { 1437 if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, name, size, NULL, NULL )) 1438 { 1439 name[size - 1] = 0; 1440 len = size; 1441 } 1442 else if (len < size) len = strlen( name ); 1443 } 1444 HeapFree( GetProcessHeap(), 0, ptr ); 1445 return len; 1446} 1447 1448 1449/*********************************************************************** 1450 * GetModuleFileNameExW (kernelbase.@) 1451 * K32GetModuleFileNameExW (kernelbase.@) 1452 */ 1453DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameExW( HANDLE process, HMODULE module, 1454 WCHAR *name, DWORD size ) 1455{ 1456 BOOL wow64, found = FALSE; 1457 DWORD len = 0; 1458 1459 if (!size) return 0; 1460 1461 if (!IsWow64Process( process, &wow64 )) return 0; 1462 1463 if (is_win64 && wow64) 1464 { 1465 LDR_DATA_TABLE_ENTRY32 ldr_module32; 1466 1467 if (get_ldr_module32( process, module, &ldr_module32 )) 1468 { 1469 len = ldr_module32.FullDllName.Length / sizeof(WCHAR); 1470 if (ReadProcessMemory( process, (void *)(DWORD_PTR)ldr_module32.FullDllName.Buffer, 1471 name, min( len, size ) * sizeof(WCHAR), NULL )) 1472 found = TRUE; 1473 } 1474 } 1475 if (!found) 1476 { 1477 LDR_DATA_TABLE_ENTRY ldr_module; 1478 1479 if (!get_ldr_module(process, module, &ldr_module)) return 0; 1480 len = ldr_module.FullDllName.Length / sizeof(WCHAR); 1481 if (!ReadProcessMemory( process, ldr_module.FullDllName.Buffer, 1482 name, min( len, size ) * sizeof(WCHAR), NULL )) 1483 return 0; 1484 } 1485 1486 if (len < size) 1487 { 1488 name[len] = 0; 1489 return len; 1490 } 1491 else 1492 { 1493 name[size - 1] = 0; 1494 return size; 1495 } 1496} 1497 1498 1499/*********************************************************************** 1500 * GetModuleInformation (kernelbase.@) 1501 * K32GetModuleInformation (kernelbase.@) 1502 */ 1503BOOL WINAPI GetModuleInformation( HANDLE process, HMODULE module, MODULEINFO *modinfo, DWORD count ) 1504{ 1505 BOOL wow64, found = FALSE; 1506 1507 if (count < sizeof(MODULEINFO)) 1508 { 1509 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 1510 return FALSE; 1511 } 1512 1513 if (!IsWow64Process( process, &wow64 )) return FALSE; 1514 1515 if (is_win64 && wow64) 1516 { 1517 LDR_DATA_TABLE_ENTRY32 ldr_module32; 1518 1519 if (get_ldr_module32( process, module, &ldr_module32 )) 1520 { 1521 modinfo->lpBaseOfDll = (void *)(DWORD_PTR)ldr_module32.BaseAddress; 1522 modinfo->SizeOfImage = ldr_module32.SizeOfImage; 1523 modinfo->EntryPoint = (void *)(DWORD_PTR)ldr_module32.EntryPoint; 1524 found = TRUE; 1525 } 1526 } 1527 if (!found) 1528 { 1529 LDR_DATA_TABLE_ENTRY ldr_module; 1530 1531 if (!get_ldr_module( process, module, &ldr_module )) return FALSE; 1532 modinfo->lpBaseOfDll = ldr_module.DllBase; 1533 modinfo->SizeOfImage = ldr_module.SizeOfImage; 1534 modinfo->EntryPoint = ldr_module.EntryPoint; 1535 } 1536 return TRUE; 1537} 1538 1539 1540/*********************************************************************** 1541 * GetPerformanceInfo (kernelbase.@) 1542 * K32GetPerformanceInfo (kernelbase.@) 1543 */ 1544BOOL WINAPI DECLSPEC_HOTPATCH GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size ) 1545{ 1546 SYSTEM_PERFORMANCE_INFORMATION perf; 1547 SYSTEM_BASIC_INFORMATION basic; 1548 SYSTEM_PROCESS_INFORMATION *process, *spi; 1549 DWORD info_size; 1550 NTSTATUS status; 1551 1552 TRACE( "(%p, %ld)\n", info, size ); 1553 1554 if (size < sizeof(*info)) 1555 { 1556 SetLastError( ERROR_BAD_LENGTH ); 1557 return FALSE; 1558 } 1559 1560 status = NtQuerySystemInformation( SystemPerformanceInformation, &perf, sizeof(perf), NULL ); 1561 if (!set_ntstatus( status )) return FALSE; 1562 status = NtQuerySystemInformation( SystemBasicInformation, &basic, sizeof(basic), NULL ); 1563 if (!set_ntstatus( status )) return FALSE; 1564 1565 info->cb = sizeof(*info); 1566 info->CommitTotal = perf.TotalCommittedPages; 1567 info->CommitLimit = perf.TotalCommitLimit; 1568 info->CommitPeak = perf.PeakCommitment; 1569 info->PhysicalTotal = basic.MmNumberOfPhysicalPages; 1570 info->PhysicalAvailable = perf.AvailablePages; 1571 info->SystemCache = 0; 1572 info->KernelTotal = perf.PagedPoolUsage + perf.NonPagedPoolUsage; 1573 info->KernelPaged = perf.PagedPoolUsage; 1574 info->KernelNonpaged = perf.NonPagedPoolUsage; 1575 info->PageSize = basic.PageSize; 1576 1577 /* fields from SYSTEM_PROCESS_INFORMATION */ 1578 NtQuerySystemInformation( SystemProcessInformation, NULL, 0, &info_size ); 1579 for (;;) 1580 { 1581 process = HeapAlloc( GetProcessHeap(), 0, info_size ); 1582 if (!process) 1583 { 1584 SetLastError( ERROR_OUTOFMEMORY ); 1585 return FALSE; 1586 } 1587 status = NtQuerySystemInformation( SystemProcessInformation, process, info_size, &info_size ); 1588 if (!status) break; 1589 HeapFree( GetProcessHeap(), 0, process ); 1590 if (status != STATUS_INFO_LENGTH_MISMATCH) 1591 { 1592 SetLastError( RtlNtStatusToDosError( status ) ); 1593 return FALSE; 1594 } 1595 } 1596 info->HandleCount = info->ProcessCount = info->ThreadCount = 0; 1597 spi = process; 1598 for (;;) 1599 { 1600 info->ProcessCount++; 1601 info->HandleCount += spi->HandleCount; 1602 info->ThreadCount += spi->dwThreadCount; 1603 if (spi->NextEntryOffset == 0) break; 1604 spi = (SYSTEM_PROCESS_INFORMATION *)((char *)spi + spi->NextEntryOffset); 1605 } 1606 HeapFree( GetProcessHeap(), 0, process ); 1607 return TRUE; 1608} 1609 1610 1611/*********************************************************************** 1612 * GetProcessImageFileNameA (kernelbase.@) 1613 * K32GetProcessImageFileNameA (kernelbase.@) 1614 */ 1615DWORD WINAPI DECLSPEC_HOTPATCH GetProcessImageFileNameA( HANDLE process, char *file, DWORD size ) 1616{ 1617 return QueryFullProcessImageNameA( process, PROCESS_NAME_NATIVE, file, &size ) ? size : 0; 1618} 1619 1620 1621/*********************************************************************** 1622 * GetProcessImageFileNameW (kernelbase.@) 1623 * K32GetProcessImageFileNameW (kernelbase.@) 1624 */ 1625DWORD WINAPI DECLSPEC_HOTPATCH GetProcessImageFileNameW( HANDLE process, WCHAR *file, DWORD size ) 1626{ 1627 return QueryFullProcessImageNameW( process, PROCESS_NAME_NATIVE, file, &size ) ? size : 0; 1628} 1629 1630 1631/*********************************************************************** 1632 * GetProcessMemoryInfo (kernelbase.@) 1633 * K32GetProcessMemoryInfo (kernelbase.@) 1634 */ 1635BOOL WINAPI DECLSPEC_HOTPATCH GetProcessMemoryInfo( HANDLE process, PROCESS_MEMORY_COUNTERS *pmc, 1636 DWORD count ) 1637{ 1638 VM_COUNTERS vmc; 1639 1640 if (count < sizeof(PROCESS_MEMORY_COUNTERS)) 1641 { 1642 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 1643 return FALSE; 1644 } 1645 1646 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessVmCounters, &vmc, sizeof(vmc), NULL ))) 1647 return FALSE; 1648 1649 pmc->cb = sizeof(PROCESS_MEMORY_COUNTERS); 1650 pmc->PageFaultCount = vmc.PageFaultCount; 1651 pmc->PeakWorkingSetSize = vmc.PeakWorkingSetSize; 1652 pmc->WorkingSetSize = vmc.WorkingSetSize; 1653 pmc->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage; 1654 pmc->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage; 1655 pmc->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage; 1656 pmc->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage; 1657 pmc->PagefileUsage = vmc.PagefileUsage; 1658 pmc->PeakPagefileUsage = vmc.PeakPagefileUsage; 1659 return TRUE; 1660} 1661 1662 1663/*********************************************************************** 1664 * GetWsChanges (kernelbase.@) 1665 * K32GetWsChanges (kernelbase.@) 1666 */ 1667BOOL WINAPI DECLSPEC_HOTPATCH GetWsChanges( HANDLE process, PSAPI_WS_WATCH_INFORMATION *info, DWORD size ) 1668{ 1669 TRACE( "(%p, %p, %ld)\n", process, info, size ); 1670 return set_ntstatus( NtQueryInformationProcess( process, ProcessWorkingSetWatch, info, size, NULL )); 1671} 1672 1673 1674/*********************************************************************** 1675 * GetWsChangesEx (kernelbase.@) 1676 * K32GetWsChangesEx (kernelbase.@) 1677 */ 1678BOOL WINAPI DECLSPEC_HOTPATCH GetWsChangesEx( HANDLE process, PSAPI_WS_WATCH_INFORMATION_EX *info, 1679 DWORD *size ) 1680{ 1681 FIXME( "(%p, %p, %p)\n", process, info, size ); 1682 SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); 1683 return FALSE; 1684} 1685 1686 1687/*********************************************************************** 1688 * InitializeProcessForWsWatch (kernelbase.@) 1689 * K32InitializeProcessForWsWatch (kernelbase.@) 1690 */ 1691BOOL WINAPI /* DECLSPEC_HOTPATCH */ InitializeProcessForWsWatch( HANDLE process ) 1692{ 1693 FIXME( "(process=%p): stub\n", process ); 1694 return TRUE; 1695} 1696 1697 1698/*********************************************************************** 1699 * QueryWorkingSet (kernelbase.@) 1700 * K32QueryWorkingSet (kernelbase.@) 1701 */ 1702BOOL WINAPI DECLSPEC_HOTPATCH QueryWorkingSet( HANDLE process, void *buffer, DWORD size ) 1703{ 1704 TRACE( "(%p, %p, %ld)\n", process, buffer, size ); 1705 return set_ntstatus( NtQueryVirtualMemory( process, NULL, MemoryWorkingSetInformation, 1706 buffer, size, NULL )); 1707} 1708 1709 1710/*********************************************************************** 1711 * QueryWorkingSetEx (kernelbase.@) 1712 * K32QueryWorkingSetEx (kernelbase.@) 1713 */ 1714BOOL WINAPI QueryWorkingSetEx( HANDLE process, void *buffer, DWORD size ) 1715{ 1716 TRACE( "(%p, %p, %ld)\n", process, buffer, size ); 1717 return set_ntstatus( NtQueryVirtualMemory( process, NULL, MemoryWorkingSetExInformation, 1718 buffer, size, NULL )); 1719} 1720 1721 1722/****************************************************************** 1723 * QueryFullProcessImageNameA (kernelbase.@) 1724 */ 1725BOOL WINAPI DECLSPEC_HOTPATCH QueryFullProcessImageNameA( HANDLE process, DWORD flags, 1726 char *name, DWORD *size ) 1727{ 1728 BOOL ret; 1729 DWORD sizeW = *size; 1730 WCHAR *nameW = HeapAlloc( GetProcessHeap(), 0, *size * sizeof(WCHAR) ); 1731 1732 ret = QueryFullProcessImageNameW( process, flags, nameW, &sizeW ); 1733 if (ret) ret = (WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, *size, NULL, NULL) > 0); 1734 if (ret) *size = strlen( name ); 1735 HeapFree( GetProcessHeap(), 0, nameW ); 1736 return ret; 1737} 1738 1739 1740/****************************************************************** 1741 * QueryFullProcessImageNameW (kernelbase.@) 1742 */ 1743BOOL WINAPI DECLSPEC_HOTPATCH QueryFullProcessImageNameW( HANDLE process, DWORD flags, 1744 WCHAR *name, DWORD *size ) 1745{ 1746 BYTE buffer[sizeof(UNICODE_STRING) + MAX_PATH*sizeof(WCHAR)]; /* this buffer should be enough */ 1747 UNICODE_STRING *dynamic_buffer = NULL; 1748 UNICODE_STRING *result = NULL; 1749 NTSTATUS status; 1750 DWORD needed; 1751 1752 /* FIXME: Use ProcessImageFileName for the PROCESS_NAME_NATIVE case */ 1753 status = NtQueryInformationProcess( process, ProcessImageFileNameWin32, buffer, 1754 sizeof(buffer) - sizeof(WCHAR), &needed ); 1755 if (status == STATUS_INFO_LENGTH_MISMATCH) 1756 { 1757 dynamic_buffer = HeapAlloc( GetProcessHeap(), 0, needed + sizeof(WCHAR) ); 1758 status = NtQueryInformationProcess( process, ProcessImageFileNameWin32, dynamic_buffer, 1759 needed, &needed ); 1760 result = dynamic_buffer; 1761 } 1762 else 1763 result = (UNICODE_STRING *)buffer; 1764 1765 if (status) goto cleanup; 1766 1767 if (flags & PROCESS_NAME_NATIVE && result->Length > 2 * sizeof(WCHAR)) 1768 { 1769 WCHAR drive[3]; 1770 WCHAR device[1024]; 1771 DWORD ntlen, devlen; 1772 1773 if (result->Buffer[1] != ':' || result->Buffer[0] < 'A' || result->Buffer[0] > 'Z') 1774 { 1775 /* We cannot convert it to an NT device path so fail */ 1776 status = STATUS_NO_SUCH_DEVICE; 1777 goto cleanup; 1778 } 1779 1780 /* Find this drive's NT device path */ 1781 drive[0] = result->Buffer[0]; 1782 drive[1] = ':'; 1783 drive[2] = 0; 1784 if (!QueryDosDeviceW(drive, device, ARRAY_SIZE(device))) 1785 { 1786 status = STATUS_NO_SUCH_DEVICE; 1787 goto cleanup; 1788 } 1789 1790 devlen = lstrlenW(device); 1791 ntlen = devlen + (result->Length/sizeof(WCHAR) - 2); 1792 if (ntlen + 1 > *size) 1793 { 1794 status = STATUS_BUFFER_TOO_SMALL; 1795 goto cleanup; 1796 } 1797 *size = ntlen; 1798 1799 memcpy( name, device, devlen * sizeof(*device) ); 1800 memcpy( name + devlen, result->Buffer + 2, result->Length - 2 * sizeof(WCHAR) ); 1801 name[*size] = 0; 1802 TRACE( "NT path: %s\n", debugstr_w(name) ); 1803 } 1804 else 1805 { 1806 if (result->Length/sizeof(WCHAR) + 1 > *size) 1807 { 1808 status = STATUS_BUFFER_TOO_SMALL; 1809 goto cleanup; 1810 } 1811 1812 *size = result->Length/sizeof(WCHAR); 1813 memcpy( name, result->Buffer, result->Length ); 1814 name[*size] = 0; 1815 } 1816 1817cleanup: 1818 HeapFree( GetProcessHeap(), 0, dynamic_buffer ); 1819 return set_ntstatus( status ); 1820}