[PATCH] ntdll: Implement NtGetNextProcess().

Nikolay Sivov nsivov at codeweavers.com
Fri Oct 2 08:05:49 CDT 2020


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45119
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/ntdll/ntdll.spec          |  1 +
 dlls/ntdll/tests/om.c          | 28 +++++++++++++++++++++++
 dlls/ntdll/unix/process.c      | 20 +++++++++++++++++
 include/wine/server_protocol.h | 23 ++++++++++++++++++-
 server/process.c               | 41 ++++++++++++++++++++++++++++++++++
 server/protocol.def            | 11 +++++++++
 server/request.h               |  9 ++++++++
 server/trace.c                 | 16 +++++++++++++
 8 files changed, 148 insertions(+), 1 deletion(-)

diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index ce9f6281d5d..701fab0ade8 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -222,6 +222,7 @@
 @ stdcall -norelay -syscall NtGetContextThread(long ptr)
 @ stdcall -syscall NtGetCurrentProcessorNumber()
 # @ stub NtGetDevicePowerState
+@ stdcall -syscall NtGetNextProcess(long long long long ptr)
 @ stdcall NtGetNlsSectionPtr(long long long ptr ptr)
 @ stub NtGetPlugPlayEvent
 @ stdcall NtGetTickCount()
diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c
index d3b932bec1d..6c43ee27823 100644
--- a/dlls/ntdll/tests/om.c
+++ b/dlls/ntdll/tests/om.c
@@ -73,6 +73,7 @@ static NTSTATUS (WINAPI *pNtQuerySystemTime)( LARGE_INTEGER * );
 static NTSTATUS (WINAPI *pRtlWaitOnAddress)( const void *, const void *, SIZE_T, const LARGE_INTEGER * );
 static void     (WINAPI *pRtlWakeAddressAll)( const void * );
 static void     (WINAPI *pRtlWakeAddressSingle)( const void * );
+static NTSTATUS (WINAPI *pNtGetNextProcess)(HANDLE process, ACCESS_MASK access, ULONG attributes, ULONG flags, HANDLE *handle);
 
 #define KEYEDEVENT_WAIT       0x0001
 #define KEYEDEVENT_WAKE       0x0002
@@ -2034,6 +2035,31 @@ static void test_wait_on_address(void)
     ok(address == 0, "got %s\n", wine_dbgstr_longlong(address));
 }
 
+static void test_get_next_process(void)
+{
+    NTSTATUS status;
+    HANDLE handle;
+
+    if (!pNtGetNextProcess)
+    {
+        win_skip("NtGetNextProcess is not available.\n");
+        return;
+    }
+
+    status = pNtGetNextProcess(0, PROCESS_QUERY_LIMITED_INFORMATION, OBJ_INHERIT, 0, &handle);
+    ok(!status, "Unexpected status %#x.\n", status);
+    pNtClose(handle);
+
+    /* Reversed search only supported in recent enough Win10 */
+    status = pNtGetNextProcess(0, PROCESS_QUERY_LIMITED_INFORMATION, OBJ_INHERIT, 1, &handle);
+    ok(!status || broken(status == STATUS_INVALID_PARAMETER), "Unexpected status %#x.\n", status);
+    if (status)
+        pNtClose(handle);
+
+    status = pNtGetNextProcess(0, PROCESS_QUERY_LIMITED_INFORMATION, OBJ_INHERIT, 2, &handle);
+    ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %#x.\n", status);
+}
+
 START_TEST(om)
 {
     HMODULE hntdll = GetModuleHandleA("ntdll.dll");
@@ -2082,6 +2108,7 @@ START_TEST(om)
     pRtlWaitOnAddress       =  (void *)GetProcAddress(hntdll, "RtlWaitOnAddress");
     pRtlWakeAddressAll      =  (void *)GetProcAddress(hntdll, "RtlWakeAddressAll");
     pRtlWakeAddressSingle   =  (void *)GetProcAddress(hntdll, "RtlWakeAddressSingle");
+    pNtGetNextProcess       =  (void *)GetProcAddress(hntdll, "NtGetNextProcess");
 
     test_case_sensitive();
     test_namespace_pipe();
@@ -2096,4 +2123,5 @@ START_TEST(om)
     test_keyed_events();
     test_null_device();
     test_wait_on_address();
+    test_get_next_process();
 }
diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c
index 5ccf435e9ff..b0f7fa88d34 100644
--- a/dlls/ntdll/unix/process.c
+++ b/dlls/ntdll/unix/process.c
@@ -1743,6 +1743,26 @@ NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
     return ret;
 }
 
+/**********************************************************************
+ *           NtGetNextProcess  (NTDLL.@)
+ */
+NTSTATUS WINAPI NtGetNextProcess( HANDLE process, ACCESS_MASK access, ULONG attributes,
+                                  ULONG flags, HANDLE *handle )
+{
+    NTSTATUS ret;
+
+    SERVER_START_REQ( get_next_process )
+    {
+        req->last = wine_server_obj_handle( process );
+        req->access = access;
+        req->attributes = attributes;
+        req->flags = flags;
+        ret = wine_server_call( req );
+        if (!ret) *handle = wine_server_ptr_handle( reply->handle );
+    }
+    SERVER_END_REQ;
+    return ret;
+}
 
 /***********************************************************************
  *           __wine_make_process_system   (NTDLL.@)
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index ea62e73f63c..70aa8839314 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -5441,6 +5441,24 @@ struct resume_process_reply
 };
 
 
+
+struct get_next_process_request
+{
+    struct request_header __header;
+    obj_handle_t last;
+    unsigned int access;
+    unsigned int attributes;
+    unsigned int flags;
+    char __pad_28[4];
+};
+struct get_next_process_reply
+{
+    struct reply_header __header;
+    obj_handle_t handle;
+    char __pad_12[4];
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -5724,6 +5742,7 @@ enum request
     REQ_terminate_job,
     REQ_suspend_process,
     REQ_resume_process,
+    REQ_get_next_process,
     REQ_NB_REQUESTS
 };
 
@@ -6012,6 +6031,7 @@ union generic_request
     struct terminate_job_request terminate_job_request;
     struct suspend_process_request suspend_process_request;
     struct resume_process_request resume_process_request;
+    struct get_next_process_request get_next_process_request;
 };
 union generic_reply
 {
@@ -6298,11 +6318,12 @@ union generic_reply
     struct terminate_job_reply terminate_job_reply;
     struct suspend_process_reply suspend_process_reply;
     struct resume_process_reply resume_process_reply;
+    struct get_next_process_reply get_next_process_reply;
 };
 
 /* ### protocol_version begin ### */
 
-#define SERVER_PROTOCOL_VERSION 647
+#define SERVER_PROTOCOL_VERSION 648
 
 /* ### protocol_version end ### */
 
diff --git a/server/process.c b/server/process.c
index 1786493a814..ced638ec966 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1829,6 +1829,47 @@ DECL_HANDLER(resume_process)
     }
 }
 
