diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c index 637bef0b656..1bef51b00b3 100644 --- a/dlls/ntdll/process.c +++ b/dlls/ntdll/process.c @@ -621,6 +621,29 @@ NTSTATUS WINAPI NtQueryInformationProcess( else ret = STATUS_INVALID_PARAMETER; break; + + case ProcessImageInformation: + len = sizeof(SECTION_IMAGE_INFORMATION); + if (ProcessInformationLength == len) + { + if (ProcessInformation) + { + pe_image_info_t pe_info; + + SERVER_START_REQ( get_process_info ) + { + req->handle = wine_server_obj_handle( ProcessHandle ); + wine_server_set_reply( req, &pe_info, sizeof(pe_info) ); + if ((ret = wine_server_call( req )) == STATUS_SUCCESS) + virtual_fill_image_information( &pe_info, ProcessInformation ); + } + SERVER_END_REQ; + } + else ret = STATUS_ACCESS_VIOLATION; + } + else ret = STATUS_INFO_LENGTH_MISMATCH; + break; + default: FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n", ProcessHandle,ProcessInformationClass, diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index f923cc7743f..cf3f7b9f6f2 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -1821,6 +1821,34 @@ todo_wine heap_free(buffer); } +static void test_query_process_image_info(void) +{ + IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress ); + NTSTATUS status; + SECTION_IMAGE_INFORMATION info; + ULONG len; + + status = pNtQueryInformationProcess( NULL, ProcessImageInformation, &info, sizeof(info), &len ); + ok( status == STATUS_INVALID_HANDLE || broken(status == STATUS_INVALID_PARAMETER), /* winxp */ + "got %08x\n", status); + + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessImageInformation, &info, sizeof(info)-1, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "got %08x\n", status); + + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessImageInformation, &info, sizeof(info)+1, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "got %08x\n", status); + + memset( &info, 0xcc, sizeof(info) ); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessImageInformation, &info, sizeof(info), &len ); + ok( status == STATUS_SUCCESS, "got %08x\n", status); + ok( len == sizeof(info), "wrong len %u\n", len ); + + ok( info.SubsystemVersionHigh == nt->OptionalHeader.MajorSubsystemVersion, "wrong major version %x/%x\n", + info.SubsystemVersionHigh, nt->OptionalHeader.MajorSubsystemVersion ); + ok( info.SubsystemVersionLow == nt->OptionalHeader.MinorSubsystemVersion, "wrong minor version %x/%x\n", + info.SubsystemVersionLow, nt->OptionalHeader.MinorSubsystemVersion ); +} + static void test_query_process_debug_object_handle(int argc, char **argv) { char cmdline[MAX_PATH]; @@ -2741,6 +2769,10 @@ START_TEST(info) trace("Starting test_process_debug_flags()\n"); test_query_process_debug_flags(argc, argv); + /* 0x25 ProcessImageInformation */ + trace("Starting test_process_image_info()\n"); + test_query_process_image_info(); + /* 0x4C SystemFirmwareTableInformation */ trace("Starting test_query_firmware()\n"); test_query_firmware(); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 2419671f0d6..3e205d4165b 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -962,6 +962,7 @@ struct get_process_info_reply client_cpu_t cpu; short int debugger_present; short int debug_children; + /* VARARG(image,pe_image_info); */ }; @@ -6684,7 +6685,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 603 +#define SERVER_PROTOCOL_VERSION 604 /* ### protocol_version end ### */ diff --git a/server/file.h b/server/file.h index aa5f6216c25..45215c588d0 100644 --- a/server/file.h +++ b/server/file.h @@ -171,6 +171,7 @@ extern struct mapping *get_mapping_obj( struct process *process, obj_handle_t ha unsigned int access ); extern struct file *get_mapping_file( struct process *process, client_ptr_t base, unsigned int access, unsigned int sharing ); +extern const pe_image_info_t *get_mapping_image_info( struct process *process, client_ptr_t base ); extern void free_mapped_views( struct process *process ); extern int get_page_size(void); diff --git a/server/mapping.c b/server/mapping.c index 0fcada7f8f5..2c34b8f3c83 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -127,6 +127,7 @@ struct memory_view struct fd *fd; /* fd for mapped file */ struct ranges *committed; /* list of committed ranges in this mapping */ struct shared_map *shared; /* temp file for shared PE mapping */ + pe_image_info_t image; /* image info (for PE image mapping) */ unsigned int flags; /* SEC_* flags */ client_ptr_t base; /* view base address (in process addr space) */ mem_size_t size; /* view size */ @@ -894,6 +895,15 @@ struct file *get_mapping_file( struct process *process, client_ptr_t base, return create_file_for_fd_obj( view->fd, access, sharing ); } +/* get the image info for a SEC_IMAGE mapping */ +const pe_image_info_t *get_mapping_image_info( struct process *process, client_ptr_t base ) +{ + struct memory_view *view = find_mapped_view( process, base ); + + if (!view || !(view->flags & SEC_IMAGE)) return NULL; + return &view->image; +} + static void mapping_dump( struct object *obj, int verbose ) { struct mapping *mapping = (struct mapping *)obj; @@ -1062,6 +1072,7 @@ DECL_HANDLER(map_view) view->fd = !is_fd_removable( mapping->fd ) ? (struct fd *)grab_object( mapping->fd ) : NULL; view->committed = mapping->committed ? (struct ranges *)grab_object( mapping->committed ) : NULL; view->shared = mapping->shared ? (struct shared_map *)grab_object( mapping->shared ) : NULL; + if (mapping->flags & SEC_IMAGE) view->image = mapping->image; list_add_tail( ¤t->process->views, &view->entry ); } diff --git a/server/process.c b/server/process.c index 6722addb091..ab3d448b001 100644 --- a/server/process.c +++ b/server/process.c @@ -1447,6 +1447,13 @@ DECL_HANDLER(get_process_info) reply->cpu = process->cpu; reply->debugger_present = !!process->debugger; reply->debug_children = process->debug_children; + if (get_reply_max_size()) + { + const pe_image_info_t *info; + struct process_dll *exe = get_process_exe_module( process ); + if (exe && (info = get_mapping_image_info( process, exe->base ))) + set_reply_data( info, min( sizeof(*info), get_reply_max_size() )); + } release_object( process ); } } diff --git a/server/protocol.def b/server/protocol.def index 2fb8e2ec80b..86efb01cc31 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -915,6 +915,7 @@ struct rawinput_device client_cpu_t cpu; /* CPU that this process is running on */ short int debugger_present; /* process is being debugged */ short int debug_children; /* inherit debugger to child processes */ + VARARG(image,pe_image_info); /* image info for main exe */ @END diff --git a/server/trace.c b/server/trace.c index ca2cbb90741..c5c006ce419 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1389,6 +1389,7 @@ static void dump_get_process_info_reply( const struct get_process_info_reply *re dump_client_cpu( ", cpu=", &req->cpu ); fprintf( stderr, ", debugger_present=%d", req->debugger_present ); fprintf( stderr, ", debug_children=%d", req->debug_children ); + dump_varargs_pe_image_info( ", image=", cur_size ); } static void dump_get_process_vm_counters_request( const struct get_process_vm_counters_request *req )