2 * Win32 debugger functions
4 * Copyright (C) 1999 Alexandre Julliard
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.
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.
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
26 #define WIN32_NO_STATUS
33 #define PSAPI_VERSION 1 /* avoid K32 function remapping */
37 #include "wine/exception.h"
39 #include "kernelbase.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
43 WINE_DECLARE_DEBUG_CHANNEL(winedbg
);
45 typedef INT (WINAPI
*MessageBoxA_funcptr
)(HWND
,LPCSTR
,LPCSTR
,UINT
);
46 typedef INT (WINAPI
*MessageBoxW_funcptr
)(HWND
,LPCWSTR
,LPCWSTR
,UINT
);
48 static PTOP_LEVEL_EXCEPTION_FILTER top_filter
;
50 void *dummy
= RtlUnwind
; /* force importing RtlUnwind from ntdll */
52 /***********************************************************************
53 * CheckRemoteDebuggerPresent (kernelbase.@)
55 BOOL WINAPI DECLSPEC_HOTPATCH
CheckRemoteDebuggerPresent( HANDLE process
, BOOL
*present
)
59 if (!process
|| !present
)
61 SetLastError( ERROR_INVALID_PARAMETER
);
64 if (!set_ntstatus( NtQueryInformationProcess( process
, ProcessDebugPort
, &port
, sizeof(port
), NULL
)))
71 /**********************************************************************
72 * ContinueDebugEvent (kernelbase.@)
74 BOOL WINAPI DECLSPEC_HOTPATCH
ContinueDebugEvent( DWORD pid
, DWORD tid
, DWORD status
)
78 id
.UniqueProcess
= ULongToHandle( pid
);
79 id
.UniqueThread
= ULongToHandle( tid
);
80 return set_ntstatus( DbgUiContinue( &id
, status
));
84 /**********************************************************************
85 * DebugActiveProcess (kernelbase.@)
87 BOOL WINAPI DECLSPEC_HOTPATCH
DebugActiveProcess( DWORD pid
)
92 if (!set_ntstatus( DbgUiConnectToDbg() )) return FALSE
;
93 if (!(process
= OpenProcess( PROCESS_VM_READ
| PROCESS_VM_WRITE
| PROCESS_SUSPEND_RESUME
|
94 PROCESS_CREATE_THREAD
, FALSE
, pid
)))
96 status
= DbgUiDebugActiveProcess( process
);
98 return set_ntstatus( status
);
102 /**********************************************************************
103 * DebugActiveProcessStop (kernelbase.@)
105 BOOL WINAPI DECLSPEC_HOTPATCH
DebugActiveProcessStop( DWORD pid
)
110 if (!(process
= OpenProcess( PROCESS_VM_READ
| PROCESS_VM_WRITE
| PROCESS_SUSPEND_RESUME
, FALSE
, pid
)))
112 status
= DbgUiStopDebugging( process
);
114 return set_ntstatus( status
);
118 /***********************************************************************
119 * DebugBreak (kernelbase.@)
121 #if defined(__i386__) || defined(__x86_64__)
122 __ASM_STDCALL_FUNC( DebugBreak
, 0, "jmp " __ASM_STDCALL("DbgBreakPoint", 0) )
124 void WINAPI
DebugBreak(void)
131 /**************************************************************************
132 * FatalAppExitA (kernelbase.@)
134 void WINAPI DECLSPEC_HOTPATCH
FatalAppExitA( UINT action
, LPCSTR str
)
136 HMODULE mod
= GetModuleHandleA( "user32.dll" );
137 MessageBoxA_funcptr pMessageBoxA
= NULL
;
139 if (mod
) pMessageBoxA
= (MessageBoxA_funcptr
)GetProcAddress( mod
, "MessageBoxA" );
140 if (pMessageBoxA
) pMessageBoxA( 0, str
, NULL
, MB_SYSTEMMODAL
| MB_OK
);
141 else ERR( "%s\n", debugstr_a(str
) );
142 RtlExitUserProcess( 1 );
146 /**************************************************************************
147 * FatalAppExitW (kernelbase.@)
149 void WINAPI DECLSPEC_HOTPATCH
FatalAppExitW( UINT action
, LPCWSTR str
)
151 HMODULE mod
= GetModuleHandleW( L
"user32.dll" );
152 MessageBoxW_funcptr pMessageBoxW
= NULL
;
154 if (mod
) pMessageBoxW
= (MessageBoxW_funcptr
)GetProcAddress( mod
, "MessageBoxW" );
155 if (pMessageBoxW
) pMessageBoxW( 0, str
, NULL
, MB_SYSTEMMODAL
| MB_OK
);
156 else ERR( "%s\n", debugstr_w(str
) );
157 RtlExitUserProcess( 1 );
161 /***********************************************************************
162 * IsDebuggerPresent (kernelbase.@)
164 BOOL WINAPI
IsDebuggerPresent(void)
166 return NtCurrentTeb()->Peb
->BeingDebugged
;
170 static LONG WINAPI
debug_exception_handler( EXCEPTION_POINTERS
*eptr
)
172 EXCEPTION_RECORD
*rec
= eptr
->ExceptionRecord
;
173 return (rec
->ExceptionCode
== DBG_PRINTEXCEPTION_C
) ? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
;
176 /***********************************************************************
177 * OutputDebugStringA (kernelbase.@)
179 void WINAPI DECLSPEC_HOTPATCH
OutputDebugStringA( LPCSTR str
)
181 static HANDLE DBWinMutex
= NULL
;
182 static BOOL mutex_inited
= FALSE
;
183 BOOL caught_by_dbg
= TRUE
;
186 WARN( "%s\n", debugstr_a(str
) );
188 /* raise exception, WaitForDebugEvent() will generate a corresponding debug event */
192 args
[0] = strlen(str
) + 1;
193 args
[1] = (ULONG_PTR
)str
;
194 RaiseException( DBG_PRINTEXCEPTION_C
, 0, 2, args
);
196 __EXCEPT(debug_exception_handler
)
198 caught_by_dbg
= FALSE
;
201 if (caught_by_dbg
) return;
203 /* send string to a system-wide monitor */
206 /* first call to OutputDebugString, initialize mutex handle */
207 HANDLE mutex
= CreateMutexExW( NULL
, L
"DBWinMutex", 0, SYNCHRONIZE
);
210 if (InterlockedCompareExchangePointer( &DBWinMutex
, mutex
, 0 ) != 0)
211 /* someone beat us here... */
212 CloseHandle( mutex
);
221 mapping
= OpenFileMappingW( FILE_MAP_WRITE
, FALSE
, L
"DBWIN_BUFFER" );
225 HANDLE eventbuffer
, eventdata
;
227 buffer
= MapViewOfFile( mapping
, FILE_MAP_WRITE
, 0, 0, 0 );
228 eventbuffer
= OpenEventW( SYNCHRONIZE
, FALSE
, L
"DBWIN_BUFFER_READY" );
229 eventdata
= OpenEventW( EVENT_MODIFY_STATE
, FALSE
, L
"DBWIN_DATA_READY" );
231 if (buffer
&& eventbuffer
&& eventdata
)
233 /* monitor is present, synchronize with other OutputDebugString invocations */
234 WaitForSingleObject( DBWinMutex
, INFINITE
);
236 /* acquire control over the buffer */
237 if (WaitForSingleObject( eventbuffer
, 10000 ) == WAIT_OBJECT_0
)
239 int str_len
= strlen( str
);
244 } *mon_buffer
= (struct _mon_buffer_t
*) buffer
;
246 if (str_len
> (4096 - sizeof(DWORD
) - 1)) str_len
= 4096 - sizeof(DWORD
) - 1;
247 mon_buffer
->pid
= GetCurrentProcessId();
248 memcpy( mon_buffer
->buffer
, str
, str_len
);
249 mon_buffer
->buffer
[str_len
] = 0;
251 /* signal data ready */
252 SetEvent( eventdata
);
254 ReleaseMutex( DBWinMutex
);
257 if (buffer
) UnmapViewOfFile( buffer
);
258 if (eventbuffer
) CloseHandle( eventbuffer
);
259 if (eventdata
) CloseHandle( eventdata
);
260 CloseHandle( mapping
);
266 /***********************************************************************
267 * OutputDebugStringW (kernelbase.@)
269 void WINAPI DECLSPEC_HOTPATCH
OutputDebugStringW( LPCWSTR str
)
274 RtlInitUnicodeString( &strW
, str
);
275 if (!RtlUnicodeStringToAnsiString( &strA
, &strW
, TRUE
))
277 OutputDebugStringA( strA
.Buffer
);
278 RtlFreeAnsiString( &strA
);
283 /*******************************************************************
284 * RaiseException (kernelbase.@)
286 void WINAPI DECLSPEC_HOTPATCH
RaiseException( DWORD code
, DWORD flags
, DWORD count
, const ULONG_PTR
*args
)
288 EXCEPTION_RECORD record
;
290 record
.ExceptionCode
= code
;
291 record
.ExceptionFlags
= flags
& EH_NONCONTINUABLE
;
292 record
.ExceptionRecord
= NULL
;
293 record
.ExceptionAddress
= RaiseException
;
296 if (count
> EXCEPTION_MAXIMUM_PARAMETERS
) count
= EXCEPTION_MAXIMUM_PARAMETERS
;
297 record
.NumberParameters
= count
;
298 memcpy( record
.ExceptionInformation
, args
, count
* sizeof(*args
) );
300 else record
.NumberParameters
= 0;
302 RtlRaiseException( &record
);
304 __ASM_STDCALL_IMPORT(RaiseException
,16)
307 /***********************************************************************
308 * SetUnhandledExceptionFilter (kernelbase.@)
310 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI DECLSPEC_HOTPATCH
SetUnhandledExceptionFilter(
311 LPTOP_LEVEL_EXCEPTION_FILTER filter
)
313 return InterlockedExchangePointer( (void **)&top_filter
, filter
);
317 /*******************************************************************
318 * format_exception_msg
320 static void format_exception_msg( const EXCEPTION_POINTERS
*ptr
, char *buffer
, int size
)
322 const EXCEPTION_RECORD
*rec
= ptr
->ExceptionRecord
;
325 switch(rec
->ExceptionCode
)
327 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
328 len
= snprintf( buffer
, size
, "Unhandled division by zero" );
330 case EXCEPTION_INT_OVERFLOW
:
331 len
= snprintf( buffer
, size
, "Unhandled overflow" );
333 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
334 len
= snprintf( buffer
, size
, "Unhandled array bounds" );
336 case EXCEPTION_ILLEGAL_INSTRUCTION
:
337 len
= snprintf( buffer
, size
, "Unhandled illegal instruction" );
339 case EXCEPTION_STACK_OVERFLOW
:
340 len
= snprintf( buffer
, size
, "Unhandled stack overflow" );
342 case EXCEPTION_PRIV_INSTRUCTION
:
343 len
= snprintf( buffer
, size
, "Unhandled privileged instruction" );
345 case EXCEPTION_ACCESS_VIOLATION
:
346 if (rec
->NumberParameters
== 2)
347 len
= snprintf( buffer
, size
, "Unhandled page fault on %s access to %p",
348 rec
->ExceptionInformation
[0] == EXCEPTION_WRITE_FAULT
? "write" :
349 rec
->ExceptionInformation
[0] == EXCEPTION_EXECUTE_FAULT
? "execute" : "read",
350 (void *)rec
->ExceptionInformation
[1]);
352 len
= snprintf( buffer
, size
, "Unhandled page fault");
354 case EXCEPTION_DATATYPE_MISALIGNMENT
:
355 len
= snprintf( buffer
, size
, "Unhandled alignment" );
358 len
= snprintf( buffer
, size
, "Unhandled ^C");
360 case STATUS_POSSIBLE_DEADLOCK
:
361 len
= snprintf( buffer
, size
, "Critical section %p wait failed",
362 (void *)rec
->ExceptionInformation
[0]);
364 case EXCEPTION_WINE_STUB
:
365 if ((ULONG_PTR
)rec
->ExceptionInformation
[1] >> 16)
366 len
= snprintf( buffer
, size
, "Unimplemented function %s.%s called",
367 (char *)rec
->ExceptionInformation
[0], (char *)rec
->ExceptionInformation
[1] );
369 len
= snprintf( buffer
, size
, "Unimplemented function %s.%ld called",
370 (char *)rec
->ExceptionInformation
[0], rec
->ExceptionInformation
[1] );
372 case EXCEPTION_WINE_ASSERTION
:
373 len
= snprintf( buffer
, size
, "Assertion failed" );
376 len
= snprintf( buffer
, size
, "Unhandled exception 0x%08x in thread %x",
377 rec
->ExceptionCode
, GetCurrentThreadId());
380 if (len
< 0 || len
>= size
) return;
381 snprintf( buffer
+ len
, size
- len
, " at address %p", ptr
->ExceptionRecord
->ExceptionAddress
);
385 /******************************************************************
388 * Does the effective debugger startup according to 'format'
390 static BOOL
start_debugger( EXCEPTION_POINTERS
*epointers
, HANDLE event
)
392 OBJECT_ATTRIBUTES attr
;
393 UNICODE_STRING nameW
;
394 WCHAR
*cmdline
, *env
, *p
, *format
= NULL
;
396 DWORD autostart
= TRUE
;
397 PROCESS_INFORMATION info
;
398 STARTUPINFOW startup
;
402 format_exception_msg( epointers
, buffer
, sizeof(buffer
) );
403 MESSAGE( "wine: %s (thread %04x), starting debugger...\n", buffer
, GetCurrentThreadId() );
405 attr
.Length
= sizeof(attr
);
406 attr
.RootDirectory
= 0;
407 attr
.ObjectName
= &nameW
;
409 attr
.SecurityDescriptor
= NULL
;
410 attr
.SecurityQualityOfService
= NULL
;
411 RtlInitUnicodeString( &nameW
, L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" );
413 if (!NtOpenKey( &dbg_key
, KEY_READ
, &attr
))
415 KEY_VALUE_PARTIAL_INFORMATION
*info
;
416 DWORD format_size
= 0;
418 RtlInitUnicodeString( &nameW
, L
"Debugger" );
419 if (NtQueryValueKey( dbg_key
, &nameW
, KeyValuePartialInformation
,
420 NULL
, 0, &format_size
) == STATUS_BUFFER_TOO_SMALL
)
422 char *data
= HeapAlloc( GetProcessHeap(), 0, format_size
);
423 NtQueryValueKey( dbg_key
, &nameW
, KeyValuePartialInformation
,
424 data
, format_size
, &format_size
);
425 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)data
;
426 format
= HeapAlloc( GetProcessHeap(), 0, info
->DataLength
+ sizeof(WCHAR
) );
427 memcpy( format
, info
->Data
, info
->DataLength
);
428 format
[info
->DataLength
/ sizeof(WCHAR
)] = 0;
430 if (info
->Type
== REG_EXPAND_SZ
)
434 format_size
= ExpandEnvironmentStringsW( format
, NULL
, 0 );
435 tmp
= HeapAlloc( GetProcessHeap(), 0, format_size
* sizeof(WCHAR
));
436 ExpandEnvironmentStringsW( format
, tmp
, format_size
);
437 HeapFree( GetProcessHeap(), 0, format
);
440 HeapFree( GetProcessHeap(), 0, data
);
443 RtlInitUnicodeString( &nameW
, L
"Auto" );
444 if (!NtQueryValueKey( dbg_key
, &nameW
, KeyValuePartialInformation
,
445 buffer
, sizeof(buffer
)-sizeof(WCHAR
), &format_size
))
447 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
448 if (info
->Type
== REG_DWORD
) memcpy( &autostart
, info
->Data
, sizeof(DWORD
) );
449 else if (info
->Type
== REG_SZ
)
451 WCHAR
*str
= (WCHAR
*)info
->Data
;
452 str
[info
->DataLength
/sizeof(WCHAR
)] = 0;
453 autostart
= wcstol( str
, NULL
, 10 );
462 size_t format_size
= lstrlenW( format
) + 2*20;
463 cmdline
= HeapAlloc( GetProcessHeap(), 0, format_size
* sizeof(WCHAR
) );
464 swprintf( cmdline
, format_size
, format
, (long)GetCurrentProcessId(), (long)HandleToLong(event
) );
465 HeapFree( GetProcessHeap(), 0, format
);
469 cmdline
= HeapAlloc( GetProcessHeap(), 0, 80 * sizeof(WCHAR
) );
470 swprintf( cmdline
, 80, L
"winedbg --auto %ld %ld", (long)GetCurrentProcessId(), (long)HandleToLong(event
) );
475 HMODULE mod
= GetModuleHandleA( "user32.dll" );
476 MessageBoxA_funcptr pMessageBoxA
= NULL
;
478 if (mod
) pMessageBoxA
= (void *)GetProcAddress( mod
, "MessageBoxA" );
481 static const char msg
[] = ".\nDo you wish to debug it?";
483 format_exception_msg( epointers
, buffer
, sizeof(buffer
) - sizeof(msg
) );
484 strcat( buffer
, msg
);
485 if (pMessageBoxA( 0, buffer
, "Exception raised", MB_YESNO
| MB_ICONHAND
) == IDNO
)
487 TRACE( "Killing process\n" );
493 /* make WINEDEBUG empty in the environment */
494 env
= GetEnvironmentStringsW();
495 if (!TRACE_ON(winedbg
))
497 for (p
= env
; *p
; p
+= lstrlenW(p
) + 1)
499 if (!wcsncmp( p
, L
"WINEDEBUG=", 10 ))
501 WCHAR
*next
= p
+ lstrlenW(p
);
502 WCHAR
*end
= next
+ 1;
503 while (*end
) end
+= lstrlenW(end
) + 1;
504 memmove( p
+ 10, next
, end
+ 1 - next
);
510 TRACE( "Starting debugger %s\n", debugstr_w(cmdline
) );
511 memset( &startup
, 0, sizeof(startup
) );
512 startup
.cb
= sizeof(startup
);
513 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
514 startup
.wShowWindow
= SW_SHOWNORMAL
;
515 ret
= CreateProcessW( NULL
, cmdline
, NULL
, NULL
, TRUE
, 0, env
, NULL
, &startup
, &info
);
516 FreeEnvironmentStringsW( env
);
520 /* wait for debugger to come up... */
522 CloseHandle( info
.hThread
);
524 handles
[1] = info
.hProcess
;
525 WaitForMultipleObjects( 2, handles
, FALSE
, INFINITE
);
526 CloseHandle( info
.hProcess
);
528 else ERR( "Couldn't start debugger %s (%d)\n"
529 "Read the Wine Developers Guide on how to set up winedbg or another debugger\n",
530 debugstr_w(cmdline
), GetLastError() );
532 HeapFree(GetProcessHeap(), 0, cmdline
);
536 /******************************************************************
537 * start_debugger_atomic
539 * starts the debugger in an atomic way:
540 * - either the debugger is not started and it is started
541 * - or the debugger has already been started by another thread
542 * - or the debugger couldn't be started
544 * returns TRUE for the two first conditions, FALSE for the last
546 static BOOL
start_debugger_atomic( EXCEPTION_POINTERS
*epointers
)
552 OBJECT_ATTRIBUTES attr
;
555 attr
.Length
= sizeof(attr
);
556 attr
.RootDirectory
= 0;
557 attr
.Attributes
= OBJ_INHERIT
;
558 attr
.ObjectName
= NULL
;
559 attr
.SecurityDescriptor
= NULL
;
560 attr
.SecurityQualityOfService
= NULL
;
562 /* ask for manual reset, so that once the debugger is started,
563 * every thread will know it */
564 NtCreateEvent( &event
, EVENT_ALL_ACCESS
, &attr
, NotificationEvent
, FALSE
);
565 if (InterlockedCompareExchangePointer( &once
, event
, 0 ) == 0)
567 /* ok, our event has been set... we're the winning thread */
568 BOOL ret
= start_debugger( epointers
, once
);
572 /* so that the other threads won't be stuck */
573 NtSetEvent( once
, NULL
);
578 /* someone beat us here... */
579 CloseHandle( event
);
582 /* and wait for the winner to have actually created the debugger */
583 WaitForSingleObject( once
, INFINITE
);
584 /* in fact, here, we only know that someone has tried to start the debugger,
585 * we'll know by reposting the exception if it has actually attached
586 * to the current process */
591 /*******************************************************************
592 * check_resource_write
594 * Check if the exception is a write attempt to the resource data.
595 * If yes, we unprotect the resources to let broken apps continue
596 * (Windows does this too).
598 static BOOL
check_resource_write( void *addr
)
603 MEMORY_BASIC_INFORMATION info
;
605 if (!VirtualQuery( addr
, &info
, sizeof(info
) )) return FALSE
;
606 if (info
.State
== MEM_FREE
|| !(info
.Type
& MEM_IMAGE
)) return FALSE
;
607 if (!(rsrc
= RtlImageDirectoryEntryToData( info
.AllocationBase
, TRUE
,
608 IMAGE_DIRECTORY_ENTRY_RESOURCE
, &size
)))
610 if (addr
< rsrc
|| (char *)addr
>= (char *)rsrc
+ size
) return FALSE
;
611 TRACE( "Broken app is writing to the resource data, enabling work-around\n" );
612 VirtualProtect( rsrc
, size
, PAGE_READWRITE
, &old_prot
);
617 /*******************************************************************
618 * UnhandledExceptionFilter (kernelbase.@)
620 LONG WINAPI
UnhandledExceptionFilter( EXCEPTION_POINTERS
*epointers
)
622 const EXCEPTION_RECORD
*rec
= epointers
->ExceptionRecord
;
624 if (rec
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
&& rec
->NumberParameters
>= 2)
626 switch (rec
->ExceptionInformation
[0])
628 case EXCEPTION_WRITE_FAULT
:
629 if (check_resource_write( (void *)rec
->ExceptionInformation
[1] ))
630 return EXCEPTION_CONTINUE_EXECUTION
;
635 if (!NtCurrentTeb()->Peb
->BeingDebugged
)
637 if (rec
->ExceptionCode
== CONTROL_C_EXIT
)
639 /* do not launch the debugger on ^C, simply terminate the process */
640 TerminateProcess( GetCurrentProcess(), 1 );
645 LONG ret
= top_filter( epointers
);
646 if (ret
!= EXCEPTION_CONTINUE_SEARCH
) return ret
;
649 /* FIXME: Should check the current error mode */
651 if (!start_debugger_atomic( epointers
) || !NtCurrentTeb()->Peb
->BeingDebugged
)
652 return EXCEPTION_EXECUTE_HANDLER
;
654 return EXCEPTION_CONTINUE_SEARCH
;
658 /***********************************************************************
659 * WerGetFlags (kernelbase.@)
661 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerGetFlags( HANDLE process
, DWORD
*flags
)
663 FIXME( "(%p, %p) stub\n", process
, flags
);
668 /***********************************************************************
669 * WerRegisterFile (kernelbase.@)
671 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerRegisterFile( const WCHAR
*file
, WER_REGISTER_FILE_TYPE type
,
674 FIXME( "(%s, %d, %d) stub\n", debugstr_w(file
), type
, flags
);
679 /***********************************************************************
680 * WerRegisterMemoryBlock (kernelbase.@)
682 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerRegisterMemoryBlock( void *block
, DWORD size
)
684 FIXME( "(%p %d) stub\n", block
, size
);
689 /***********************************************************************
690 * WerRegisterRuntimeExceptionModule (kernelbase.@)
692 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerRegisterRuntimeExceptionModule( const WCHAR
*dll
, void *context
)
694 FIXME( "(%s, %p) stub\n", debugstr_w(dll
), context
);
699 /***********************************************************************
700 * WerSetFlags (kernelbase.@)
702 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerSetFlags( DWORD flags
)
704 FIXME("(%d) stub\n", flags
);
709 /***********************************************************************
710 * WerUnregisterFile (kernelbase.@)
712 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerUnregisterFile( const WCHAR
*file
)
714 FIXME( "(%s) stub\n", debugstr_w(file
) );
719 /***********************************************************************
720 * WerUnregisterMemoryBlock (kernelbase.@)
722 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerUnregisterMemoryBlock( void *block
)
724 FIXME( "(%p) stub\n", block
);
729 /***********************************************************************
730 * WerUnregisterRuntimeExceptionModule (kernelbase.@)
732 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerUnregisterRuntimeExceptionModule( const WCHAR
*dll
, void *context
)
734 FIXME( "(%s, %p) stub\n", debugstr_w(dll
), context
);
739 /***********************************************************************
741 ***********************************************************************/
744 typedef struct _PEB32
746 BOOLEAN InheritedAddressSpace
;
747 BOOLEAN ReadImageFileExecOptions
;
748 BOOLEAN BeingDebugged
;
751 DWORD ImageBaseAddress
;
755 typedef struct _LIST_ENTRY32
761 typedef struct _PEB_LDR_DATA32
766 LIST_ENTRY32 InLoadOrderModuleList
;
769 typedef struct _UNICODE_STRING32
772 USHORT MaximumLength
;
776 typedef struct _LDR_DATA_TABLE_ENTRY32
778 LIST_ENTRY32 InLoadOrderModuleList
;
779 LIST_ENTRY32 InMemoryOrderModuleList
;
780 LIST_ENTRY32 InInitializationOrderModuleList
;
784 UNICODE_STRING32 FullDllName
;
785 UNICODE_STRING32 BaseDllName
;
786 } LDR_DATA_TABLE_ENTRY32
;
788 struct module_iterator
794 LDR_DATA_TABLE_ENTRY ldr_module
;
795 LDR_DATA_TABLE_ENTRY32 ldr_module32
;
799 static BOOL
init_module_iterator( struct module_iterator
*iter
, HANDLE process
)
801 PROCESS_BASIC_INFORMATION pbi
;
802 PPEB_LDR_DATA ldr_data
;
804 if (!IsWow64Process( process
, &iter
->wow64
)) return FALSE
;
806 /* get address of PEB */
807 if (!set_ntstatus( NtQueryInformationProcess( process
, ProcessBasicInformation
,
808 &pbi
, sizeof(pbi
), NULL
)))
811 if (is_win64
&& iter
->wow64
)
813 PEB_LDR_DATA32
*ldr_data32_ptr
;
814 DWORD ldr_data32
, first_module
;
817 peb32
= (PEB32
*)(DWORD_PTR
)pbi
.PebBaseAddress
;
818 if (!ReadProcessMemory( process
, &peb32
->LdrData
, &ldr_data32
, sizeof(ldr_data32
), NULL
))
820 ldr_data32_ptr
= (PEB_LDR_DATA32
*)(DWORD_PTR
) ldr_data32
;
821 if (!ReadProcessMemory( process
, &ldr_data32_ptr
->InLoadOrderModuleList
.Flink
,
822 &first_module
, sizeof(first_module
), NULL
))
824 iter
->head
= (LIST_ENTRY
*)&ldr_data32_ptr
->InLoadOrderModuleList
;
825 iter
->current
= (LIST_ENTRY
*)(DWORD_PTR
)first_module
;
826 iter
->process
= process
;
830 /* read address of LdrData from PEB */
831 if (!ReadProcessMemory( process
, &pbi
.PebBaseAddress
->LdrData
, &ldr_data
, sizeof(ldr_data
), NULL
))
834 /* read address of first module from LdrData */
835 if (!ReadProcessMemory( process
, &ldr_data
->InLoadOrderModuleList
.Flink
,
836 &iter
->current
, sizeof(iter
->current
), NULL
))
839 iter
->head
= &ldr_data
->InLoadOrderModuleList
;
840 iter
->process
= process
;
845 static int module_iterator_next( struct module_iterator
*iter
)
847 if (iter
->current
== iter
->head
) return 0;
849 if (is_win64
&& iter
->wow64
)
851 LIST_ENTRY32
*entry32
= (LIST_ENTRY32
*)iter
->current
;
853 if (!ReadProcessMemory( iter
->process
,
854 CONTAINING_RECORD(entry32
, LDR_DATA_TABLE_ENTRY32
, InLoadOrderModuleList
),
855 &iter
->ldr_module32
, sizeof(iter
->ldr_module32
), NULL
))
857 iter
->current
= (LIST_ENTRY
*)(DWORD_PTR
)iter
->ldr_module32
.InLoadOrderModuleList
.Flink
;
861 if (!ReadProcessMemory( iter
->process
,
862 CONTAINING_RECORD(iter
->current
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
),
863 &iter
->ldr_module
, sizeof(iter
->ldr_module
), NULL
))
866 iter
->current
= iter
->ldr_module
.InLoadOrderLinks
.Flink
;
871 static BOOL
get_ldr_module( HANDLE process
, HMODULE module
, LDR_DATA_TABLE_ENTRY
*ldr_module
)
873 struct module_iterator iter
;
876 if (!init_module_iterator( &iter
, process
)) return FALSE
;
878 while ((ret
= module_iterator_next( &iter
)) > 0)
879 /* When hModule is NULL we return the process image - which will be
880 * the first module since our iterator uses InLoadOrderModuleList */
881 if (!module
|| module
== iter
.ldr_module
.DllBase
)
883 *ldr_module
= iter
.ldr_module
;
887 if (ret
== 0) SetLastError( ERROR_INVALID_HANDLE
);
892 static BOOL
get_ldr_module32( HANDLE process
, HMODULE module
, LDR_DATA_TABLE_ENTRY32
*ldr_module
)
894 struct module_iterator iter
;
897 if (!init_module_iterator( &iter
, process
)) return FALSE
;
899 while ((ret
= module_iterator_next( &iter
)) > 0)
900 /* When hModule is NULL we return the process image - which will be
901 * the first module since our iterator uses InLoadOrderModuleList */
902 if (!module
|| (DWORD
)(DWORD_PTR
)module
== iter
.ldr_module32
.BaseAddress
)
904 *ldr_module
= iter
.ldr_module32
;
908 if (ret
== 0) SetLastError( ERROR_INVALID_HANDLE
);
913 /***********************************************************************
914 * EmptyWorkingSet (kernelbase.@)
915 * K32EmptyWorkingSet (kernelbase.@)
917 BOOL WINAPI DECLSPEC_HOTPATCH
EmptyWorkingSet( HANDLE process
)
919 return SetProcessWorkingSetSizeEx( process
, (SIZE_T
)-1, (SIZE_T
)-1, 0 );
923 /***********************************************************************
924 * EnumDeviceDrivers (kernelbase.@)
925 * K32EnumDeviceDrivers (kernelbase.@)
927 BOOL WINAPI
EnumDeviceDrivers( void **image_base
, DWORD count
, DWORD
*needed
)
929 FIXME( "(%p, %d, %p): stub\n", image_base
, count
, needed
);
930 if (needed
) *needed
= 0;
935 /***********************************************************************
936 * EnumPageFilesA (kernelbase.@)
937 * K32EnumPageFilesA (kernelbase.@)
939 BOOL WINAPI
/* DECLSPEC_HOTPATCH */ EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback
, void *context
)
941 FIXME( "(%p, %p) stub\n", callback
, context
);
946 /***********************************************************************
947 * EnumPageFilesW (kernelbase.@)
948 * K32EnumPageFilesW (kernelbase.@)
950 BOOL WINAPI
/* DECLSPEC_HOTPATCH */ EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback
, void *context
)
952 FIXME( "(%p, %p) stub\n", callback
, context
);
957 /***********************************************************************
958 * EnumProcessModules (kernelbase.@)
959 * K32EnumProcessModules (kernelbase.@)
961 BOOL WINAPI DECLSPEC_HOTPATCH
EnumProcessModules( HANDLE process
, HMODULE
*module
,
962 DWORD count
, DWORD
*needed
)
964 struct module_iterator iter
;
968 if (process
== GetCurrentProcess())
970 PPEB_LDR_DATA ldr_data
= NtCurrentTeb()->Peb
->LdrData
;
971 PLIST_ENTRY head
= &ldr_data
->InLoadOrderModuleList
;
972 PLIST_ENTRY entry
= head
->Flink
;
974 if (count
&& !module
)
976 SetLastError( ERROR_NOACCESS
);
979 while (entry
!= head
)
981 LDR_DATA_TABLE_ENTRY
*ldr
= CONTAINING_RECORD( entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
982 if (count
>= sizeof(HMODULE
))
984 *module
++ = ldr
->DllBase
;
985 count
-= sizeof(HMODULE
);
987 size
+= sizeof(HMODULE
);
988 entry
= entry
->Flink
;
992 SetLastError( ERROR_NOACCESS
);
999 if (!init_module_iterator( &iter
, process
)) return FALSE
;
1001 if (count
&& !module
)
1003 SetLastError( ERROR_NOACCESS
);
1007 while ((ret
= module_iterator_next( &iter
)) > 0)
1009 if (count
>= sizeof(HMODULE
))
1011 if (sizeof(void *) == 8 && iter
.wow64
)
1012 *module
++ = (HMODULE
) (DWORD_PTR
)iter
.ldr_module32
.BaseAddress
;
1014 *module
++ = iter
.ldr_module
.DllBase
;
1015 count
-= sizeof(HMODULE
);
1017 size
+= sizeof(HMODULE
);
1022 SetLastError( ERROR_NOACCESS
);
1030 /***********************************************************************
1031 * EnumProcessModulesEx (kernelbase.@)
1032 * K32EnumProcessModulesEx (kernelbase.@)
1034 BOOL WINAPI
EnumProcessModulesEx( HANDLE process
, HMODULE
*module
, DWORD count
,
1035 DWORD
*needed
, DWORD filter
)
1037 FIXME( "(%p, %p, %d, %p, %d) semi-stub\n", process
, module
, count
, needed
, filter
);
1038 return EnumProcessModules( process
, module
, count
, needed
);
1042 /***********************************************************************
1043 * EnumProcesses (kernelbase.@)
1044 * K32EnumProcesses (kernelbase.@)
1046 BOOL WINAPI
EnumProcesses( DWORD
*ids
, DWORD count
, DWORD
*used
)
1048 SYSTEM_PROCESS_INFORMATION
*spi
;
1049 ULONG size
= 0x4000;
1056 HeapFree( GetProcessHeap(), 0, buf
);
1057 if (!(buf
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
1058 status
= NtQuerySystemInformation( SystemProcessInformation
, buf
, size
, NULL
);
1059 } while (status
== STATUS_INFO_LENGTH_MISMATCH
);
1061 if (!set_ntstatus( status
))
1063 HeapFree( GetProcessHeap(), 0, buf
);
1067 for (*used
= 0; count
>= sizeof(DWORD
); count
-= sizeof(DWORD
))
1069 *ids
++ = HandleToUlong( spi
->UniqueProcessId
);
1070 *used
+= sizeof(DWORD
);
1071 if (spi
->NextEntryOffset
== 0) break;
1072 spi
= (SYSTEM_PROCESS_INFORMATION
*)(((PCHAR
)spi
) + spi
->NextEntryOffset
);
1074 HeapFree( GetProcessHeap(), 0, buf
);
1079 /***********************************************************************
1080 * GetDeviceDriverBaseNameA (kernelbase.@)
1081 * K32GetDeviceDriverBaseNameA (kernelbase.@)
1083 DWORD WINAPI DECLSPEC_HOTPATCH
GetDeviceDriverBaseNameA( void *image_base
, char *name
, DWORD size
)
1085 FIXME( "(%p, %p, %d): stub\n", image_base
, name
, size
);
1086 if (name
&& size
) name
[0] = 0;
1091 /***********************************************************************
1092 * GetDeviceDriverBaseNameW (kernelbase.@)
1093 * K32GetDeviceDriverBaseNameW (kernelbase.@)
1095 DWORD WINAPI DECLSPEC_HOTPATCH
GetDeviceDriverBaseNameW( void *image_base
, WCHAR
*name
, DWORD size
)
1097 FIXME( "(%p, %p, %d): stub\n", image_base
, name
, size
);
1098 if (name
&& size
) name
[0] = 0;
1103 /***********************************************************************
1104 * GetDeviceDriverFileNameA (kernelbase.@)
1105 * K32GetDeviceDriverFileNameA (kernelbase.@)
1107 DWORD WINAPI DECLSPEC_HOTPATCH
GetDeviceDriverFileNameA( void *image_base
, char *name
, DWORD size
)
1109 FIXME( "(%p, %p, %d): stub\n", image_base
, name
, size
);
1110 if (name
&& size
) name
[0] = 0;
1115 /***********************************************************************
1116 * GetDeviceDriverFileNameW (kernelbase.@)
1117 * K32GetDeviceDriverFileNameW (kernelbase.@)
1119 DWORD WINAPI DECLSPEC_HOTPATCH
GetDeviceDriverFileNameW( void *image_base
, WCHAR
*name
, DWORD size
)
1121 FIXME( "(%p, %p, %d): stub\n", image_base
, name
, size
);
1122 if (name
&& size
) name
[0] = 0;
1127 /***********************************************************************
1128 * GetMappedFileNameA (kernelbase.@)
1129 * K32GetMappedFileNameA (kernelbase.@)
1131 DWORD WINAPI DECLSPEC_HOTPATCH
GetMappedFileNameA( HANDLE process
, void *addr
, char *name
, DWORD size
)
1133 WCHAR nameW
[MAX_PATH
];
1138 SetLastError( ERROR_INVALID_PARAMETER
);
1141 if (!GetMappedFileNameW( process
, addr
, nameW
, MAX_PATH
)) return 0;
1144 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1147 len
= file_name_WtoA( nameW
, wcslen(nameW
), name
, size
);
1148 name
[min(len
, size
- 1)] = 0;
1153 /***********************************************************************
1154 * GetMappedFileNameW (kernelbase.@)
1155 * K32GetMappedFileNameW (kernelbase.@)
1157 DWORD WINAPI DECLSPEC_HOTPATCH
GetMappedFileNameW( HANDLE process
, void *addr
, WCHAR
*name
, DWORD size
)
1159 ULONG_PTR buffer
[(sizeof(MEMORY_SECTION_NAME
) + MAX_PATH
* sizeof(WCHAR
)) / sizeof(ULONG_PTR
)];
1160 MEMORY_SECTION_NAME
*mem
= (MEMORY_SECTION_NAME
*)buffer
;
1165 SetLastError( ERROR_INVALID_PARAMETER
);
1168 if (!set_ntstatus( NtQueryVirtualMemory( process
, addr
, MemorySectionName
, mem
, sizeof(buffer
), NULL
)))
1171 len
= mem
->SectionFileName
.Length
/ sizeof(WCHAR
);
1172 memcpy( name
, mem
->SectionFileName
.Buffer
, min( mem
->SectionFileName
.Length
, size
* sizeof(WCHAR
) ));
1173 if (len
>= size
) SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1174 name
[min(len
, size
- 1)] = 0;
1179 /***********************************************************************
1180 * GetModuleBaseNameA (kernelbase.@)
1181 * K32GetModuleBaseNameA (kernelbase.@)
1183 DWORD WINAPI DECLSPEC_HOTPATCH
GetModuleBaseNameA( HANDLE process
, HMODULE module
,
1184 char *name
, DWORD size
)
1191 SetLastError( ERROR_INVALID_PARAMETER
);
1194 if (!(name_w
= HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR
) * size
))) return 0;
1196 len
= GetModuleBaseNameW( process
, module
, name_w
, size
);
1197 TRACE( "%d, %s\n", len
, debugstr_w(name_w
) );
1200 ret
= WideCharToMultiByte( CP_ACP
, 0, name_w
, len
, name
, size
, NULL
, NULL
);
1201 if (ret
< size
) name
[ret
] = 0;
1203 HeapFree( GetProcessHeap(), 0, name_w
);
1208 /***********************************************************************
1209 * GetModuleBaseNameW (kernelbase.@)
1210 * K32GetModuleBaseNameW (kernelbase.@)
1212 DWORD WINAPI DECLSPEC_HOTPATCH
GetModuleBaseNameW( HANDLE process
, HMODULE module
,
1213 WCHAR
*name
, DWORD size
)
1217 if (!IsWow64Process( process
, &wow64
)) return 0;
1219 if (is_win64
&& wow64
)
1221 LDR_DATA_TABLE_ENTRY32 ldr_module32
;
1223 if (!get_ldr_module32(process
, module
, &ldr_module32
)) return 0;
1224 size
= min( ldr_module32
.BaseDllName
.Length
/ sizeof(WCHAR
), size
);
1225 if (!ReadProcessMemory( process
, (void *)(DWORD_PTR
)ldr_module32
.BaseDllName
.Buffer
,
1226 name
, size
* sizeof(WCHAR
), NULL
))
1231 LDR_DATA_TABLE_ENTRY ldr_module
;
1233 if (!get_ldr_module( process
, module
, &ldr_module
)) return 0;
1234 size
= min( ldr_module
.BaseDllName
.Length
/ sizeof(WCHAR
), size
);
1235 if (!ReadProcessMemory( process
, ldr_module
.BaseDllName
.Buffer
,
1236 name
, size
* sizeof(WCHAR
), NULL
))
1244 /***********************************************************************
1245 * GetModuleFileNameExA (kernelbase.@)
1246 * K32GetModuleFileNameExA (kernelbase.@)
1248 DWORD WINAPI DECLSPEC_HOTPATCH
GetModuleFileNameExA( HANDLE process
, HMODULE module
,
1249 char *name
, DWORD size
)
1254 TRACE( "(process=%p, module=%p, %p, %d)\n", process
, module
, name
, size
);
1258 SetLastError( ERROR_INVALID_PARAMETER
);
1261 if (process
== GetCurrentProcess())
1263 len
= GetModuleFileNameA( module
, name
, size
);
1264 name
[size
- 1] = '\0';
1268 if (!(ptr
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return 0;
1269 len
= GetModuleFileNameExW( process
, module
, ptr
, size
);
1276 if (!WideCharToMultiByte( CP_ACP
, 0, ptr
, -1, name
, size
, NULL
, NULL
))
1281 else if (len
< size
) len
= strlen( name
);
1283 HeapFree( GetProcessHeap(), 0, ptr
);
1288 /***********************************************************************
1289 * GetModuleFileNameExW (kernelbase.@)
1290 * K32GetModuleFileNameExW (kernelbase.@)
1292 DWORD WINAPI DECLSPEC_HOTPATCH
GetModuleFileNameExW( HANDLE process
, HMODULE module
,
1293 WCHAR
*name
, DWORD size
)
1298 if (!size
) return 0;
1300 if (!IsWow64Process( process
, &wow64
)) return 0;
1302 if (is_win64
&& wow64
)
1304 LDR_DATA_TABLE_ENTRY32 ldr_module32
;
1306 if (!get_ldr_module32( process
, module
, &ldr_module32
)) return 0;
1307 len
= ldr_module32
.FullDllName
.Length
/ sizeof(WCHAR
);
1308 if (!ReadProcessMemory( process
, (void *)(DWORD_PTR
)ldr_module32
.FullDllName
.Buffer
,
1309 name
, min( len
, size
) * sizeof(WCHAR
), NULL
))
1314 LDR_DATA_TABLE_ENTRY ldr_module
;
1316 if (!get_ldr_module(process
, module
, &ldr_module
)) return 0;
1317 len
= ldr_module
.FullDllName
.Length
/ sizeof(WCHAR
);
1318 if (!ReadProcessMemory( process
, ldr_module
.FullDllName
.Buffer
,
1319 name
, min( len
, size
) * sizeof(WCHAR
), NULL
))
1336 /***********************************************************************
1337 * GetModuleInformation (kernelbase.@)
1338 * K32GetModuleInformation (kernelbase.@)
1340 BOOL WINAPI
GetModuleInformation( HANDLE process
, HMODULE module
, MODULEINFO
*modinfo
, DWORD count
)
1344 if (count
< sizeof(MODULEINFO
))
1346 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1350 if (!IsWow64Process( process
, &wow64
)) return FALSE
;
1352 if (is_win64
&& wow64
)
1354 LDR_DATA_TABLE_ENTRY32 ldr_module32
;
1356 if (!get_ldr_module32( process
, module
, &ldr_module32
)) return FALSE
;
1357 modinfo
->lpBaseOfDll
= (void *)(DWORD_PTR
)ldr_module32
.BaseAddress
;
1358 modinfo
->SizeOfImage
= ldr_module32
.SizeOfImage
;
1359 modinfo
->EntryPoint
= (void *)(DWORD_PTR
)ldr_module32
.EntryPoint
;
1363 LDR_DATA_TABLE_ENTRY ldr_module
;
1365 if (!get_ldr_module( process
, module
, &ldr_module
)) return FALSE
;
1366 modinfo
->lpBaseOfDll
= ldr_module
.DllBase
;
1367 modinfo
->SizeOfImage
= ldr_module
.SizeOfImage
;
1368 modinfo
->EntryPoint
= ldr_module
.EntryPoint
;
1374 /***********************************************************************
1375 * GetPerformanceInfo (kernelbase.@)
1376 * K32GetPerformanceInfo (kernelbase.@)
1378 BOOL WINAPI DECLSPEC_HOTPATCH
GetPerformanceInfo( PPERFORMANCE_INFORMATION info
, DWORD size
)
1380 SYSTEM_PERFORMANCE_INFORMATION perf
;
1381 SYSTEM_BASIC_INFORMATION basic
;
1382 SYSTEM_PROCESS_INFORMATION
*process
, *spi
;
1386 TRACE( "(%p, %d)\n", info
, size
);
1388 if (size
< sizeof(*info
))
1390 SetLastError( ERROR_BAD_LENGTH
);
1394 status
= NtQuerySystemInformation( SystemPerformanceInformation
, &perf
, sizeof(perf
), NULL
);
1395 if (!set_ntstatus( status
)) return FALSE
;
1396 status
= NtQuerySystemInformation( SystemBasicInformation
, &basic
, sizeof(basic
), NULL
);
1397 if (!set_ntstatus( status
)) return FALSE
;
1399 info
->cb
= sizeof(*info
);
1400 info
->CommitTotal
= perf
.TotalCommittedPages
;
1401 info
->CommitLimit
= perf
.TotalCommitLimit
;
1402 info
->CommitPeak
= perf
.PeakCommitment
;
1403 info
->PhysicalTotal
= basic
.MmNumberOfPhysicalPages
;
1404 info
->PhysicalAvailable
= perf
.AvailablePages
;
1405 info
->SystemCache
= 0;
1406 info
->KernelTotal
= perf
.PagedPoolUsage
+ perf
.NonPagedPoolUsage
;
1407 info
->KernelPaged
= perf
.PagedPoolUsage
;
1408 info
->KernelNonpaged
= perf
.NonPagedPoolUsage
;
1409 info
->PageSize
= basic
.PageSize
;
1411 /* fields from SYSTEM_PROCESS_INFORMATION */
1412 NtQuerySystemInformation( SystemProcessInformation
, NULL
, 0, &info_size
);
1415 process
= HeapAlloc( GetProcessHeap(), 0, info_size
);
1418 SetLastError( ERROR_OUTOFMEMORY
);
1421 status
= NtQuerySystemInformation( SystemProcessInformation
, process
, info_size
, &info_size
);
1423 HeapFree( GetProcessHeap(), 0, process
);
1424 if (status
!= STATUS_INFO_LENGTH_MISMATCH
)
1426 SetLastError( RtlNtStatusToDosError( status
) );
1430 info
->HandleCount
= info
->ProcessCount
= info
->ThreadCount
= 0;
1434 info
->ProcessCount
++;
1435 info
->HandleCount
+= spi
->HandleCount
;
1436 info
->ThreadCount
+= spi
->dwThreadCount
;
1437 if (spi
->NextEntryOffset
== 0) break;
1438 spi
= (SYSTEM_PROCESS_INFORMATION
*)((char *)spi
+ spi
->NextEntryOffset
);
1440 HeapFree( GetProcessHeap(), 0, process
);
1445 /***********************************************************************
1446 * GetProcessImageFileNameA (kernelbase.@)
1447 * K32GetProcessImageFileNameA (kernelbase.@)
1449 DWORD WINAPI DECLSPEC_HOTPATCH
GetProcessImageFileNameA( HANDLE process
, char *file
, DWORD size
)
1451 return QueryFullProcessImageNameA( process
, PROCESS_NAME_NATIVE
, file
, &size
) ? size
: 0;
1455 /***********************************************************************
1456 * GetProcessImageFileNameW (kernelbase.@)
1457 * K32GetProcessImageFileNameW (kernelbase.@)
1459 DWORD WINAPI DECLSPEC_HOTPATCH
GetProcessImageFileNameW( HANDLE process
, WCHAR
*file
, DWORD size
)
1461 return QueryFullProcessImageNameW( process
, PROCESS_NAME_NATIVE
, file
, &size
) ? size
: 0;
1465 /***********************************************************************
1466 * GetProcessMemoryInfo (kernelbase.@)
1467 * K32GetProcessMemoryInfo (kernelbase.@)
1469 BOOL WINAPI DECLSPEC_HOTPATCH
GetProcessMemoryInfo( HANDLE process
, PROCESS_MEMORY_COUNTERS
*pmc
,
1474 if (count
< sizeof(PROCESS_MEMORY_COUNTERS
))
1476 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1480 if (!set_ntstatus( NtQueryInformationProcess( process
, ProcessVmCounters
, &vmc
, sizeof(vmc
), NULL
)))
1483 pmc
->cb
= sizeof(PROCESS_MEMORY_COUNTERS
);
1484 pmc
->PageFaultCount
= vmc
.PageFaultCount
;
1485 pmc
->PeakWorkingSetSize
= vmc
.PeakWorkingSetSize
;
1486 pmc
->WorkingSetSize
= vmc
.WorkingSetSize
;
1487 pmc
->QuotaPeakPagedPoolUsage
= vmc
.QuotaPeakPagedPoolUsage
;
1488 pmc
->QuotaPagedPoolUsage
= vmc
.QuotaPagedPoolUsage
;
1489 pmc
->QuotaPeakNonPagedPoolUsage
= vmc
.QuotaPeakNonPagedPoolUsage
;
1490 pmc
->QuotaNonPagedPoolUsage
= vmc
.QuotaNonPagedPoolUsage
;
1491 pmc
->PagefileUsage
= vmc
.PagefileUsage
;
1492 pmc
->PeakPagefileUsage
= vmc
.PeakPagefileUsage
;
1497 /***********************************************************************
1498 * GetWsChanges (kernelbase.@)
1499 * K32GetWsChanges (kernelbase.@)
1501 BOOL WINAPI DECLSPEC_HOTPATCH
GetWsChanges( HANDLE process
, PSAPI_WS_WATCH_INFORMATION
*info
, DWORD size
)
1503 TRACE( "(%p, %p, %d)\n", process
, info
, size
);
1504 return set_ntstatus( NtQueryInformationProcess( process
, ProcessWorkingSetWatch
, info
, size
, NULL
));
1508 /***********************************************************************
1509 * GetWsChangesEx (kernelbase.@)
1510 * K32GetWsChangesEx (kernelbase.@)
1512 BOOL WINAPI DECLSPEC_HOTPATCH
GetWsChangesEx( HANDLE process
, PSAPI_WS_WATCH_INFORMATION_EX
*info
,
1515 FIXME( "(%p, %p, %p)\n", process
, info
, size
);
1516 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1521 /***********************************************************************
1522 * InitializeProcessForWsWatch (kernelbase.@)
1523 * K32InitializeProcessForWsWatch (kernelbase.@)
1525 BOOL WINAPI
/* DECLSPEC_HOTPATCH */ InitializeProcessForWsWatch( HANDLE process
)
1527 FIXME( "(process=%p): stub\n", process
);
1532 /***********************************************************************
1533 * QueryWorkingSet (kernelbase.@)
1534 * K32QueryWorkingSet (kernelbase.@)
1536 BOOL WINAPI DECLSPEC_HOTPATCH
QueryWorkingSet( HANDLE process
, void *buffer
, DWORD size
)
1538 TRACE( "(%p, %p, %d)\n", process
, buffer
, size
);
1539 return set_ntstatus( NtQueryVirtualMemory( process
, NULL
, MemoryWorkingSetList
, buffer
, size
, NULL
));
1543 /***********************************************************************
1544 * QueryWorkingSetEx (kernelbase.@)
1545 * K32QueryWorkingSetEx (kernelbase.@)
1547 BOOL WINAPI
QueryWorkingSetEx( HANDLE process
, void *buffer
, DWORD size
)
1549 TRACE( "(%p, %p, %d)\n", process
, buffer
, size
);
1550 return set_ntstatus( NtQueryVirtualMemory( process
, NULL
, MemoryWorkingSetExInformation
,
1551 buffer
, size
, NULL
));
1555 /******************************************************************
1556 * QueryFullProcessImageNameA (kernelbase.@)
1558 BOOL WINAPI DECLSPEC_HOTPATCH
QueryFullProcessImageNameA( HANDLE process
, DWORD flags
,
1559 char *name
, DWORD
*size
)
1562 DWORD sizeW
= *size
;
1563 WCHAR
*nameW
= HeapAlloc( GetProcessHeap(), 0, *size
* sizeof(WCHAR
) );
1565 ret
= QueryFullProcessImageNameW( process
, flags
, nameW
, &sizeW
);
1566 if (ret
) ret
= (WideCharToMultiByte( CP_ACP
, 0, nameW
, -1, name
, *size
, NULL
, NULL
) > 0);
1567 if (ret
) *size
= strlen( name
);
1568 HeapFree( GetProcessHeap(), 0, nameW
);
1573 /******************************************************************
1574 * QueryFullProcessImageNameW (kernelbase.@)
1576 BOOL WINAPI DECLSPEC_HOTPATCH
QueryFullProcessImageNameW( HANDLE process
, DWORD flags
,
1577 WCHAR
*name
, DWORD
*size
)
1579 BYTE buffer
[sizeof(UNICODE_STRING
) + MAX_PATH
*sizeof(WCHAR
)]; /* this buffer should be enough */
1580 UNICODE_STRING
*dynamic_buffer
= NULL
;
1581 UNICODE_STRING
*result
= NULL
;
1585 /* FIXME: Use ProcessImageFileName for the PROCESS_NAME_NATIVE case */
1586 status
= NtQueryInformationProcess( process
, ProcessImageFileNameWin32
, buffer
,
1587 sizeof(buffer
) - sizeof(WCHAR
), &needed
);
1588 if (status
== STATUS_INFO_LENGTH_MISMATCH
)
1590 dynamic_buffer
= HeapAlloc( GetProcessHeap(), 0, needed
+ sizeof(WCHAR
) );
1591 status
= NtQueryInformationProcess( process
, ProcessImageFileNameWin32
, dynamic_buffer
,
1593 result
= dynamic_buffer
;
1596 result
= (UNICODE_STRING
*)buffer
;
1598 if (status
) goto cleanup
;
1600 if (flags
& PROCESS_NAME_NATIVE
)
1604 DWORD ntlen
, devlen
;
1606 if (result
->Buffer
[1] != ':' || result
->Buffer
[0] < 'A' || result
->Buffer
[0] > 'Z')
1608 /* We cannot convert it to an NT device path so fail */
1609 status
= STATUS_NO_SUCH_DEVICE
;
1613 /* Find this drive's NT device path */
1614 drive
[0] = result
->Buffer
[0];
1617 if (!QueryDosDeviceW(drive
, device
, ARRAY_SIZE(device
)))
1619 status
= STATUS_NO_SUCH_DEVICE
;
1623 devlen
= lstrlenW(device
);
1624 ntlen
= devlen
+ (result
->Length
/sizeof(WCHAR
) - 2);
1625 if (ntlen
+ 1 > *size
)
1627 status
= STATUS_BUFFER_TOO_SMALL
;
1632 memcpy( name
, device
, devlen
* sizeof(*device
) );
1633 memcpy( name
+ devlen
, result
->Buffer
+ 2, result
->Length
- 2 * sizeof(WCHAR
) );
1635 TRACE( "NT path: %s\n", debugstr_w(name
) );
1639 if (result
->Length
/sizeof(WCHAR
) + 1 > *size
)
1641 status
= STATUS_BUFFER_TOO_SMALL
;
1645 *size
= result
->Length
/sizeof(WCHAR
);
1646 memcpy( name
, result
->Buffer
, result
->Length
);
1651 HeapFree( GetProcessHeap(), 0, dynamic_buffer
);
1652 return set_ntstatus( status
);