+/* Iterate process list */
+DECL_HANDLER(get_next_process)
+{
+    struct process *process = NULL, *next;
+    struct list *ptr;
+
+    reply->handle = 0;
+
+    if ( req->flags > 1 )
+    {
+        set_error( STATUS_INVALID_PARAMETER );
+        return;
+    }
+
+    if (!req->last)
+    {
+        ptr = req->flags ? list_tail( &process_list ) : list_head( &process_list );
+    }
+    else if ((process = get_process_from_handle( req->last, 0 )))
+    {
+        ptr = req->flags ? list_prev( &process_list, &process->entry ) :
+                list_next( &process_list, &process->entry );
+    }
+    else
+        return;
+
+    while (ptr)
+    {
+        next = LIST_ENTRY( ptr, struct process, entry );
+        if ((reply->handle = alloc_handle( current->process, next, req->access, req->attributes )))
+            break;
+        ptr = req->flags ? list_prev( &process_list, &next->entry ) : list_next( &process_list, &next->entry );
+    }
+
+    if (!reply->handle)
+        set_error( STATUS_NO_MORE_ENTRIES );
+
+    if (process)
+        release_object( process );
+}
+
 /* Get a list of processes and threads currently running */
 DECL_HANDLER(list_processes)
 {
diff --git a/server/protocol.def b/server/protocol.def
index f538c6dcf51..81ce88cca82 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3703,3 +3703,14 @@ struct handle_info
 @REQ(resume_process)
     obj_handle_t handle;       /* process handle */
 @END
+
+
+/* Iterate process list */
+ at REQ(get_next_process)
+    obj_handle_t last;         /* process handle to start with */
+    unsigned int access;       /* desired access for returned handle */
+    unsigned int attributes;   /* returned handle attributes */
+    unsigned int flags;        /* controls iteration direction */
+ at REPLY
+    obj_handle_t handle;       /* next process handle */
+ at END
diff --git a/server/request.h b/server/request.h
index bc6f29f2110..26fc80dc5d6 100644
--- a/server/request.h
+++ b/server/request.h
@@ -400,6 +400,7 @@ DECL_HANDLER(get_job_info);
 DECL_HANDLER(terminate_job);
 DECL_HANDLER(suspend_process);
 DECL_HANDLER(resume_process);
+DECL_HANDLER(get_next_process);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -687,6 +688,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_terminate_job,
     (req_handler)req_suspend_process,
     (req_handler)req_resume_process,
+    (req_handler)req_get_next_process,
 };
 
 C_ASSERT( sizeof(abstime_t) == 8 );
@@ -2280,6 +2282,13 @@ C_ASSERT( FIELD_OFFSET(struct suspend_process_request, handle) == 12 );
 C_ASSERT( sizeof(struct suspend_process_request) == 16 );
 C_ASSERT( FIELD_OFFSET(struct resume_process_request, handle) == 12 );
 C_ASSERT( sizeof(struct resume_process_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_next_process_request, last) == 12 );
+C_ASSERT( FIELD_OFFSET(struct get_next_process_request, access) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_next_process_request, attributes) == 20 );
+C_ASSERT( FIELD_OFFSET(struct get_next_process_request, flags) == 24 );
+C_ASSERT( sizeof(struct get_next_process_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct get_next_process_reply, handle) == 8 );
+C_ASSERT( sizeof(struct get_next_process_reply) == 16 );
 
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index ffe9d6e19c6..092cc8e94f8 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -4424,6 +4424,19 @@ static void dump_resume_process_request( const struct resume_process_request *re
     fprintf( stderr, " handle=%04x", req->handle );
 }
 
+static void dump_get_next_process_request( const struct get_next_process_request *req )
+{
+    fprintf( stderr, " last=%04x", req->last );
+    fprintf( stderr, ", access=%08x", req->access );
+    fprintf( stderr, ", attributes=%08x", req->attributes );
+    fprintf( stderr, ", flags=%08x", req->flags );
+}
+
+static void dump_get_next_process_reply( const struct get_next_process_reply *req )
+{
+    fprintf( stderr, " handle=%04x", req->handle );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_exec_process_request,
@@ -4706,6 +4719,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_terminate_job_request,
     (dump_func)dump_suspend_process_request,
     (dump_func)dump_resume_process_request,
+    (dump_func)dump_get_next_process_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -4990,6 +5004,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     NULL,
     NULL,
     NULL,
+    (dump_func)dump_get_next_process_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -5274,6 +5289,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "terminate_job",
     "suspend_process",
     "resume_process",
+    "get_next_process",
 };
 
 static const struct
-- 
2.28.0




More information about the wine-devel mailing list