[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