[PATCH 4/5] combase: Move CoWaitForMultipleHandles().

Nikolay Sivov nsivov at codeweavers.com
Wed Aug 19 03:29:12 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/combase/combase.c         | 163 ++++++++++++++++++++++++++++++
 dlls/combase/combase.spec      |   2 +-
 dlls/combase/combase_private.h |  40 +++++++-
 dlls/combase/marshal.c         |   3 +-
 dlls/ole32/compobj.c           | 179 ---------------------------------
 dlls/ole32/ole32.spec          |   2 +-
 6 files changed, 206 insertions(+), 183 deletions(-)

diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c
index 114ea89e05e..88dc7aa7b19 100644
--- a/dlls/combase/combase.c
+++ b/dlls/combase/combase.c
@@ -25,6 +25,7 @@
 #define USE_COM_CONTEXT_DEF
 #include "objbase.h"
 #include "oleauto.h"
+#include "dde.h"
 #include "winternl.h"
 
 #include "combase_private.h"
@@ -1521,3 +1522,165 @@ HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
     }
     return S_OK;
 }
+
+static BOOL com_peek_message(struct apartment *apt, MSG *msg)
+{
+    /* First try to retrieve messages for incoming COM calls to the apartment window */
+    return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE | PM_NOYIELD)) ||
+            /* Next retrieve other messages necessary for the app to remain responsive */
+            PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE | PM_NOYIELD) ||
+            PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT | PM_QS_SENDMESSAGE | PM_REMOVE | PM_NOYIELD);
+}
+
+/***********************************************************************
+ *           CoWaitForMultipleHandles    (combase.@)
+ */
+HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle_count, HANDLE *handles,
+        DWORD *index)
+{
+    BOOL check_apc = !!(flags & COWAIT_ALERTABLE), post_quit = FALSE, message_loop;
+    DWORD start_time, wait_flags = 0;
+    struct tlsdata *tlsdata;
+    struct apartment *apt;
+    UINT exit_code;
+    HRESULT hr;
+
+    TRACE("%#x, %#x, %u, %p, %p\n", flags, timeout, handle_count, handles, index);
+
+    if (!index)
+        return E_INVALIDARG;
+
+    *index = 0;
+
+    if (!handles)
+        return E_INVALIDARG;
+
+    if (!handle_count)
+        return RPC_E_NO_SYNC;
+
+    if (FAILED(hr = com_get_tlsdata(&tlsdata)))
+        return hr;
+
+    apt = com_get_current_apt();
+    message_loop = apt && !apt->multi_threaded;
+
+    if (flags & COWAIT_WAITALL)
+        wait_flags |= MWMO_WAITALL;
+    if (flags & COWAIT_ALERTABLE)
+        wait_flags |= MWMO_ALERTABLE;
+
+    start_time = GetTickCount();
+
+    while (TRUE)
+    {
+        DWORD now = GetTickCount(), res;
+
+        if (now - start_time > timeout)
+        {
+            hr = RPC_S_CALLPENDING;
+            break;
+        }
+
+        if (message_loop)
+        {
+            TRACE("waiting for rpc completion or window message\n");
+
+            res = WAIT_TIMEOUT;
+
+            if (check_apc)
+            {
+                res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), 0, TRUE);
+                check_apc = FALSE;
+            }
+
+            if (res == WAIT_TIMEOUT)
+                res = MsgWaitForMultipleObjectsEx(handle_count, handles,
+                        timeout == INFINITE ? INFINITE : start_time + timeout - now,
+                        QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
+
+            if (res == WAIT_OBJECT_0 + handle_count)  /* messages available */
+            {
+                int msg_count = 0;
+                MSG msg;
+
+                /* call message filter */
+
+                if (apt->filter)
+                {
+                    PENDINGTYPE pendingtype = tlsdata->pending_call_count_server ? PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
+                    DWORD be_handled = IMessageFilter_MessagePending(apt->filter, 0 /* FIXME */, now - start_time, pendingtype);
+
+                    TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
+
+                    switch (be_handled)
+                    {
+                    case PENDINGMSG_CANCELCALL:
+                        WARN("call canceled\n");
+                        hr = RPC_E_CALL_CANCELED;
+                        break;
+                    case PENDINGMSG_WAITNOPROCESS:
+                    case PENDINGMSG_WAITDEFPROCESS:
+                    default:
+                        /* FIXME: MSDN is very vague about the difference
+                         * between WAITNOPROCESS and WAITDEFPROCESS - there
+                         * appears to be none, so it is possibly a left-over
+                         * from the 16-bit world. */
+                        break;
+                    }
+                }
+
+                if (!apt->win)
+                {
+                    /* If window is NULL on apartment, peek at messages so that it will not trigger
+                     * MsgWaitForMultipleObjects next time. */
+                    PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
+                }
+
+                /* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
+                 * so after processing 100 messages we go back to checking the wait handles */
+                while (msg_count++ < 100 && com_peek_message(apt, &msg))
+                {
+                    if (msg.message == WM_QUIT)
+                    {
+                        TRACE("Received WM_QUIT message\n");
+                        post_quit = TRUE;
+                        exit_code = msg.wParam;
+                    }
+                    else
+                    {
+                        TRACE("Received message whilst waiting for RPC: 0x%04x\n", msg.message);
+                        TranslateMessage(&msg);
+                        DispatchMessageW(&msg);
+                    }
+                }
+                continue;
+            }
+        }
+        else
+        {
+            TRACE("Waiting for rpc completion\n");
+
+            res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL),
+                    (timeout == INFINITE) ? INFINITE : start_time + timeout - now, !!(flags & COWAIT_ALERTABLE));
+        }
+
+        switch (res)
+        {
+        case WAIT_TIMEOUT:
+            hr = RPC_S_CALLPENDING;
+            break;
+        case WAIT_FAILED:
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            break;
+        default:
+            *index = res;
+            break;
+        }
+        break;
+    }
+    if (post_quit) PostQuitMessage(exit_code);
+
+    TRACE("-- 0x%08x\n", hr);
+
+    return hr;
+}
diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec
index 08426810784..7fd1e964cd3 100644
--- a/dlls/combase/combase.spec
+++ b/dlls/combase/combase.spec
@@ -170,7 +170,7 @@
 @ stub CoVrfCheckThreadState
 @ stub CoVrfGetThreadState
 @ stub CoVrfReleaseThreadState
