diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 8eaf4d63..3383dfda 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -310,6 +310,7 @@ patch_enable_all () enable_server_LABEL_SECURITY_INFORMATION="$1" enable_server_Map_EXDEV_Error="$1" enable_server_Misc_ACL="$1" + enable_server_Object_Types="$1" enable_server_PeekMessage="$1" enable_server_Pipe_ObjectName="$1" enable_server_Realtime_Priority="$1" @@ -1151,6 +1152,9 @@ patch_enable () server-Misc_ACL) enable_server_Misc_ACL="$2" ;; + server-Object_Types) + enable_server_Object_Types="$2" + ;; server-PeekMessage) enable_server_PeekMessage="$2" ;; @@ -2134,6 +2138,31 @@ if test "$enable_shell32_Progress_Dialog" -eq 1; then enable_shell32_SHFileOperation_Move=1 fi +if test "$enable_server_Realtime_Priority" -eq 1; then + if test "$enable_ntdll_ThreadTime" -gt 1; then + abort "Patchset ntdll-ThreadTime disabled, but server-Realtime_Priority depends on that." + fi + enable_ntdll_ThreadTime=1 +fi + +if test "$enable_server_Pipe_ObjectName" -eq 1; then + if test "$enable_kernel32_Named_Pipe" -gt 1; then + abort "Patchset kernel32-Named_Pipe disabled, but server-Pipe_ObjectName depends on that." + fi + enable_kernel32_Named_Pipe=1 +fi + +if test "$enable_server_Object_Types" -eq 1; then + if test "$enable_server_Misc_ACL" -gt 1; then + abort "Patchset server-Misc_ACL disabled, but server-Object_Types depends on that." + fi + if test "$enable_server_Shared_Memory" -gt 1; then + abort "Patchset server-Shared_Memory disabled, but server-Object_Types depends on that." + fi + enable_server_Misc_ACL=1 + enable_server_Shared_Memory=1 +fi + if test "$enable_server_Shared_Memory" -eq 1; then if test "$enable_ntdll_Threading" -gt 1; then abort "Patchset ntdll-Threading disabled, but server-Shared_Memory depends on that." @@ -2157,20 +2186,6 @@ if test "$enable_server_Shared_Memory" -eq 1; then enable_server_Signal_Thread=1 fi -if test "$enable_server_Realtime_Priority" -eq 1; then - if test "$enable_ntdll_ThreadTime" -gt 1; then - abort "Patchset ntdll-ThreadTime disabled, but server-Realtime_Priority depends on that." - fi - enable_ntdll_ThreadTime=1 -fi - -if test "$enable_server_Pipe_ObjectName" -eq 1; then - if test "$enable_kernel32_Named_Pipe" -gt 1; then - abort "Patchset kernel32-Named_Pipe disabled, but server-Pipe_ObjectName depends on that." - fi - enable_kernel32_Named_Pipe=1 -fi - if test "$enable_server_LABEL_SECURITY_INFORMATION" -eq 1; then if test "$enable_advapi32_GetExplicitEntriesFromAclW" -gt 1; then abort "Patchset advapi32-GetExplicitEntriesFromAclW disabled, but server-LABEL_SECURITY_INFORMATION depends on that." @@ -6699,50 +6714,6 @@ if test "$enable_server_PeekMessage" -eq 1; then ) >> "$patchlist" fi -# Patchset server-Pipe_ObjectName -# | -# | This patchset has the following (direct or indirect) dependencies: -# | * server-Desktop_Refcount, kernel32-Named_Pipe -# | -# | Modified files: -# | * dlls/ntdll/tests/om.c, server/named_pipe.c, server/object.c, server/object.h -# | -if test "$enable_server_Pipe_ObjectName" -eq 1; then - patch_apply server-Pipe_ObjectName/0001-server-Store-a-reference-to-the-parent-object-for-pi.patch - ( - printf '%s\n' '+ { "Sebastian Lackner", "server: Store a reference to the parent object for pipe servers.", 2 },'; - ) >> "$patchlist" -fi - -# Patchset server-Realtime_Priority -# | -# | This patchset has the following (direct or indirect) dependencies: -# | * ntdll-ThreadTime -# | -# | Modified files: -# | * server/Makefile.in, server/main.c, server/scheduler.c, server/thread.c, server/thread.h -# | -if test "$enable_server_Realtime_Priority" -eq 1; then - patch_apply server-Realtime_Priority/0001-wineserver-Draft-to-implement-priority-levels-throug.patch - ( - printf '%s\n' '+ { "Joakim Hernberg", "wineserver: Draft to implement priority levels through POSIX scheduling policies on linux.", 1 },'; - ) >> "$patchlist" -fi - -# Patchset server-Registry_Notifications -# | -# | Modified files: -# | * dlls/ntdll/tests/reg.c, server/registry.c -# | -if test "$enable_server_Registry_Notifications" -eq 1; then - patch_apply server-Registry_Notifications/0001-server-Allow-multiple-registry-notifications-for-the.patch - patch_apply server-Registry_Notifications/0002-server-Introduce-refcounting-for-registry-notificati.patch - ( - printf '%s\n' '+ { "Sebastian Lackner", "server: Allow multiple registry notifications for the same key.", 1 },'; - printf '%s\n' '+ { "Sebastian Lackner", "server: Introduce refcounting for registry notifications.", 1 },'; - ) >> "$patchlist" -fi - # Patchset server-Signal_Thread # | # | Modified files: @@ -6789,6 +6760,88 @@ if test "$enable_server_Shared_Memory" -eq 1; then ) >> "$patchlist" fi +# Patchset server-Object_Types +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * server-Misc_ACL, ntdll-Threading, server-ClipCursor, server-Key_State, server-PeekMessage, server-Signal_Thread, server- +# | Shared_Memory +# | +# | Modified files: +# | * dlls/ntdll/nt.c, dlls/ntdll/om.c, dlls/ntdll/tests/info.c, dlls/ntdll/tests/om.c, include/winternl.h, +# | server/completion.c, server/directory.c, server/event.c, server/file.c, server/handle.c, server/mailslot.c, +# | server/main.c, server/mapping.c, server/mutex.c, server/named_pipe.c, server/object.c, server/object.h, +# | server/process.c, server/protocol.def, server/registry.c, server/semaphore.c, server/symlink.c, server/thread.c, +# | server/timer.c, server/token.c, server/winstation.c +# | +if test "$enable_server_Object_Types" -eq 1; then + patch_apply server-Object_Types/0001-ntdll-Implement-SystemExtendedHandleInformation-in-N.patch + patch_apply server-Object_Types/0002-ntdll-Implement-ObjectTypesInformation-in-NtQueryObj.patch + patch_apply server-Object_Types/0003-server-Register-types-during-startup.patch + patch_apply server-Object_Types/0004-server-Rename-ObjectType-to-Type.patch + patch_apply server-Object_Types/0005-server-Add-type-Token.patch + patch_apply server-Object_Types/0006-server-Add-type-Process.patch + patch_apply server-Object_Types/0007-server-Add-type-Thread.patch + patch_apply server-Object_Types/0008-ntdll-Set-TypeIndex-for-ObjectTypeInformation-in-NtQ.patch + patch_apply server-Object_Types/0009-ntdll-Set-object-type-for-System-Extended-HandleInfo.patch + patch_apply server-Object_Types/0010-ntdll-Mimic-object-type-behavior-for-different-windo.patch + ( + printf '%s\n' '+ { "Michael Müller", "ntdll: Implement SystemExtendedHandleInformation in NtQuerySystemInformation.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "ntdll: Implement ObjectTypesInformation in NtQueryObject.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "server: Register types during startup.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "server: Rename ObjectType to Type.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "server: Add type Token.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "server: Add type Process.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "server: Add type Thread.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "ntdll: Set TypeIndex for ObjectTypeInformation in NtQueryObject.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "ntdll: Set object type for System(Extended)HandleInformation in NtQuerySystemInformation.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "ntdll: Mimic object type behavior for different windows versions.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset server-Pipe_ObjectName +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * server-Desktop_Refcount, kernel32-Named_Pipe +# | +# | Modified files: +# | * dlls/ntdll/tests/om.c, server/named_pipe.c, server/object.c, server/object.h +# | +if test "$enable_server_Pipe_ObjectName" -eq 1; then + patch_apply server-Pipe_ObjectName/0001-server-Store-a-reference-to-the-parent-object-for-pi.patch + ( + printf '%s\n' '+ { "Sebastian Lackner", "server: Store a reference to the parent object for pipe servers.", 2 },'; + ) >> "$patchlist" +fi + +# Patchset server-Realtime_Priority +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * ntdll-ThreadTime +# | +# | Modified files: +# | * server/Makefile.in, server/main.c, server/scheduler.c, server/thread.c, server/thread.h +# | +if test "$enable_server_Realtime_Priority" -eq 1; then + patch_apply server-Realtime_Priority/0001-wineserver-Draft-to-implement-priority-levels-throug.patch + ( + printf '%s\n' '+ { "Joakim Hernberg", "wineserver: Draft to implement priority levels through POSIX scheduling policies on linux.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset server-Registry_Notifications +# | +# | Modified files: +# | * dlls/ntdll/tests/reg.c, server/registry.c +# | +if test "$enable_server_Registry_Notifications" -eq 1; then + patch_apply server-Registry_Notifications/0001-server-Allow-multiple-registry-notifications-for-the.patch + patch_apply server-Registry_Notifications/0002-server-Introduce-refcounting-for-registry-notificati.patch + ( + printf '%s\n' '+ { "Sebastian Lackner", "server: Allow multiple registry notifications for the same key.", 1 },'; + printf '%s\n' '+ { "Sebastian Lackner", "server: Introduce refcounting for registry notifications.", 1 },'; + ) >> "$patchlist" +fi + # Patchset server-Timestamp_Compat # | # | Modified files: diff --git a/patches/server-Object_Types/0001-ntdll-Implement-SystemExtendedHandleInformation-in-N.patch b/patches/server-Object_Types/0001-ntdll-Implement-SystemExtendedHandleInformation-in-N.patch new file mode 100644 index 00000000..3b9b864c --- /dev/null +++ b/patches/server-Object_Types/0001-ntdll-Implement-SystemExtendedHandleInformation-in-N.patch @@ -0,0 +1,187 @@ +From 0384d32afa328e76bff7f8e508201ce2535ee763 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Tue, 7 Mar 2017 18:30:33 +0100 +Subject: ntdll: Implement SystemExtendedHandleInformation in + NtQuerySystemInformation. + +--- + dlls/ntdll/nt.c | 51 +++++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/tests/info.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ + include/winternl.h | 21 +++++++++++++++++ + 3 files changed, 132 insertions(+) + +diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c +index de8f16f9a0..a939298d19 100644 +--- a/dlls/ntdll/nt.c ++++ b/dlls/ntdll/nt.c +@@ -2294,6 +2294,57 @@ NTSTATUS WINAPI NtQuerySystemInformation( + RtlFreeHeap( GetProcessHeap(), 0, info ); + } + break; ++ case SystemExtendedHandleInformation: ++ { ++ struct handle_info *info; ++ DWORD i, num_handles; ++ ++ if (Length < sizeof(SYSTEM_HANDLE_INFORMATION_EX)) ++ { ++ ret = STATUS_INFO_LENGTH_MISMATCH; ++ break; ++ } ++ ++ if (!SystemInformation) ++ { ++ ret = STATUS_ACCESS_VIOLATION; ++ break; ++ } ++ ++ num_handles = (Length - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handle )); ++ num_handles /= sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX); ++ if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) * num_handles ))) ++ return STATUS_NO_MEMORY; ++ ++ SERVER_START_REQ( get_system_handles ) ++ { ++ wine_server_set_reply( req, info, sizeof(*info) * num_handles ); ++ if (!(ret = wine_server_call( req ))) ++ { ++ SYSTEM_HANDLE_INFORMATION_EX *shi = SystemInformation; ++ shi->Count = wine_server_reply_size( req ) / sizeof(*info); ++ shi->Reserved = 0; ++ len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handle[shi->Count] ); ++ for (i = 0; i < shi->Count; i++) ++ { ++ memset( &shi->Handle[i], 0, sizeof(shi->Handle[i]) ); ++ shi->Handle[i].UniqueProcessId = info[i].owner; ++ shi->Handle[i].HandleValue = info[i].handle; ++ shi->Handle[i].GrantedAccess = info[i].access; ++ /* FIXME: Fill out remaining fields */ ++ } ++ } ++ else if (ret == STATUS_BUFFER_TOO_SMALL) ++ { ++ len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handle[reply->count] ); ++ ret = STATUS_INFO_LENGTH_MISMATCH; ++ } ++ } ++ SERVER_END_REQ; ++ ++ RtlFreeHeap( GetProcessHeap(), 0, info ); ++ } ++ break; + case SystemCacheInformation: + { + SYSTEM_CACHE_INFORMATION sci; +diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c +index 32cb4f5a5d..c65a74bf5e 100644 +--- a/dlls/ntdll/tests/info.c ++++ b/dlls/ntdll/tests/info.c +@@ -561,6 +561,62 @@ done: + HeapFree( GetProcessHeap(), 0, shi); + } + ++static void test_query_handle_ex(void) ++{ ++ NTSTATUS status; ++ ULONG ExpectedLength, ReturnLength; ++ ULONG SystemInformationLength = sizeof(SYSTEM_HANDLE_INFORMATION_EX); ++ SYSTEM_HANDLE_INFORMATION_EX* shi = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength); ++ HANDLE EventHandle; ++ BOOL found; ++ INT i; ++ ++ EventHandle = CreateEventA(NULL, FALSE, FALSE, NULL); ++ ok( EventHandle != NULL, "CreateEventA failed %u\n", GetLastError() ); ++ ++ ReturnLength = 0xdeadbeef; ++ status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi, SystemInformationLength, &ReturnLength); ++ ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); ++ ok( ReturnLength != 0xdeadbeef, "Expected valid ReturnLength\n" ); ++ ++ SystemInformationLength = ReturnLength; ++ shi = HeapReAlloc(GetProcessHeap(), 0, shi , SystemInformationLength); ++ memset(shi, 0x55, SystemInformationLength); ++ ++ ReturnLength = 0xdeadbeef; ++ status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi, SystemInformationLength, &ReturnLength); ++ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status ); ++ ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handle[shi->Count]); ++ ok( ReturnLength == ExpectedLength, "Expected length %u, got %u\n", ExpectedLength, ReturnLength ); ++ ok( shi->Count > 1, "Expected more than 1 handle, got %u\n", (DWORD)shi->Count ); ++ ++ for (i = 0, found = FALSE; i < shi->Count && !found; i++) ++ found = (shi->Handle[i].UniqueProcessId == GetCurrentProcessId()) && ++ ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle); ++ ok( found, "Expected to find event handle %p (pid %x) in handle list\n", EventHandle, GetCurrentProcessId() ); ++ ++ if (!found) ++ { ++ for (i = 0; i < shi->Count; i++) ++ trace( "%d: handle %x pid %x\n", i, (DWORD)shi->Handle[i].HandleValue, (DWORD)shi->Handle[i].UniqueProcessId ); ++ } ++ ++ CloseHandle(EventHandle); ++ ++ ReturnLength = 0xdeadbeef; ++ status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi, SystemInformationLength, &ReturnLength); ++ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status ); ++ for (i = 0, found = FALSE; i < shi->Count && !found; i++) ++ found = (shi->Handle[i].UniqueProcessId == GetCurrentProcessId()) && ++ ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle); ++ ok( !found, "Unexpectedly found event handle in handle list\n" ); ++ ++ status = pNtQuerySystemInformation(SystemExtendedHandleInformation, NULL, SystemInformationLength, &ReturnLength); ++ ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status ); ++ ++ HeapFree( GetProcessHeap(), 0, shi); ++} ++ + static void test_query_cache(void) + { + NTSTATUS status; +@@ -2147,6 +2203,10 @@ START_TEST(info) + trace("Starting test_query_handle()\n"); + test_query_handle(); + ++ /* 0x40 SystemHandleInformation */ ++ trace("Starting test_query_handle_ex()\n"); ++ test_query_handle_ex(); ++ + /* 0x15 SystemCacheInformation */ + trace("Starting test_query_cache()\n"); + test_query_cache(); +diff --git a/include/winternl.h b/include/winternl.h +index 87b2c4d253..7ffe4f6c81 100644 +--- a/include/winternl.h ++++ b/include/winternl.h +@@ -1442,6 +1442,27 @@ typedef struct _SYSTEM_HANDLE_INFORMATION { + SYSTEM_HANDLE_ENTRY Handle[1]; + } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; + ++/* System Information Class 0x40 */ ++ ++typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX ++{ ++ PVOID Object; ++ ULONG_PTR UniqueProcessId; ++ ULONG_PTR HandleValue; ++ ULONG GrantedAccess; ++ USHORT CreatorBackTraceIndex; ++ USHORT ObjectTypeIndex; ++ ULONG HandleAttributes; ++ ULONG Reserved; ++} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; ++ ++typedef struct _SYSTEM_HANDLE_INFORMATION_EX ++{ ++ ULONG_PTR Count; ++ ULONG_PTR Reserved; ++ SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handle[1]; ++} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; ++ + /* System Information Class 0x15 */ + + typedef struct _SYSTEM_CACHE_INFORMATION { +-- +2.11.0 + diff --git a/patches/server-Object_Types/0002-ntdll-Implement-ObjectTypesInformation-in-NtQueryObj.patch b/patches/server-Object_Types/0002-ntdll-Implement-ObjectTypesInformation-in-NtQueryObj.patch new file mode 100644 index 00000000..2d9ca47b --- /dev/null +++ b/patches/server-Object_Types/0002-ntdll-Implement-ObjectTypesInformation-in-NtQueryObj.patch @@ -0,0 +1,278 @@ +From b3286b1c7ea9b507918c96f901d8e2c1311a4a1c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Wed, 8 Mar 2017 02:12:37 +0100 +Subject: ntdll: Implement ObjectTypesInformation in NtQueryObject. + +--- + dlls/ntdll/om.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/tests/om.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ + include/winternl.h | 30 +++++++++++++++++++++++++-- + server/directory.c | 19 ++++++++++++++++- + server/protocol.def | 9 ++++++++ + 5 files changed, 163 insertions(+), 3 deletions(-) + +diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c +index 0f21800df6..8911a28b20 100644 +--- a/dlls/ntdll/om.c ++++ b/dlls/ntdll/om.c +@@ -43,6 +43,7 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(ntdll); + ++#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1)) + + /* + * Generic object functions +@@ -188,6 +189,56 @@ NTSTATUS WINAPI NtQueryObject(IN HANDLE handle, + SERVER_END_REQ; + } + break; ++ case ObjectTypesInformation: ++ { ++ OBJECT_TYPES_INFORMATION *p = ptr; ++ OBJECT_TYPE_INFORMATION *type = (OBJECT_TYPE_INFORMATION *)(p + 1); ++ ULONG count, type_len, req_len = sizeof(OBJECT_TYPES_INFORMATION); ++ ++ for (count = 0, status = STATUS_SUCCESS; !status; count++) ++ { ++ SERVER_START_REQ( get_object_type_by_index ) ++ { ++ req->index = count; ++ if (len > sizeof(*type)) ++ wine_server_set_reply( req, type + 1, len - sizeof(*type) ); ++ status = wine_server_call( req ); ++ if (status == STATUS_SUCCESS) ++ { ++ type_len = sizeof(*type); ++ if (reply->total) ++ type_len += ROUND_UP( reply->total + sizeof(WCHAR), sizeof(DWORD_PTR) ); ++ req_len += type_len; ++ } ++ if (status == STATUS_SUCCESS && len >= req_len) ++ { ++ ULONG res = wine_server_reply_size( reply ); ++ memset( type, 0, sizeof(*type) ); ++ if (reply->total) ++ { ++ type->TypeName.Buffer = (WCHAR *)(type + 1); ++ type->TypeName.Length = res; ++ type->TypeName.MaximumLength = res + sizeof(WCHAR); ++ type->TypeName.Buffer[res / sizeof(WCHAR)] = 0; ++ } ++ type->TypeIndex = count; ++ type = (OBJECT_TYPE_INFORMATION *)((char *)type + type_len); ++ } ++ } ++ SERVER_END_REQ; ++ } ++ ++ if (status != STATUS_NO_MORE_ENTRIES) ++ return status; ++ ++ if (used_len) *used_len = req_len; ++ if (len < req_len) ++ return STATUS_INFO_LENGTH_MISMATCH; ++ ++ p->NumberOfTypes = count - 1; ++ status = STATUS_SUCCESS; ++ } ++ break; + case ObjectDataInformation: + { + OBJECT_DATA_INFORMATION* p = ptr; +diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c +index 9a1ba670ab..534cb514f9 100644 +--- a/dlls/ntdll/tests/om.c ++++ b/dlls/ntdll/tests/om.c +@@ -74,6 +74,21 @@ static NTSTATUS (WINAPI *pNtOpenIoCompletion)( PHANDLE, ACCESS_MASK, POBJECT_ATT + #define KEYEDEVENT_WAKE 0x0002 + #define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x0003) + ++#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1)) ++ ++static LPCSTR wine_dbgstr_us( const UNICODE_STRING *us ) ++{ ++ if (!us) return "(null)"; ++ return wine_dbgstr_wn(us->Buffer, us->Length / sizeof(WCHAR)); ++} ++ ++static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n ) ++{ ++ if (n <= 0) return 0; ++ while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; } ++ return *str1 - *str2; ++} ++ + static void test_case_sensitive (void) + { + static const WCHAR buffer1[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s','\\','t','e','s','t',0}; +@@ -1524,6 +1539,47 @@ static void test_query_object(void) + pRtlFreeUnicodeString( &session ); + } + ++static void test_query_object_types(void) ++{ ++ static const WCHAR typeW[] = {'T','y','p','e'}; ++ OBJECT_TYPES_INFORMATION *buffer; ++ OBJECT_TYPE_INFORMATION *type; ++ NTSTATUS status; ++ ULONG len, i; ++ ++ buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(OBJECT_TYPES_INFORMATION) ); ++ ok( buffer != NULL, "Failed to allocate memory\n" ); ++ ++ status = pNtQueryObject( NULL, ObjectTypesInformation, buffer, sizeof(OBJECT_TYPES_INFORMATION), &len ); ++ ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); ++ ok( len, "len is zero\n"); ++ ++ buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, len ); ++ ok( buffer != NULL, "Failed to allocate memory\n" ); ++ ++ memset( buffer, 0, len ); ++ status = pNtQueryObject( NULL, ObjectTypesInformation, buffer, len, &len ); ++ ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); ++ ok( buffer->NumberOfTypes, "NumberOfTypes is zero\n" ); ++ ++ type = (OBJECT_TYPE_INFORMATION *)(buffer + 1); ++ for (i = 0; i < buffer->NumberOfTypes; i++) ++ { ++ USHORT length = type->TypeName.MaximumLength; ++ trace( "Type %u: %s\n", i, wine_dbgstr_us(&type->TypeName) ); ++ ++ if (i == 0) ++ { ++ todo_wine ok( type->TypeName.Length == sizeof(typeW) && !strncmpW(typeW, type->TypeName.Buffer, 4), ++ "Expected 'Type' as first type, got %s\n", wine_dbgstr_us(&type->TypeName) ); ++ } ++ ++ type = (OBJECT_TYPE_INFORMATION *)ROUND_UP( (DWORD_PTR)(type + 1) + length, sizeof(DWORD_PTR) ); ++ } ++ ++ HeapFree( GetProcessHeap(), 0, buffer ); ++} ++ + static void test_type_mismatch(void) + { + HANDLE h; +@@ -2036,6 +2092,7 @@ START_TEST(om) + test_directory(); + test_symboliclink(); + test_query_object(); ++ test_query_object_types(); + test_type_mismatch(); + test_event(); + test_mutant(); +diff --git a/include/winternl.h b/include/winternl.h +index 7ffe4f6c81..0a2e323c5b 100644 +--- a/include/winternl.h ++++ b/include/winternl.h +@@ -790,7 +790,7 @@ typedef enum _OBJECT_INFORMATION_CLASS { + ObjectBasicInformation, + ObjectNameInformation, + ObjectTypeInformation, +- ObjectAllInformation, ++ ObjectTypesInformation, + ObjectDataInformation + } OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; + +@@ -1208,9 +1208,35 @@ typedef struct _OBJECT_NAME_INFORMATION { + + typedef struct __OBJECT_TYPE_INFORMATION { + UNICODE_STRING TypeName; +- ULONG Reserved [22]; ++ ULONG TotalNumberOfObjects; ++ ULONG TotalNumberOfHandles; ++ ULONG TotalPagedPoolUsage; ++ ULONG TotalNonPagedPoolUsage; ++ ULONG TotalNamePoolUsage; ++ ULONG TotalHandleTableUsage; ++ ULONG HighWaterNumberOfObjects; ++ ULONG HighWaterNumberOfHandles; ++ ULONG HighWaterPagedPoolUsage; ++ ULONG HighWaterNonPagedPoolUsage; ++ ULONG HighWaterNamePoolUsage; ++ ULONG HighWaterHandleTableUsage; ++ ULONG InvalidAttributes; ++ GENERIC_MAPPING GenericMapping; ++ ULONG ValidAccessMask; ++ BOOLEAN SecurityRequired; ++ BOOLEAN MaintainHandleCount; ++ UCHAR TypeIndex; ++ CHAR Reserved; ++ ULONG PoolType; ++ ULONG DefaultPagedPoolCharge; ++ ULONG DefaultNonPagedPoolCharge; + } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; + ++typedef struct _OBJECT_TYPES_INFORMATION ++{ ++ ULONG NumberOfTypes; ++} OBJECT_TYPES_INFORMATION, *POBJECT_TYPES_INFORMATION; ++ + typedef struct _PROCESS_BASIC_INFORMATION { + #ifdef __WINESRC__ + DWORD_PTR ExitStatus; +diff --git a/server/directory.c b/server/directory.c +index d903ff283c..ebec63e6c6 100644 +--- a/server/directory.c ++++ b/server/directory.c +@@ -72,6 +72,8 @@ static const struct object_ops object_type_ops = + no_destroy /* destroy */ + }; + ++static struct object_type *object_type_list[64]; ++static unsigned int object_type_count; + + struct directory + { +@@ -238,7 +240,8 @@ struct object_type *get_object_type( const struct unicode_str *name ) + { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) + { +- grab_object( type ); ++ assert( object_type_count < sizeof(object_type_list)/sizeof(object_type_list[0]) ); ++ object_type_list[ object_type_count++ ] = (struct object_type *)grab_object( type ); + make_object_static( &type->obj ); + } + clear_error(); +@@ -531,3 +534,17 @@ DECL_HANDLER(get_object_type) + } + release_object( obj ); + } ++ ++/* query object type name information by index */ ++DECL_HANDLER(get_object_type_by_index) ++{ ++ struct object_type *type; ++ const WCHAR *name; ++ ++ if (req->index < object_type_count && (type = object_type_list[ req->index ])) ++ { ++ if ((name = get_object_name( &type->obj, &reply->total ))) ++ set_reply_data( name, min( reply->total, get_reply_max_size() ) ); ++ } ++ else set_error( STATUS_NO_MORE_ENTRIES ); ++} +diff --git a/server/protocol.def b/server/protocol.def +index 071129723f..98c4c58a4e 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3548,6 +3548,15 @@ struct handle_info + @END + + ++/* Query object type name information */ ++@REQ(get_object_type_by_index) ++ unsigned int index; /* index of the type */ ++@REPLY ++ data_size_t total; /* needed size for type name */ ++ VARARG(type,unicode_str); /* type name */ ++@END ++ ++ + /* Unlink a named object */ + @REQ(unlink_object) + obj_handle_t handle; /* handle to the object */ +-- +2.11.0 + diff --git a/patches/server-Object_Types/0003-server-Register-types-during-startup.patch b/patches/server-Object_Types/0003-server-Register-types-during-startup.patch new file mode 100644 index 00000000..85b05fef --- /dev/null +++ b/patches/server-Object_Types/0003-server-Register-types-during-startup.patch @@ -0,0 +1,342 @@ +From 35a8bfa127fa1195bbb6454a79d8ff1a794ee9d9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Wed, 8 Mar 2017 03:32:43 +0100 +Subject: server: Register types during startup. + +--- + server/completion.c | 3 +-- + server/directory.c | 6 ++---- + server/event.c | 6 ++---- + server/file.c | 3 +-- + server/mailslot.c | 3 +-- + server/main.c | 1 + + server/mapping.c | 3 +-- + server/mutex.c | 3 +-- + server/named_pipe.c | 3 +-- + server/object.c | 36 ++++++++++++++++++++++++++++++++++++ + server/object.h | 21 +++++++++++++++++++++ + server/process.c | 3 +-- + server/registry.c | 3 +-- + server/semaphore.c | 3 +-- + server/symlink.c | 3 +-- + server/timer.c | 3 +-- + server/winstation.c | 6 ++---- + 17 files changed, 75 insertions(+), 34 deletions(-) + +diff --git a/server/completion.c b/server/completion.c +index 72dbc5b821..af4a3f74e1 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -110,8 +110,7 @@ static void completion_dump( struct object *obj, int verbose ) + + static struct object_type *completion_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'I','o','C','o','m','p','l','e','t','i','o','n'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_IoCompletion, sizeof(type_IoCompletion) }; + return get_object_type( &str ); + } + +diff --git a/server/directory.c b/server/directory.c +index ebec63e6c6..98dd2defa3 100644 +--- a/server/directory.c ++++ b/server/directory.c +@@ -121,8 +121,7 @@ static void object_type_dump( struct object *obj, int verbose ) + + static struct object_type *object_type_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'O','b','j','e','c','t','T','y','p','e'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_ObjectType, sizeof(type_ObjectType) }; + return get_object_type( &str ); + } + +@@ -133,8 +132,7 @@ static void directory_dump( struct object *obj, int verbose ) + + static struct object_type *directory_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'D','i','r','e','c','t','o','r','y'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_Directory, sizeof(type_Directory) }; + return get_object_type( &str ); + } + +diff --git a/server/event.c b/server/event.c +index 608fafb94d..04ebda60a5 100644 +--- a/server/event.c ++++ b/server/event.c +@@ -161,8 +161,7 @@ static void event_dump( struct object *obj, int verbose ) + + static struct object_type *event_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'E','v','e','n','t'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_Event, sizeof(type_Event) }; + return get_object_type( &str ); + } + +@@ -231,8 +230,7 @@ static void keyed_event_dump( struct object *obj, int verbose ) + + static struct object_type *keyed_event_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'K','e','y','e','d','E','v','e','n','t'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_KeyedEvent, sizeof(type_KeyedEvent) }; + return get_object_type( &str ); + } + +diff --git a/server/file.c b/server/file.c +index babbcc6a63..5c3ae775b3 100644 +--- a/server/file.c ++++ b/server/file.c +@@ -456,8 +456,7 @@ static void file_dump( struct object *obj, int verbose ) + + static struct object_type *file_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'F','i','l','e'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_File, sizeof(type_File) }; + return get_object_type( &str ); + } + +diff --git a/server/mailslot.c b/server/mailslot.c +index 04c4b9f50c..b69c957595 100644 +--- a/server/mailslot.c ++++ b/server/mailslot.c +@@ -349,8 +349,7 @@ static void mailslot_device_dump( struct object *obj, int verbose ) + + static struct object_type *mailslot_device_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'D','e','v','i','c','e'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ const struct unicode_str str = { type_Device, sizeof(type_Device) }; + return get_object_type( &str ); + } + +diff --git a/server/main.c b/server/main.c +index 313039a308..13af3b9feb 100644 +--- a/server/main.c ++++ b/server/main.c +@@ -148,6 +148,7 @@ int main( int argc, char *argv[] ) + init_directories(); + init_registry(); + init_shared_memory(); ++ init_types(); + main_loop(); + return 0; + } +diff --git a/server/mapping.c b/server/mapping.c +index 44fbe63793..9691dd832c 100644 +--- a/server/mapping.c ++++ b/server/mapping.c +@@ -728,8 +728,7 @@ static void mapping_dump( struct object *obj, int verbose ) + + static struct object_type *mapping_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'S','e','c','t','i','o','n'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_Section, sizeof(type_Section) }; + return get_object_type( &str ); + } + +diff --git a/server/mutex.c b/server/mutex.c +index a2a0a24bdc..7ca41316ab 100644 +--- a/server/mutex.c ++++ b/server/mutex.c +@@ -142,8 +142,7 @@ static void mutex_dump( struct object *obj, int verbose ) + + static struct object_type *mutex_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'M','u','t','a','n','t'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_Mutant, sizeof(type_Mutant) }; + return get_object_type( &str ); + } + +diff --git a/server/named_pipe.c b/server/named_pipe.c +index bc4b6f08fd..e3ebb4571e 100644 +--- a/server/named_pipe.c ++++ b/server/named_pipe.c +@@ -524,8 +524,7 @@ static void named_pipe_device_dump( struct object *obj, int verbose ) + + static struct object_type *named_pipe_device_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'D','e','v','i','c','e'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ const struct unicode_str str = { type_Device, sizeof(type_Device) }; + return get_object_type( &str ); + } + +diff --git a/server/object.c b/server/object.c +index 7281ef82ec..e6d20196a9 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -710,3 +710,39 @@ int no_close_handle( struct object *obj, struct process *process, obj_handle_t h + void no_destroy( struct object *obj ) + { + } ++ ++static const struct unicode_str type_array[] = ++{ ++ {type_ObjectType, sizeof(type_ObjectType)}, ++ {type_Directory, sizeof(type_Directory)}, ++ {type_SymbolicLink, sizeof(type_SymbolicLink)}, ++ /* Token */ ++ {type_Job, sizeof(type_Job)}, ++ /* Process */ ++ /* Thread */ ++ {type_Event, sizeof(type_Event)}, ++ {type_Mutant, sizeof(type_Mutant)}, ++ {type_Semaphore, sizeof(type_Semaphore)}, ++ {type_Timer, sizeof(type_Timer)}, ++ {type_KeyedEvent, sizeof(type_KeyedEvent)}, ++ {type_WindowStation, sizeof(type_WindowStation)}, ++ {type_Desktop, sizeof(type_Desktop)}, ++ {type_Device, sizeof(type_Device)}, ++ /* Driver */ ++ {type_IoCompletion, sizeof(type_IoCompletion)}, ++ {type_File, sizeof(type_File)}, ++ {type_Section, sizeof(type_Section)}, ++ {type_Key, sizeof(type_Key)}, ++}; ++ ++void init_types(void) ++{ ++ struct object_type *type; ++ unsigned int i; ++ ++ for (i = 0; i < sizeof(type_array) / sizeof(type_array[0]); i++) ++ { ++ type = get_object_type(&type_array[i]); ++ if (type) release_object(type); ++ } ++} +diff --git a/server/object.h b/server/object.h +index 498186bc92..be71c705c5 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -241,6 +241,27 @@ extern struct object_type *get_object_type( const struct unicode_str *name ); + extern int directory_link_name( struct object *obj, struct object_name *name, struct object *parent ); + extern void init_directories(void); + ++/* type functions */ ++ ++static const WCHAR type_Desktop[] = {'D','e','s','k','t','o','p'}; ++static const WCHAR type_Device[] = {'D','e','v','i','c','e'}; ++static const WCHAR type_Directory[] = {'D','i','r','e','c','t','o','r','y'}; ++static const WCHAR type_Event[] = {'E','v','e','n','t'}; ++static const WCHAR type_File[] = {'F','i','l','e'}; ++static const WCHAR type_IoCompletion[] = {'I','o','C','o','m','p','l','e','t','i','o','n'}; ++static const WCHAR type_Job[] = {'J','o','b'}; ++static const WCHAR type_Key[] = {'K','e','y'}; ++static const WCHAR type_KeyedEvent[] = {'K','e','y','e','d','E','v','e','n','t'}; ++static const WCHAR type_Mutant[] = {'M','u','t','a','n','t'}; ++static const WCHAR type_ObjectType[] = {'O','b','j','e','c','t','T','y','p','e'}; ++static const WCHAR type_Section[] = {'S','e','c','t','i','o','n'}; ++static const WCHAR type_Semaphore[] = {'S','e','m','a','p','h','o','r','e'}; ++static const WCHAR type_SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k'}; ++static const WCHAR type_Timer[] = {'T','i','m','e','r'}; ++static const WCHAR type_WindowStation[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n'}; ++ ++extern void init_types(void); ++ + /* symbolic link functions */ + + extern struct object *create_obj_symlink( struct object *root, const struct unicode_str *name, +diff --git a/server/process.c b/server/process.c +index a59be6cfad..df1e9f1b0d 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -214,8 +214,7 @@ static struct job *get_job_obj( struct process *process, obj_handle_t handle, un + + static struct object_type *job_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'J','o','b'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_Job, sizeof(type_Job) }; + return get_object_type( &str ); + }; + +diff --git a/server/registry.c b/server/registry.c +index 368a56abcf..3a45f4f081 100644 +--- a/server/registry.c ++++ b/server/registry.c +@@ -314,8 +314,7 @@ static void key_dump( struct object *obj, int verbose ) + + static struct object_type *key_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'K','e','y'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_Key, sizeof(type_Key) }; + return get_object_type( &str ); + } + +diff --git a/server/semaphore.c b/server/semaphore.c +index 15e7392513..60940aaa76 100644 +--- a/server/semaphore.c ++++ b/server/semaphore.c +@@ -128,8 +128,7 @@ static void semaphore_dump( struct object *obj, int verbose ) + + static struct object_type *semaphore_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'S','e','m','a','p','h','o','r','e'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_Semaphore, sizeof(type_Semaphore) }; + return get_object_type( &str ); + } + +diff --git a/server/symlink.c b/server/symlink.c +index ecc0e4300c..33efdaa699 100644 +--- a/server/symlink.c ++++ b/server/symlink.c +@@ -87,8 +87,7 @@ static void symlink_dump( struct object *obj, int verbose ) + + static struct object_type *symlink_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'S','y','m','b','o','l','i','c','L','i','n','k'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_SymbolicLink, sizeof(type_SymbolicLink) }; + return get_object_type( &str ); + } + +diff --git a/server/timer.c b/server/timer.c +index 23c613b3cb..cb686b90f9 100644 +--- a/server/timer.c ++++ b/server/timer.c +@@ -190,8 +190,7 @@ static void timer_dump( struct object *obj, int verbose ) + + static struct object_type *timer_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'T','i','m','e','r'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_Timer, sizeof(type_Timer) }; + return get_object_type( &str ); + } + +diff --git a/server/winstation.c b/server/winstation.c +index 39131d538e..d449ec667d 100644 +--- a/server/winstation.c ++++ b/server/winstation.c +@@ -166,8 +166,7 @@ static void winstation_dump( struct object *obj, int verbose ) + + static struct object_type *winstation_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_WindowStation, sizeof(type_WindowStation) }; + return get_object_type( &str ); + } + +@@ -271,8 +270,7 @@ static void desktop_dump( struct object *obj, int verbose ) + + static struct object_type *desktop_get_type( struct object *obj ) + { +- static const WCHAR name[] = {'D','e','s','k','t','o','p'}; +- static const struct unicode_str str = { name, sizeof(name) }; ++ static const struct unicode_str str = { type_Desktop, sizeof(type_Desktop) }; + return get_object_type( &str ); + } + +-- +2.11.0 + diff --git a/patches/server-Object_Types/0004-server-Rename-ObjectType-to-Type.patch b/patches/server-Object_Types/0004-server-Rename-ObjectType-to-Type.patch new file mode 100644 index 00000000..8d2eeed3 --- /dev/null +++ b/patches/server-Object_Types/0004-server-Rename-ObjectType-to-Type.patch @@ -0,0 +1,71 @@ +From 0498c01e0c379ccf5874b07fbbf3ec86b34f97ad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Wed, 8 Mar 2017 03:44:19 +0100 +Subject: server: Rename ObjectType to Type. + +--- + dlls/ntdll/tests/om.c | 2 +- + server/directory.c | 2 +- + server/object.c | 2 +- + server/object.h | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c +index 534cb514f9..02d83016e2 100644 +--- a/dlls/ntdll/tests/om.c ++++ b/dlls/ntdll/tests/om.c +@@ -1570,7 +1570,7 @@ static void test_query_object_types(void) + + if (i == 0) + { +- todo_wine ok( type->TypeName.Length == sizeof(typeW) && !strncmpW(typeW, type->TypeName.Buffer, 4), ++ ok( type->TypeName.Length == sizeof(typeW) && !strncmpW(typeW, type->TypeName.Buffer, 4), + "Expected 'Type' as first type, got %s\n", wine_dbgstr_us(&type->TypeName) ); + } + +diff --git a/server/directory.c b/server/directory.c +index 98dd2defa3..b4f53e2edf 100644 +--- a/server/directory.c ++++ b/server/directory.c +@@ -121,7 +121,7 @@ static void object_type_dump( struct object *obj, int verbose ) + + static struct object_type *object_type_get_type( struct object *obj ) + { +- static const struct unicode_str str = { type_ObjectType, sizeof(type_ObjectType) }; ++ static const struct unicode_str str = { type_Type, sizeof(type_Type) }; + return get_object_type( &str ); + } + +diff --git a/server/object.c b/server/object.c +index e6d20196a9..960422df1c 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -713,7 +713,7 @@ void no_destroy( struct object *obj ) + + static const struct unicode_str type_array[] = + { +- {type_ObjectType, sizeof(type_ObjectType)}, ++ {type_Type, sizeof(type_Type)}, + {type_Directory, sizeof(type_Directory)}, + {type_SymbolicLink, sizeof(type_SymbolicLink)}, + /* Token */ +diff --git a/server/object.h b/server/object.h +index be71c705c5..0ed46b159d 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -253,11 +253,11 @@ static const WCHAR type_Job[] = {'J','o','b'}; + static const WCHAR type_Key[] = {'K','e','y'}; + static const WCHAR type_KeyedEvent[] = {'K','e','y','e','d','E','v','e','n','t'}; + static const WCHAR type_Mutant[] = {'M','u','t','a','n','t'}; +-static const WCHAR type_ObjectType[] = {'O','b','j','e','c','t','T','y','p','e'}; + static const WCHAR type_Section[] = {'S','e','c','t','i','o','n'}; + static const WCHAR type_Semaphore[] = {'S','e','m','a','p','h','o','r','e'}; + static const WCHAR type_SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k'}; + static const WCHAR type_Timer[] = {'T','i','m','e','r'}; ++static const WCHAR type_Type[] = {'T','y','p','e'}; + static const WCHAR type_WindowStation[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n'}; + + extern void init_types(void); +-- +2.11.0 + diff --git a/patches/server-Object_Types/0005-server-Add-type-Token.patch b/patches/server-Object_Types/0005-server-Add-type-Token.patch new file mode 100644 index 00000000..04f4ee89 --- /dev/null +++ b/patches/server-Object_Types/0005-server-Add-type-Token.patch @@ -0,0 +1,73 @@ +From b4ba31df8d342f736a590977ba950d6f07f2377c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Wed, 8 Mar 2017 03:48:02 +0100 +Subject: server: Add type Token. + +--- + server/object.c | 2 +- + server/object.h | 1 + + server/token.c | 9 ++++++++- + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/server/object.c b/server/object.c +index 960422df1c..c2c877f692 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -716,7 +716,7 @@ static const struct unicode_str type_array[] = + {type_Type, sizeof(type_Type)}, + {type_Directory, sizeof(type_Directory)}, + {type_SymbolicLink, sizeof(type_SymbolicLink)}, +- /* Token */ ++ {type_Token, sizeof(type_Token)}, + {type_Job, sizeof(type_Job)}, + /* Process */ + /* Thread */ +diff --git a/server/object.h b/server/object.h +index 0ed46b159d..46a9f770ca 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -257,6 +257,7 @@ static const WCHAR type_Section[] = {'S','e','c','t','i','o','n'}; + static const WCHAR type_Semaphore[] = {'S','e','m','a','p','h','o','r','e'}; + static const WCHAR type_SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k'}; + static const WCHAR type_Timer[] = {'T','i','m','e','r'}; ++static const WCHAR type_Token[] = {'T','o','k','e','n'}; + static const WCHAR type_Type[] = {'T','y','p','e'}; + static const WCHAR type_WindowStation[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n'}; + +diff --git a/server/token.c b/server/token.c +index 3b5c498147..f0afb95868 100644 +--- a/server/token.c ++++ b/server/token.c +@@ -150,6 +150,7 @@ struct group + }; + + static void token_dump( struct object *obj, int verbose ); ++static struct object_type *token_get_type( struct object *obj ); + static unsigned int token_map_access( struct object *obj, unsigned int access ); + static void token_destroy( struct object *obj ); + +@@ -157,7 +158,7 @@ static const struct object_ops token_ops = + { + sizeof(struct token), /* size */ + token_dump, /* dump */ +- no_get_type, /* get_type */ ++ token_get_type, /* get_type */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ +@@ -183,6 +184,12 @@ static void token_dump( struct object *obj, int verbose ) + /* FIXME: dump token members */ + } + ++static struct object_type *token_get_type( struct object *obj ) ++{ ++ static const struct unicode_str str = { type_Token, sizeof(type_Token) }; ++ return get_object_type( &str ); ++} ++ + static unsigned int token_map_access( struct object *obj, unsigned int access ) + { + if (access & GENERIC_READ) access |= TOKEN_READ; +-- +2.11.0 + diff --git a/patches/server-Object_Types/0006-server-Add-type-Process.patch b/patches/server-Object_Types/0006-server-Add-type-Process.patch new file mode 100644 index 00000000..25b08c58 --- /dev/null +++ b/patches/server-Object_Types/0006-server-Add-type-Process.patch @@ -0,0 +1,73 @@ +From 97057ab129833bd9fdcf683e05a44c0d06330edd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Wed, 8 Mar 2017 03:52:47 +0100 +Subject: server: Add type Process. + +--- + server/object.c | 2 +- + server/object.h | 1 + + server/process.c | 9 ++++++++- + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/server/object.c b/server/object.c +index c2c877f692..f7c249689f 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -718,7 +718,7 @@ static const struct unicode_str type_array[] = + {type_SymbolicLink, sizeof(type_SymbolicLink)}, + {type_Token, sizeof(type_Token)}, + {type_Job, sizeof(type_Job)}, +- /* Process */ ++ {type_Process, sizeof(type_Process)}, + /* Thread */ + {type_Event, sizeof(type_Event)}, + {type_Mutant, sizeof(type_Mutant)}, +diff --git a/server/object.h b/server/object.h +index 46a9f770ca..cca12b6cf0 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -253,6 +253,7 @@ static const WCHAR type_Job[] = {'J','o','b'}; + static const WCHAR type_Key[] = {'K','e','y'}; + static const WCHAR type_KeyedEvent[] = {'K','e','y','e','d','E','v','e','n','t'}; + static const WCHAR type_Mutant[] = {'M','u','t','a','n','t'}; ++static const WCHAR type_Process[] = {'P','r','o','c','e','s','s'}; + static const WCHAR type_Section[] = {'S','e','c','t','i','o','n'}; + static const WCHAR type_Semaphore[] = {'S','e','m','a','p','h','o','r','e'}; + static const WCHAR type_SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k'}; +diff --git a/server/process.c b/server/process.c +index df1e9f1b0d..de3e926717 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -60,6 +60,7 @@ static int shutdown_stage; /* current stage in the shutdown process */ + /* process operations */ + + static void process_dump( struct object *obj, int verbose ); ++static struct object_type *process_get_type( struct object *obj ); + static int process_signaled( struct object *obj, struct wait_queue_entry *entry ); + static unsigned int process_map_access( struct object *obj, unsigned int access ); + static struct security_descriptor *process_get_sd( struct object *obj ); +@@ -71,7 +72,7 @@ static const struct object_ops process_ops = + { + sizeof(struct process), /* size */ + process_dump, /* dump */ +- no_get_type, /* get_type */ ++ process_get_type, /* get_type */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + process_signaled, /* signaled */ +@@ -655,6 +656,12 @@ static void process_dump( struct object *obj, int verbose ) + fprintf( stderr, "Process id=%04x handles=%p\n", process->id, process->handles ); + } + ++static struct object_type *process_get_type( struct object *obj ) ++{ ++ static const struct unicode_str str = { type_Process, sizeof(type_Process) }; ++ return get_object_type( &str ); ++} ++ + static int process_signaled( struct object *obj, struct wait_queue_entry *entry ) + { + struct process *process = (struct process *)obj; +-- +2.11.0 + diff --git a/patches/server-Object_Types/0007-server-Add-type-Thread.patch b/patches/server-Object_Types/0007-server-Add-type-Thread.patch new file mode 100644 index 00000000..52e7d062 --- /dev/null +++ b/patches/server-Object_Types/0007-server-Add-type-Thread.patch @@ -0,0 +1,73 @@ +From ef0142aadbcbd3e36ff3e2473dca76e68ba5ecba Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Wed, 8 Mar 2017 03:56:00 +0100 +Subject: server: Add type Thread. + +--- + server/object.c | 2 +- + server/object.h | 1 + + server/thread.c | 9 ++++++++- + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/server/object.c b/server/object.c +index f7c249689f..37ac0adce6 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -719,7 +719,7 @@ static const struct unicode_str type_array[] = + {type_Token, sizeof(type_Token)}, + {type_Job, sizeof(type_Job)}, + {type_Process, sizeof(type_Process)}, +- /* Thread */ ++ {type_Thread, sizeof(type_Thread)}, + {type_Event, sizeof(type_Event)}, + {type_Mutant, sizeof(type_Mutant)}, + {type_Semaphore, sizeof(type_Semaphore)}, +diff --git a/server/object.h b/server/object.h +index cca12b6cf0..3ba3f4b431 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -257,6 +257,7 @@ static const WCHAR type_Process[] = {'P','r','o','c','e','s','s'}; + static const WCHAR type_Section[] = {'S','e','c','t','i','o','n'}; + static const WCHAR type_Semaphore[] = {'S','e','m','a','p','h','o','r','e'}; + static const WCHAR type_SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k'}; ++static const WCHAR type_Thread[] = {'T','h','r','e','a','d'}; + static const WCHAR type_Timer[] = {'T','i','m','e','r'}; + static const WCHAR type_Token[] = {'T','o','k','e','n'}; + static const WCHAR type_Type[] = {'T','y','p','e'}; +diff --git a/server/thread.c b/server/thread.c +index 53e94fda42..108444ebc5 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -129,6 +129,7 @@ static const struct object_ops thread_apc_ops = + /* thread operations */ + + static void dump_thread( struct object *obj, int verbose ); ++static struct object_type *thread_get_type( struct object *obj ); + static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ); + static unsigned int thread_map_access( struct object *obj, unsigned int access ); + static void thread_poll_event( struct fd *fd, int event ); +@@ -138,7 +139,7 @@ static const struct object_ops thread_ops = + { + sizeof(struct thread), /* size */ + dump_thread, /* dump */ +- no_get_type, /* get_type */ ++ thread_get_type, /* get_type */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + thread_signaled, /* signaled */ +@@ -344,6 +345,12 @@ static void dump_thread( struct object *obj, int verbose ) + thread->id, thread->unix_pid, thread->unix_tid, thread->state ); + } + ++static struct object_type *thread_get_type( struct object *obj ) ++{ ++ static const struct unicode_str str = { type_Thread, sizeof(type_Thread) }; ++ return get_object_type( &str ); ++} ++ + static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ) + { + struct thread *mythread = (struct thread *)obj; +-- +2.11.0 + diff --git a/patches/server-Object_Types/0008-ntdll-Set-TypeIndex-for-ObjectTypeInformation-in-NtQ.patch b/patches/server-Object_Types/0008-ntdll-Set-TypeIndex-for-ObjectTypeInformation-in-NtQ.patch new file mode 100644 index 00000000..feb7ddfc --- /dev/null +++ b/patches/server-Object_Types/0008-ntdll-Set-TypeIndex-for-ObjectTypeInformation-in-NtQ.patch @@ -0,0 +1,71 @@ +From 1e3e93483b223c6e0e9d712fff4a8874c503c973 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Wed, 8 Mar 2017 17:41:11 +0100 +Subject: ntdll: Set TypeIndex for ObjectTypeInformation in NtQueryObject. + +--- + dlls/ntdll/om.c | 4 ++++ + server/directory.c | 5 ++++- + server/protocol.def | 1 + + 3 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c +index 8911a28b20..8f54d4f49f 100644 +--- a/dlls/ntdll/om.c ++++ b/dlls/ntdll/om.c +@@ -184,6 +184,10 @@ NTSTATUS WINAPI NtQueryObject(IN HANDLE handle, + p->TypeName.Buffer[res / sizeof(WCHAR)] = 0; + if (used_len) *used_len = sizeof(*p) + p->TypeName.MaximumLength; + } ++ if (status == STATUS_SUCCESS) ++ { ++ p->TypeIndex = reply->index; ++ } + } + } + SERVER_END_REQ; +diff --git a/server/directory.c b/server/directory.c +index b4f53e2edf..59c8194d09 100644 +--- a/server/directory.c ++++ b/server/directory.c +@@ -44,6 +44,7 @@ + struct object_type + { + struct object obj; /* object header */ ++ unsigned int index; /* type index */ + }; + + static void object_type_dump( struct object *obj, int verbose ); +@@ -239,7 +240,8 @@ struct object_type *get_object_type( const struct unicode_str *name ) + if (get_error() != STATUS_OBJECT_NAME_EXISTS) + { + assert( object_type_count < sizeof(object_type_list)/sizeof(object_type_list[0]) ); +- object_type_list[ object_type_count++ ] = (struct object_type *)grab_object( type ); ++ type->index = object_type_count++; ++ object_type_list[ type->index ] = (struct object_type *)grab_object( type ); + make_object_static( &type->obj ); + } + clear_error(); +@@ -528,6 +530,7 @@ DECL_HANDLER(get_object_type) + { + if ((name = get_object_name( &type->obj, &reply->total ))) + set_reply_data( name, min( reply->total, get_reply_max_size() ) ); ++ reply->index = type->index; + release_object( type ); + } + release_object( obj ); +diff --git a/server/protocol.def b/server/protocol.def +index 98c4c58a4e..d6847f8d55 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3543,6 +3543,7 @@ struct handle_info + @REQ(get_object_type) + obj_handle_t handle; /* handle to the object */ + @REPLY ++ unsigned int index; /* type index */ + data_size_t total; /* needed size for type name */ + VARARG(type,unicode_str); /* type name */ + @END +-- +2.11.0 + diff --git a/patches/server-Object_Types/0009-ntdll-Set-object-type-for-System-Extended-HandleInfo.patch b/patches/server-Object_Types/0009-ntdll-Set-object-type-for-System-Extended-HandleInfo.patch new file mode 100644 index 00000000..72db5626 --- /dev/null +++ b/patches/server-Object_Types/0009-ntdll-Set-object-type-for-System-Extended-HandleInfo.patch @@ -0,0 +1,108 @@ +From ba10e334a375c7dde7cd890554fbbade1be81a9d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Wed, 8 Mar 2017 17:44:17 +0100 +Subject: ntdll: Set object type for System(Extended)HandleInformation in + NtQuerySystemInformation. + +--- + dlls/ntdll/nt.c | 4 +++- + server/directory.c | 6 ++++++ + server/handle.c | 10 ++++++++++ + server/object.h | 1 + + server/protocol.def | 1 + + 5 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c +index a939298d19..211b67f98b 100644 +--- a/dlls/ntdll/nt.c ++++ b/dlls/ntdll/nt.c +@@ -2280,7 +2280,8 @@ NTSTATUS WINAPI NtQuerySystemInformation( + shi->Handle[i].OwnerPid = info[i].owner; + shi->Handle[i].HandleValue = info[i].handle; + shi->Handle[i].AccessMask = info[i].access; +- /* FIXME: Fill out ObjectType, HandleFlags, ObjectPointer */ ++ shi->Handle[i].ObjectType = info[i].type; ++ /* FIXME: Fill out HandleFlags, ObjectPointer */ + } + } + else if (ret == STATUS_BUFFER_TOO_SMALL) +@@ -2331,6 +2332,7 @@ NTSTATUS WINAPI NtQuerySystemInformation( + shi->Handle[i].UniqueProcessId = info[i].owner; + shi->Handle[i].HandleValue = info[i].handle; + shi->Handle[i].GrantedAccess = info[i].access; ++ shi->Handle[i].ObjectTypeIndex = info[i].type; + /* FIXME: Fill out remaining fields */ + } + } +diff --git a/server/directory.c b/server/directory.c +index 59c8194d09..f61a5cecf1 100644 +--- a/server/directory.c ++++ b/server/directory.c +@@ -249,6 +249,12 @@ struct object_type *get_object_type( const struct unicode_str *name ) + return type; + } + ++/* retrieve the object type index */ ++unsigned int type_get_index( struct object_type *type ) ++{ ++ return type->index; ++} ++ + /* Global initialization */ + + static void create_session( unsigned int id ) +diff --git a/server/handle.c b/server/handle.c +index 0e909ff27e..e29cead46b 100644 +--- a/server/handle.c ++++ b/server/handle.c +@@ -971,6 +971,7 @@ static int enum_handles( struct process *process, void *user ) + struct handle_table *table = process->handles; + struct handle_entry *entry; + struct handle_info *handle; ++ struct object_type *type; + unsigned int i; + + if (!table) +@@ -989,6 +990,15 @@ static int enum_handles( struct process *process, void *user ) + handle->owner = process->id; + handle->handle = index_to_handle(i); + handle->access = entry->access & ~RESERVED_ALL; ++ ++ if ((type = entry->ptr->ops->get_type(entry->ptr))) ++ { ++ handle->type = type_get_index(type); ++ release_object(type); ++ } ++ else ++ handle->type = 0; ++ + info->count--; + } + +diff --git a/server/object.h b/server/object.h +index 3ba3f4b431..4a5d282a47 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -264,6 +264,7 @@ static const WCHAR type_Type[] = {'T','y','p','e'}; + static const WCHAR type_WindowStation[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n'}; + + extern void init_types(void); ++extern unsigned int type_get_index( struct object_type *type ); + + /* symbolic link functions */ + +diff --git a/server/protocol.def b/server/protocol.def +index d6847f8d55..35730d60cb 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3433,6 +3433,7 @@ struct handle_info + process_id_t owner; + obj_handle_t handle; + unsigned int access; ++ unsigned int type; + }; + + /* Return a list of all opened handles */ +-- +2.11.0 + diff --git a/patches/server-Object_Types/0010-ntdll-Mimic-object-type-behavior-for-different-windo.patch b/patches/server-Object_Types/0010-ntdll-Mimic-object-type-behavior-for-different-windo.patch new file mode 100644 index 00000000..826096ab --- /dev/null +++ b/patches/server-Object_Types/0010-ntdll-Mimic-object-type-behavior-for-different-windo.patch @@ -0,0 +1,180 @@ +From c157e1ed4e1a3f373471bb49f1a8c536ea0ce2cc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Wed, 8 Mar 2017 19:39:29 +0100 +Subject: ntdll: Mimic object type behavior for different windows versions. + +--- + dlls/ntdll/nt.c | 17 ++++++++++++-- + dlls/ntdll/om.c | 5 +++- + dlls/ntdll/tests/om.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 83 insertions(+), 4 deletions(-) + +diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c +index 211b67f98b..1dd890c4bd 100644 +--- a/dlls/ntdll/nt.c ++++ b/dlls/ntdll/nt.c +@@ -70,6 +70,19 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(ntdll); + ++static DWORD translate_object_index(DWORD index) ++{ ++ WORD version = MAKEWORD(NtCurrentTeb()->Peb->OSMinorVersion, NtCurrentTeb()->Peb->OSMajorVersion); ++ ++ /* Process Hacker depends on this logic */ ++ if (version >= 0x0602) ++ return index; ++ else if (version == 0x0601) ++ return index + 2; ++ else ++ return index + 1; ++} ++ + /* + * Token + */ +@@ -2280,7 +2293,7 @@ NTSTATUS WINAPI NtQuerySystemInformation( + shi->Handle[i].OwnerPid = info[i].owner; + shi->Handle[i].HandleValue = info[i].handle; + shi->Handle[i].AccessMask = info[i].access; +- shi->Handle[i].ObjectType = info[i].type; ++ shi->Handle[i].ObjectType = translate_object_index(info[i].type); + /* FIXME: Fill out HandleFlags, ObjectPointer */ + } + } +@@ -2332,7 +2345,7 @@ NTSTATUS WINAPI NtQuerySystemInformation( + shi->Handle[i].UniqueProcessId = info[i].owner; + shi->Handle[i].HandleValue = info[i].handle; + shi->Handle[i].GrantedAccess = info[i].access; +- shi->Handle[i].ObjectTypeIndex = info[i].type; ++ shi->Handle[i].ObjectTypeIndex = translate_object_index(info[i].type); + /* FIXME: Fill out remaining fields */ + } + } +diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c +index 8f54d4f49f..92fc654448 100644 +--- a/dlls/ntdll/om.c ++++ b/dlls/ntdll/om.c +@@ -186,7 +186,10 @@ NTSTATUS WINAPI NtQueryObject(IN HANDLE handle, + } + if (status == STATUS_SUCCESS) + { +- p->TypeIndex = reply->index; ++ WORD version = MAKEWORD(NtCurrentTeb()->Peb->OSMinorVersion, ++ NtCurrentTeb()->Peb->OSMajorVersion); ++ if (version >= 0x0602) ++ p->TypeIndex = reply->index; + } + } + } +diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c +index 02d83016e2..84b783b80a 100644 +--- a/dlls/ntdll/tests/om.c ++++ b/dlls/ntdll/tests/om.c +@@ -69,6 +69,7 @@ static NTSTATUS (WINAPI *pNtWaitForKeyedEvent)( HANDLE, const void *, BOOLEAN, c + static NTSTATUS (WINAPI *pNtReleaseKeyedEvent)( HANDLE, const void *, BOOLEAN, const LARGE_INTEGER * ); + static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); + static NTSTATUS (WINAPI *pNtOpenIoCompletion)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); ++static NTSTATUS (WINAPI *pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); + + #define KEYEDEVENT_WAIT 0x0001 + #define KEYEDEVENT_WAKE 0x0002 +@@ -1539,13 +1540,31 @@ static void test_query_object(void) + pRtlFreeUnicodeString( &session ); + } + ++static BOOL winver_equal_or_newer(WORD major, WORD minor) ++{ ++ OSVERSIONINFOEXW info = {sizeof(info)}; ++ ULONGLONG mask = 0; ++ ++ info.dwMajorVersion = major; ++ info.dwMinorVersion = minor; ++ ++ VER_SET_CONDITION(mask, VER_MAJORVERSION, VER_GREATER_EQUAL); ++ VER_SET_CONDITION(mask, VER_MINORVERSION, VER_GREATER_EQUAL); ++ ++ return VerifyVersionInfoW(&info, VER_MAJORVERSION | VER_MINORVERSION, mask); ++} ++ + static void test_query_object_types(void) + { + static const WCHAR typeW[] = {'T','y','p','e'}; ++ static const WCHAR eventW[] = {'E','v','e','n','t'}; ++ SYSTEM_HANDLE_INFORMATION_EX *shi; + OBJECT_TYPES_INFORMATION *buffer; + OBJECT_TYPE_INFORMATION *type; + NTSTATUS status; +- ULONG len, i; ++ HANDLE handle; ++ BOOL found; ++ ULONG len, i, event_type_index = 0; + + buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(OBJECT_TYPES_INFORMATION) ); + ok( buffer != NULL, "Failed to allocate memory\n" ); +@@ -1573,11 +1592,54 @@ static void test_query_object_types(void) + ok( type->TypeName.Length == sizeof(typeW) && !strncmpW(typeW, type->TypeName.Buffer, 4), + "Expected 'Type' as first type, got %s\n", wine_dbgstr_us(&type->TypeName) ); + } ++ if (type->TypeName.Length == sizeof(eventW) && !strncmpW(eventW, type->TypeName.Buffer, 5)) ++ { ++ if (winver_equal_or_newer( 6, 2 )) ++ event_type_index = type->TypeIndex; ++ else ++ event_type_index = winver_equal_or_newer( 6, 1 ) ? i + 2 : i + 1; ++ } + + type = (OBJECT_TYPE_INFORMATION *)ROUND_UP( (DWORD_PTR)(type + 1) + length, sizeof(DWORD_PTR) ); + } + + HeapFree( GetProcessHeap(), 0, buffer ); ++ ++ ok( event_type_index, "Could not find object type for events\n" ); ++ ++ handle = CreateEventA( NULL, FALSE, FALSE, NULL ); ++ ok( handle != NULL, "Failed to create event\n" ); ++ ++ shi = HeapAlloc( GetProcessHeap(), 0, sizeof(*shi) ); ++ ok( shi != NULL, "Failed to allocate memory\n" ); ++ ++ status = pNtQuerySystemInformation( SystemExtendedHandleInformation, shi, sizeof(*shi), &len ); ++ ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status ); ++ ++ shi = HeapReAlloc( GetProcessHeap(), 0, shi, len ); ++ ok( shi != NULL, "Failed to allocate memory\n" ); ++ ++ status = pNtQuerySystemInformation( SystemExtendedHandleInformation, shi, len, &len ); ++ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status ); ++ ++ found = FALSE; ++ for (i = 0; i < shi->Count; i++) ++ { ++ if (shi->Handle[i].UniqueProcessId != GetCurrentProcessId()) ++ continue; ++ if ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue != handle) ++ continue; ++ ++ ok( shi->Handle[i].ObjectTypeIndex == event_type_index, "Event type does not match: %u vs %u\n", ++ shi->Handle[i].ObjectTypeIndex, event_type_index ); ++ ++ found = TRUE; ++ break; ++ } ++ ok( found, "Expected to find event handle %p (pid %x) in handle list\n", handle, GetCurrentProcessId() ); ++ ++ HeapFree( GetProcessHeap(), 0, shi ); ++ CloseHandle( handle ); + } + + static void test_type_mismatch(void) +@@ -2084,6 +2146,7 @@ START_TEST(om) + pNtReleaseKeyedEvent = (void *)GetProcAddress(hntdll, "NtReleaseKeyedEvent"); + pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion"); + pNtOpenIoCompletion = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion"); ++ pNtQuerySystemInformation = (void *)GetProcAddress(hntdll, "NtQuerySystemInformation"); + + test_case_sensitive(); + test_namespace_pipe(); +-- +2.11.0 + diff --git a/patches/server-Object_Types/definition b/patches/server-Object_Types/definition new file mode 100644 index 00000000..f42c481d --- /dev/null +++ b/patches/server-Object_Types/definition @@ -0,0 +1,3 @@ +Fixes: Implement querying for object types and their indices +Depends: server-Shared_Memory +Depends: server-Misc_ACL