static inline BOOL find_next_hook(DWORD event, HWND hwnd, LONG object_id, LONG child_id, struct hook_info *info) { BOOL ret; SERVER_START_REQ( get_hook_info ) { req->handle = wine_server_user_handle( info->handle ); req->get_next = 1; req->event = event; req->window = wine_server_user_handle( hwnd ); req->object_id = object_id; req->child_id = child_id; wine_server_set_reply( req, info->module, sizeof(info->module)-sizeof(WCHAR) ); ret = !wine_server_call( req ); if (ret) { info->module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0; info->handle = wine_server_ptr_handle( reply->handle ); info->proc = wine_server_get_ptr( reply->proc ); info->tid = reply->tid; } } SERVER_END_REQ; return ret; }
LRESULT call_current_hook( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam ) { struct hook_info info; ZeroMemory( &info, sizeof(info) - sizeof(info.module) ); SERVER_START_REQ( get_hook_info ) { req->handle = wine_server_user_handle( hhook ); req->get_next = 0; req->event = EVENT_MIN; wine_server_set_reply( req, info.module, sizeof(info.module)-sizeof(WCHAR) ); if (!wine_server_call_err( req )) { info.module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0; info.handle = wine_server_ptr_handle( reply->handle ); info.id = reply->id; info.pid = reply->pid; info.tid = reply->tid; info.proc = wine_server_get_ptr( reply->proc ); info.next_unicode = reply->unicode; } } SERVER_END_REQ; info.prev_unicode = TRUE; /* assume Unicode for this function */ return call_hook( &info, code, wparam, lparam ); }
static inline BOOL find_first_hook(DWORD id, DWORD event, HWND hwnd, LONG object_id, LONG child_id, struct hook_info *info) { struct user_thread_info *thread_info = get_user_thread_info(); BOOL ret; if (!HOOK_IsHooked( id )) { TRACE( "skipping hook %s mask %x\n", hook_names[id-WH_MINHOOK], thread_info->active_hooks ); return FALSE; } SERVER_START_REQ( start_hook_chain ) { req->id = id; req->event = event; req->window = wine_server_user_handle( hwnd ); req->object_id = object_id; req->child_id = child_id; wine_server_set_reply( req, info->module, sizeof(info->module)-sizeof(WCHAR) ); ret = !wine_server_call( req ); if (ret) { info->module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0; info->handle = wine_server_ptr_handle( reply->handle ); info->proc = wine_server_get_ptr( reply->proc ); info->tid = reply->tid; thread_info->active_hooks = reply->active_hooks; } } SERVER_END_REQ; return ret && (info->tid || info->proc); }
/*********************************************************************** * CallNextHookEx (USER32.@) */ LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam ) { struct user_thread_info *thread_info = get_user_thread_info(); struct hook_info info; ZeroMemory( &info, sizeof(info) - sizeof(info.module) ); SERVER_START_REQ( get_hook_info ) { req->handle = wine_server_user_handle( thread_info->hook ); req->get_next = 1; req->event = EVENT_MIN; wine_server_set_reply( req, info.module, sizeof(info.module)-sizeof(WCHAR) ); if (!wine_server_call_err( req )) { info.module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0; info.handle = wine_server_ptr_handle( reply->handle ); info.id = reply->id; info.pid = reply->pid; info.tid = reply->tid; info.proc = wine_server_get_ptr( reply->proc ); info.next_unicode = reply->unicode; } } SERVER_END_REQ; info.prev_unicode = thread_info->hook_unicode; return call_hook( &info, code, wparam, lparam ); }
/*********************************************************************** * HOOK_CallHooks */ LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL unicode ) { struct user_thread_info *thread_info = get_user_thread_info(); struct hook_info info; DWORD_PTR ret = 0; USER_CheckNotLock(); if (!HOOK_IsHooked( id )) { TRACE( "skipping hook %s mask %x\n", hook_names[id-WH_MINHOOK], thread_info->active_hooks ); return 0; } ZeroMemory( &info, sizeof(info) - sizeof(info.module) ); info.prev_unicode = unicode; info.id = id; SERVER_START_REQ( start_hook_chain ) { req->id = info.id; req->event = EVENT_MIN; wine_server_set_reply( req, info.module, sizeof(info.module)-sizeof(WCHAR) ); if (!wine_server_call( req )) { info.module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0; info.handle = wine_server_ptr_handle( reply->handle ); info.pid = reply->pid; info.tid = reply->tid; info.proc = wine_server_get_ptr( reply->proc ); info.next_unicode = reply->unicode; thread_info->active_hooks = reply->active_hooks; } } SERVER_END_REQ; if (!info.tid && !info.proc) return 0; ret = call_hook( &info, code, wparam, lparam ); SERVER_START_REQ( finish_hook_chain ) { req->id = id; wine_server_call( req ); } SERVER_END_REQ; return ret; }
/****************************************************************************** * WaitForDebugEvent (KERNEL32.@) * * Waits for a debugging event to occur in a process being debugged before * filling out the debug event structure. * * PARAMS * event [O] Address of structure for event information. * timeout [I] Number of milliseconds to wait for event. * * RETURNS * * Returns true if a debug event occurred and false if the call timed out. */ BOOL WINAPI WaitForDebugEvent( LPDEBUG_EVENT event, DWORD timeout) { BOOL ret; DWORD res; int i; for (;;) { HANDLE wait = 0; debug_event_t data; SERVER_START_REQ( wait_debug_event ) { req->get_handle = (timeout != 0); wine_server_set_reply( req, &data, sizeof(data) ); if (!(ret = !wine_server_call_err( req ))) goto done; if (!wine_server_reply_size(reply)) /* timeout */ { wait = wine_server_ptr_handle( reply->wait ); ret = FALSE; goto done; } event->dwDebugEventCode = data.code; event->dwProcessId = (DWORD)reply->pid; event->dwThreadId = (DWORD)reply->tid; switch(data.code) { case EXCEPTION_DEBUG_EVENT: event->u.Exception.dwFirstChance = data.exception.first; event->u.Exception.ExceptionRecord.ExceptionCode = data.exception.exc_code; event->u.Exception.ExceptionRecord.ExceptionFlags = data.exception.flags; event->u.Exception.ExceptionRecord.ExceptionRecord = wine_server_get_ptr( data.exception.record ); event->u.Exception.ExceptionRecord.ExceptionAddress = wine_server_get_ptr( data.exception.address ); event->u.Exception.ExceptionRecord.NumberParameters = data.exception.nb_params; for (i = 0; i < data.exception.nb_params; i++) event->u.Exception.ExceptionRecord.ExceptionInformation[i] = data.exception.params[i]; break; case CREATE_THREAD_DEBUG_EVENT: event->u.CreateThread.hThread = wine_server_ptr_handle( data.create_thread.handle ); event->u.CreateThread.lpThreadLocalBase = wine_server_get_ptr( data.create_thread.teb ); event->u.CreateThread.lpStartAddress = wine_server_get_ptr( data.create_thread.start ); break; case CREATE_PROCESS_DEBUG_EVENT: event->u.CreateProcessInfo.hFile = wine_server_ptr_handle( data.create_process.file ); event->u.CreateProcessInfo.hProcess = wine_server_ptr_handle( data.create_process.process ); event->u.CreateProcessInfo.hThread = wine_server_ptr_handle( data.create_process.thread ); event->u.CreateProcessInfo.lpBaseOfImage = wine_server_get_ptr( data.create_process.base ); event->u.CreateProcessInfo.dwDebugInfoFileOffset = data.create_process.dbg_offset; event->u.CreateProcessInfo.nDebugInfoSize = data.create_process.dbg_size; event->u.CreateProcessInfo.lpThreadLocalBase = wine_server_get_ptr( data.create_process.teb ); event->u.CreateProcessInfo.lpStartAddress = wine_server_get_ptr( data.create_process.start ); event->u.CreateProcessInfo.lpImageName = wine_server_get_ptr( data.create_process.name ); event->u.CreateProcessInfo.fUnicode = data.create_process.unicode; break; case EXIT_THREAD_DEBUG_EVENT: event->u.ExitThread.dwExitCode = data.exit.exit_code; break; case EXIT_PROCESS_DEBUG_EVENT: event->u.ExitProcess.dwExitCode = data.exit.exit_code; break; case LOAD_DLL_DEBUG_EVENT: event->u.LoadDll.hFile = wine_server_ptr_handle( data.load_dll.handle ); event->u.LoadDll.lpBaseOfDll = wine_server_get_ptr( data.load_dll.base ); event->u.LoadDll.dwDebugInfoFileOffset = data.load_dll.dbg_offset; event->u.LoadDll.nDebugInfoSize = data.load_dll.dbg_size; event->u.LoadDll.lpImageName = wine_server_get_ptr( data.load_dll.name ); event->u.LoadDll.fUnicode = data.load_dll.unicode; break; case UNLOAD_DLL_DEBUG_EVENT: event->u.UnloadDll.lpBaseOfDll = wine_server_get_ptr( data.unload_dll.base ); break; case OUTPUT_DEBUG_STRING_EVENT: event->u.DebugString.lpDebugStringData = wine_server_get_ptr( data.output_string.string ); event->u.DebugString.fUnicode = FALSE; event->u.DebugString.nDebugStringLength = data.output_string.length; break; case RIP_EVENT: event->u.RipInfo.dwError = data.rip_info.error; event->u.RipInfo.dwType = data.rip_info.type; break; } done: /* nothing */ ; } SERVER_END_REQ; if (ret) return TRUE; if (!wait) break; res = WaitForSingleObject( wait, timeout ); CloseHandle( wait ); if (res != STATUS_WAIT_0) break; } SetLastError( ERROR_SEM_TIMEOUT ); return FALSE; }
/****************************************************************************** * NtQueryInformationProcess [NTDLL.@] * ZwQueryInformationProcess [NTDLL.@] * */ NTSTATUS WINAPI NtQueryInformationProcess( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength) { NTSTATUS ret = STATUS_SUCCESS; ULONG len = 0; TRACE("(%p,0x%08x,%p,0x%08x,%p)\n", ProcessHandle,ProcessInformationClass, ProcessInformation,ProcessInformationLength, ReturnLength); switch (ProcessInformationClass) { UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits); UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority); UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority); UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort); UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken); UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation); UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize); UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers); UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits); UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch); UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL); UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup); UNIMPLEMENTED_INFO_CLASS(ProcessPriorityClass); UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information); UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost); UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap); UNIMPLEMENTED_INFO_CLASS(ProcessSessionInformation); UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation); UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled); UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination); UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing); case ProcessBasicInformation: { PROCESS_BASIC_INFORMATION pbi; const ULONG_PTR affinity_mask = ((ULONG_PTR)1 << NtCurrentTeb()->Peb->NumberOfProcessors) - 1; if (ProcessInformationLength >= sizeof(PROCESS_BASIC_INFORMATION)) { if (!ProcessInformation) ret = STATUS_ACCESS_VIOLATION; else if (!ProcessHandle) ret = STATUS_INVALID_HANDLE; else { SERVER_START_REQ(get_process_info) { req->handle = wine_server_obj_handle( ProcessHandle ); if ((ret = wine_server_call( req )) == STATUS_SUCCESS) { pbi.ExitStatus = reply->exit_code; pbi.PebBaseAddress = wine_server_get_ptr( reply->peb ); pbi.AffinityMask = reply->affinity & affinity_mask; pbi.BasePriority = reply->priority; pbi.UniqueProcessId = reply->pid; pbi.InheritedFromUniqueProcessId = reply->ppid; } } SERVER_END_REQ; memcpy(ProcessInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION)); len = sizeof(PROCESS_BASIC_INFORMATION); } if (ProcessInformationLength > sizeof(PROCESS_BASIC_INFORMATION)) ret = STATUS_INFO_LENGTH_MISMATCH; } else { len = sizeof(PROCESS_BASIC_INFORMATION); ret = STATUS_INFO_LENGTH_MISMATCH; } } break; case ProcessIoCounters: { IO_COUNTERS pii; if (ProcessInformationLength >= sizeof(IO_COUNTERS)) { if (!ProcessInformation) ret = STATUS_ACCESS_VIOLATION; else if (!ProcessHandle) ret = STATUS_INVALID_HANDLE; else { /* FIXME : real data */ memset(&pii, 0 , sizeof(IO_COUNTERS)); memcpy(ProcessInformation, &pii, sizeof(IO_COUNTERS)); len = sizeof(IO_COUNTERS); } if (ProcessInformationLength > sizeof(IO_COUNTERS)) ret = STATUS_INFO_LENGTH_MISMATCH; } else { len = sizeof(IO_COUNTERS); ret = STATUS_INFO_LENGTH_MISMATCH; } } break; case ProcessVmCounters: { VM_COUNTERS pvmi; /* older Windows versions don't have the PrivatePageCount field */ if (ProcessInformationLength >= FIELD_OFFSET(VM_COUNTERS,PrivatePageCount)) { if (!ProcessInformation) ret = STATUS_ACCESS_VIOLATION; else if (!ProcessHandle) ret = STATUS_INVALID_HANDLE; else { /* FIXME : real data */ memset(&pvmi, 0 , sizeof(VM_COUNTERS)); len = ProcessInformationLength; if (len != FIELD_OFFSET(VM_COUNTERS,PrivatePageCount)) len = sizeof(VM_COUNTERS); memcpy(ProcessInformation, &pvmi, min(ProcessInformationLength,sizeof(VM_COUNTERS))); } if (ProcessInformationLength != FIELD_OFFSET(VM_COUNTERS,PrivatePageCount) && ProcessInformationLength != sizeof(VM_COUNTERS)) ret = STATUS_INFO_LENGTH_MISMATCH; } else { len = sizeof(pvmi); ret = STATUS_INFO_LENGTH_MISMATCH; } } break; case ProcessTimes: { KERNEL_USER_TIMES pti; if (ProcessInformationLength >= sizeof(KERNEL_USER_TIMES)) { if (!ProcessInformation) ret = STATUS_ACCESS_VIOLATION; else if (!ProcessHandle) ret = STATUS_INVALID_HANDLE; else { /* FIXME : User- and KernelTime have to be implemented */ memset(&pti, 0, sizeof(KERNEL_USER_TIMES)); SERVER_START_REQ(get_process_info) { req->handle = wine_server_obj_handle( ProcessHandle ); if ((ret = wine_server_call( req )) == STATUS_SUCCESS) { pti.CreateTime.QuadPart = reply->start_time; pti.ExitTime.QuadPart = reply->end_time; } } SERVER_END_REQ; memcpy(ProcessInformation, &pti, sizeof(KERNEL_USER_TIMES)); len = sizeof(KERNEL_USER_TIMES); } if (ProcessInformationLength > sizeof(KERNEL_USER_TIMES)) ret = STATUS_INFO_LENGTH_MISMATCH; } else { len = sizeof(KERNEL_USER_TIMES); ret = STATUS_INFO_LENGTH_MISMATCH; } }
/****************************************************************************** * NtQueryInformationProcess [NTDLL.@] * ZwQueryInformationProcess [NTDLL.@] * */ NTSTATUS WINAPI NtQueryInformationProcess( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength) { NTSTATUS ret = STATUS_SUCCESS; ULONG len = 0; TRACE("(%p,0x%08x,%p,0x%08x,%p)\n", ProcessHandle,ProcessInformationClass, ProcessInformation,ProcessInformationLength, ReturnLength); switch (ProcessInformationClass) { UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits); UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority); UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority); UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort); UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken); UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation); UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize); UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers); UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits); UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch); UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL); UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup); UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information); UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost); UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap); UNIMPLEMENTED_INFO_CLASS(ProcessSessionInformation); UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation); UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled); UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination); UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing); case ProcessBasicInformation: { PROCESS_BASIC_INFORMATION pbi; const ULONG_PTR affinity_mask = get_system_affinity_mask(); if (ProcessInformationLength >= sizeof(PROCESS_BASIC_INFORMATION)) { if (!ProcessInformation) ret = STATUS_ACCESS_VIOLATION; else if (!ProcessHandle) ret = STATUS_INVALID_HANDLE; else { SERVER_START_REQ(get_process_info) { req->handle = wine_server_obj_handle( ProcessHandle ); if ((ret = wine_server_call( req )) == STATUS_SUCCESS) { pbi.ExitStatus = reply->exit_code; pbi.PebBaseAddress = wine_server_get_ptr( reply->peb ); pbi.AffinityMask = reply->affinity & affinity_mask; pbi.BasePriority = reply->priority; pbi.UniqueProcessId = reply->pid; pbi.InheritedFromUniqueProcessId = reply->ppid; } } SERVER_END_REQ; memcpy(ProcessInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION)); len = sizeof(PROCESS_BASIC_INFORMATION); } if (ProcessInformationLength > sizeof(PROCESS_BASIC_INFORMATION)) ret = STATUS_INFO_LENGTH_MISMATCH; } else { len = sizeof(PROCESS_BASIC_INFORMATION); ret = STATUS_INFO_LENGTH_MISMATCH; } } break; case ProcessIoCounters: { IO_COUNTERS pii; if (ProcessInformationLength >= sizeof(IO_COUNTERS)) { if (!ProcessInformation) ret = STATUS_ACCESS_VIOLATION; else if (!ProcessHandle) ret = STATUS_INVALID_HANDLE; else { /* FIXME : real data */ memset(&pii, 0 , sizeof(IO_COUNTERS)); memcpy(ProcessInformation, &pii, sizeof(IO_COUNTERS)); len = sizeof(IO_COUNTERS); } if (ProcessInformationLength > sizeof(IO_COUNTERS)) ret = STATUS_INFO_LENGTH_MISMATCH; } else { len = sizeof(IO_COUNTERS); ret = STATUS_INFO_LENGTH_MISMATCH; } } break; case ProcessVmCounters: { VM_COUNTERS pvmi; /* older Windows versions don't have the PrivatePageCount field */ if (ProcessInformationLength >= FIELD_OFFSET(VM_COUNTERS,PrivatePageCount)) { if (!ProcessInformation) ret = STATUS_ACCESS_VIOLATION; else { memset(&pvmi, 0 , sizeof(VM_COUNTERS)); if (ProcessHandle == GetCurrentProcess()) fill_VM_COUNTERS(&pvmi); else { SERVER_START_REQ(get_process_vm_counters) { req->handle = wine_server_obj_handle( ProcessHandle ); if (!(ret = wine_server_call( req ))) { pvmi.PeakVirtualSize = reply->peak_virtual_size; pvmi.VirtualSize = reply->virtual_size; pvmi.PeakWorkingSetSize = reply->peak_working_set_size; pvmi.WorkingSetSize = reply->working_set_size; pvmi.PagefileUsage = reply->pagefile_usage; pvmi.PeakPagefileUsage = reply->peak_pagefile_usage; } } SERVER_END_REQ; if (ret) break; } len = ProcessInformationLength; if (len != FIELD_OFFSET(VM_COUNTERS,PrivatePageCount)) len = sizeof(VM_COUNTERS); memcpy(ProcessInformation, &pvmi, min(ProcessInformationLength,sizeof(VM_COUNTERS))); } if (ProcessInformationLength != FIELD_OFFSET(VM_COUNTERS,PrivatePageCount) && ProcessInformationLength != sizeof(VM_COUNTERS)) ret = STATUS_INFO_LENGTH_MISMATCH; } else { len = sizeof(pvmi); ret = STATUS_INFO_LENGTH_MISMATCH; } }