-@ stdcall CoWaitForMultipleHandles(long long long ptr ptr) ole32.CoWaitForMultipleHandles
+@ stdcall CoWaitForMultipleHandles(long long long ptr ptr)
 @ stub CoWaitForMultipleObjects
 @ stdcall CreateErrorInfo(ptr)
 @ stdcall CreateStreamOnHGlobal(ptr long ptr) ole32.CreateStreamOnHGlobal
diff --git a/dlls/combase/combase_private.h b/dlls/combase/combase_private.h
index bae57e89487..28a98fd5803 100644
--- a/dlls/combase/combase_private.h
+++ b/dlls/combase/combase_private.h
@@ -15,10 +15,41 @@
  */
 
 #include "winternl.h"
+#include "wine/orpc.h"
 
 #include "wine/list.h"
 
-struct apartment;
+struct apartment
+{
+    struct list entry;
+
+    LONG  refs;              /* refcount of the apartment (LOCK) */
+    BOOL multi_threaded;     /* multi-threaded or single-threaded apartment? (RO) */
+    DWORD tid;               /* thread id (RO) */
+    OXID oxid;               /* object exporter ID (RO) */
+    LONG ipidc;              /* interface pointer ID counter, starts at 1 (LOCK) */
+    CRITICAL_SECTION cs;     /* thread safety */
+    struct list proxies;     /* imported objects (CS cs) */
+    struct list stubmgrs;    /* stub managers for exported objects (CS cs) */
+    BOOL remunk_exported;    /* has the IRemUnknown interface for this apartment been created yet? (CS cs) */
+    LONG remoting_started;   /* has the RPC system been started for this apartment? (LOCK) */
+    struct list loaded_dlls; /* list of dlls loaded by this apartment (CS cs) */
+    DWORD host_apt_tid;      /* thread ID of apartment hosting objects of differing threading model (CS cs) */
+    HWND host_apt_hwnd;      /* handle to apartment window of host apartment (CS cs) */
+    struct local_server *local_server; /* A marshallable object exposing local servers (CS cs) */
+    BOOL being_destroyed;    /* is currently being destroyed */
+
+    /* FIXME: OIDs should be given out by RPCSS */
+    OID oidc;                /* object ID counter, starts at 1, zero is invalid OID (CS cs) */
+
+    /* STA-only fields */
+    HWND win;                /* message window (LOCK) */
+    IMessageFilter *filter;  /* message filter (CS cs) */
+    BOOL main;               /* is this a main-threaded-apartment? (RO) */
+
+    /* MTA-only */
+    struct list usage_cookies; /* Used for refcount control with CoIncrementMTAUsage()/CoDecrementMTAUsage(). */
+};
 
 /* this is what is stored in TEB->ReservedForOle */
 struct tlsdata
