1
0
mirror of https://github.com/UzixLS/KernelEx.git synced 2025-07-18 23:11:19 +03:00
Files
KernelEx/apilibs/kexbasen/ole32/CoWaitForMultipleHandles.c
2018-11-03 16:22:49 +03:00

165 lines
4.4 KiB
C
Executable File

/*
* KernelEx
* Copyright 2010, Tihiy
*
* Copyright 1995 Martin von Loewis
* Copyright 1998 Justin Bradford
* Copyright 1999 Francis Beaudet
* Copyright 1999 Sylvain St-Germain
* Copyright 2002 Marcus Meissner
* Copyright 2004 Mike Hearn
* Copyright 2005-2006 Robert Shearman (for CodeWeavers)
*
* This file is part of KernelEx source code.
*
* KernelEx is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; version 2 of the License.
*
* KernelEx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#define COBJMACROS
#define CINTERFACE
#include <windows.h>
#include "kexcoresdk.h"
#define COFLAGS_APARTMENTTHREADED 0x80
typedef struct
{
DWORD Unknown; //+0x00
DWORD dwCOMFlags; //+0x04
BYTE filler[0x40]; //+0x08
IMessageFilter *filter; //+0x48
} APARTMENT, *PAPARTMENT;
static PAPARTMENT COM_CurrentApt()
{
DWORD** ppdwTlsIndex = (DWORD**)
( (DWORD)kexGetProcAddress(GetModuleHandle("OLE32.DLL"),"CoGetState")+2 );
return (PAPARTMENT)TlsGetValue(**ppdwTlsIndex);
}
BOOL CALLBACK FindCOMWindow( HWND hwnd, LPARAM lParam )
{
char wndname[200];
if ( GetWindowTextA(hwnd,wndname,200) && strcmp(wndname,"OleMainThreadWndName") == 0
&& (HINSTANCE)GetWindowLongA(hwnd,GWL_HINSTANCE) == GetModuleHandle("OLE32.DLL") )
{
*(PHANDLE)lParam = hwnd;
return FALSE;
}
return TRUE;
}
/* processes COM messages, returns FALSE if thread quits */
static BOOL COM_PumpMessages()
{
HWND comWindow = NULL;
EnumThreadWindows(GetCurrentThreadId(),FindCOMWindow,(LPARAM)&comWindow);
MSG msg;
BOOL haveMsgs =
PeekMessageA(&msg, comWindow, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
/* next retrieve other messages necessary for the app to remain responsive */
PeekMessageA(&msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
PeekMessageA(&msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
if (haveMsgs)
{
DispatchMessage(&msg);
if (msg.message == WM_QUIT) //resend
{
PostQuitMessage(msg.wParam);
return FALSE;
}
}
return TRUE;
}
/* MAKE_EXPORT CoWaitForMultipleHandles_new=CoWaitForMultipleHandles */
HRESULT WINAPI CoWaitForMultipleHandles_new(
DWORD dwFlags,
DWORD dwTimeout,
ULONG cHandles,
LPHANDLE pHandles,
LPDWORD lpdwindex
)
{
if (!pHandles || !lpdwindex)
return E_INVALIDARG;
HRESULT hr = S_OK;
DWORD start_time = GetTickCount();
PAPARTMENT apt = COM_CurrentApt();
BOOL message_loop = apt && (apt->dwCOMFlags & COFLAGS_APARTMENTTHREADED);
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);
res = MsgWaitForMultipleObjectsEx(cHandles,pHandles,
(dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
QS_ALLINPUT,wait_flags);
if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
{
if (apt->filter) /* call message filter */
{
//don't know htask or pendingtype :(
DWORD handled = IMessageFilter_MessagePending(apt->filter,0,
now-start_time,PENDINGTYPE_TOPLEVEL);
if (handled == PENDINGMSG_CANCELCALL)
hr = RPC_E_CALL_CANCELED;
}
message_loop = COM_PumpMessages();
continue;
}
}
else
{
res = WaitForMultipleObjectsEx(cHandles,pHandles,
(dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
(dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
(dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
}
if (res < WAIT_OBJECT_0 + cHandles)
{
/* handle signaled, store index */
*lpdwindex = (res - WAIT_OBJECT_0);
break;
}
else if (res == WAIT_TIMEOUT)
{
hr = RPC_S_CALLPENDING;
break;
}
else
{
hr = E_UNEXPECTED;
break;
}
}
return hr;
}