Signed-off-by: Nikolay Sivov nsivov@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)