@@ -50,3 +81,10 @@ static inline HRESULT com_get_tlsdata(struct tlsdata **data)
     *data = NtCurrentTeb()->ReservedForOle;
     return *data ? S_OK : InternalTlsAllocData(data);
 }
+
+static inline struct apartment* com_get_current_apt(void)
+{
+    struct tlsdata *tlsdata = NULL;
+    com_get_tlsdata(&tlsdata);
+    return tlsdata->apt;
+}
diff --git a/dlls/combase/marshal.c b/dlls/combase/marshal.c
index 9a88be72368..db5089f013e 100644
--- a/dlls/combase/marshal.c
+++ b/dlls/combase/marshal.c
@@ -22,9 +22,10 @@
 #define COBJMACROS
 #include "objbase.h"
 
+#include "combase_private.h"
+
 #include "wine/debug.h"
 #include "wine/heap.h"
-#include "wine/orpc.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index 2a5e9f573ab..574a7b33055 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -3348,185 +3348,6 @@ HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
     return S_OK;
 }
 
-static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
-{
-    /* first try to retrieve messages for incoming COM calls to the apartment window */
-    return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
-           /* next retrieve other messages necessary for the app to remain responsive */
-           PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
-           PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
-}
-
-/***********************************************************************
- *           CoWaitForMultipleHandles [OLE32.@]
- *
- * Waits for one or more handles to become signaled.
- *
- * PARAMS
- *  dwFlags   [I] Flags. See notes.
- *  dwTimeout [I] Timeout in milliseconds.
- *  cHandles  [I] Number of handles pointed to by pHandles.
- *  pHandles  [I] Handles to wait for.
- *  lpdwindex [O] Index of handle that was signaled.
- *
- * RETURNS
- *  Success: S_OK.
- *  Failure: RPC_S_CALLPENDING on timeout.
- *
- * NOTES
- *
- * The dwFlags parameter can be zero or more of the following:
- *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
- *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
- *
- * SEE ALSO
- *  MsgWaitForMultipleObjects, WaitForMultipleObjects.
- */
-HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
-    ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
-{
-    HRESULT hr = S_OK;
-    DWORD start_time = GetTickCount();
-    APARTMENT *apt = COM_CurrentApt();
-    BOOL message_loop = apt && !apt->multi_threaded;
-    BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
-    BOOL post_quit = FALSE;
-    UINT exit_code;
-
-    TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
-        pHandles, lpdwindex);
-
-    if (!lpdwindex)
-        return E_INVALIDARG;
-
-    *lpdwindex = 0;
-
-    if (!pHandles)
-        return E_INVALIDARG;
-
-    if (!cHandles)
-        return RPC_E_NO_SYNC;
-
-    while (TRUE)
-    {
-        DWORD now = GetTickCount();
-        DWORD res;
-
-        if (now - start_time > dwTimeout)
-        {
-            hr = RPC_S_CALLPENDING;
-            break;
-        }
-
-        if (message_loop)
-        {
-            DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
-                    ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
-
-            TRACE("waiting for rpc completion or window message\n");
-
-            res = WAIT_TIMEOUT;
-
-            if (check_apc)
-            {
-                res = WaitForMultipleObjectsEx(cHandles, pHandles,
-                    (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
-                check_apc = FALSE;
-            }
-
-            if (res == WAIT_TIMEOUT)
-                res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
-                    (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
-                    QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
-
-            if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
-            {
-                MSG msg;
-                int count = 0;
-
-                /* call message filter */
-
-                if (COM_CurrentApt()->filter)
-                {
-                    PENDINGTYPE pendingtype =
-                        COM_CurrentInfo()->pending_call_count_server ?
-                            PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
-                    DWORD be_handled = IMessageFilter_MessagePending(
-                        COM_CurrentApt()->filter, 0 /* FIXME */,
-                        now - start_time, pendingtype);
-                    TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
-                    switch (be_handled)
-                    {
-                    case PENDINGMSG_CANCELCALL:
-                        WARN("call canceled\n");
-                        hr = RPC_E_CALL_CANCELED;
-                        break;
-                    case PENDINGMSG_WAITNOPROCESS:
-                    case PENDINGMSG_WAITDEFPROCESS:
-                    default:
-                        /* FIXME: MSDN is very vague about the difference
-                         * between WAITNOPROCESS and WAITDEFPROCESS - there
-                         * appears to be none, so it is possibly a left-over
-                         * from the 16-bit world. */
-                        break;
-                    }
-                }
-
-                if (!apt->win)
-                {
-                    /* If window is NULL on apartment, peek at messages so that it will not trigger
-                     * MsgWaitForMultipleObjects next time. */
-                    PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
-                }
-                /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
-                 * so after processing 100 messages we go back to checking the wait handles */
-                while (count++ < 100 && COM_PeekMessage(apt, &msg))
-                {
-                    if (msg.message == WM_QUIT)
-                    {
-                        TRACE("received WM_QUIT message\n");
-                        post_quit = TRUE;
-                        exit_code = msg.wParam;
-                    }
-                    else
-                    {
-                        TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
-                        TranslateMessage(&msg);
-                        DispatchMessageW(&msg);
-                    }
-                }
-                continue;
-            }
-        }
-        else
-        {
-            TRACE("waiting for rpc completion\n");
-
-            res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
-                (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
-                (dwFlags & COWAIT_ALERTABLE) != 0);
-        }
-
-        switch (res)
-        {
-        case WAIT_TIMEOUT:
-            hr = RPC_S_CALLPENDING;
-            break;
-        case WAIT_FAILED:
-            hr = HRESULT_FROM_WIN32( GetLastError() );
-            break;
-        default:
-            *lpdwindex = res;
-            break;
-        }
-        break;
-    }
-    if (post_quit) PostQuitMessage(exit_code);
-    TRACE("-- 0x%08x\n", hr);
-    return hr;
-}
-
-
 /***********************************************************************
  *           CoGetObject [OLE32.@]
  *
diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec
index a4837bd6ff0..afb0e104075 100644
--- a/dlls/ole32/ole32.spec
+++ b/dlls/ole32/ole32.spec
@@ -91,7 +91,7 @@
 @ stub CoUnloadingWOW
 @ stdcall CoUnmarshalHresult(ptr ptr) combase.CoUnmarshalHresult
 @ stdcall CoUnmarshalInterface(ptr ptr ptr)
-@ stdcall CoWaitForMultipleHandles(long long long ptr ptr)
+@ stdcall CoWaitForMultipleHandles(long long long ptr ptr) combase.CoWaitForMultipleHandles
 @ stdcall CreateAntiMoniker(ptr)
 @ stdcall CreateBindCtx(long ptr)
 @ stdcall CreateClassMoniker(ptr ptr)
-- 
2.28.0




More information about the wine-devel mailing list