combase: Move CoWaitForMultipleHandles().
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
c9586634d4
commit
e56061bb4c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.@]
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue