Implemented WaitForInputIdle.
diff --git a/if1632/thunk.c b/if1632/thunk.c
index 5501e7d..51cfa2a 100644
--- a/if1632/thunk.c
+++ b/if1632/thunk.c
@@ -375,6 +375,7 @@
GETADDR( DispatchMessageW, "DispatchMessageW" );
GETADDR( DispatchMessageA, "DispatchMessageA" );
GETADDR( RedrawWindow, "RedrawWindow" );
+ GETADDR( WaitForInputIdle, "WaitForInputIdle" );
#undef GETADDR
}
diff --git a/include/callback.h b/include/callback.h
index 44a49a0..7bf4343 100644
--- a/include/callback.h
+++ b/include/callback.h
@@ -103,6 +103,7 @@
HQUEUE16 WINAPI (*InitThreadInput16)( WORD unknown, WORD flags );
void WINAPI (*UserYield16)( void );
WORD WINAPI (*DestroyIcon32)( HGLOBAL16 handle, UINT16 flags );
+ DWORD WINAPI (*WaitForInputIdle)( HANDLE hProcess, DWORD dwTimeOut );
} CALLOUT_TABLE;
diff --git a/include/process.h b/include/process.h
index b1d9236..54665c1 100644
--- a/include/process.h
+++ b/include/process.h
@@ -96,6 +96,8 @@
struct _PDB *next; /* List reference - list of PDB's */
WORD winver; /* Windows version figured out by VERSION_GetVersion */
struct _SERVICETABLE *service_table; /* Service table for service thread */
+ HANDLE idle_event; /* event to signal, when the process is idle */
+ HANDLE16 main_queue; /* main message queue of the process */
} PDB;
/* Process flags */
@@ -146,6 +148,7 @@
extern DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset );
void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value );
+extern DWORD WINAPI MapProcessHandle( HANDLE handle );
/* scheduler/environ.c */
extern BOOL ENV_InheritEnvironment( PDB *pdb, LPCSTR env );
diff --git a/loader/module.c b/loader/module.c
index 89916f9..5813d3b 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -834,6 +834,10 @@
return 11;
}
+ /* Give 30 seconds to the app to come up */
+ if ( Callout.WaitForInputIdle ( info.hProcess, 30000 ) == 0xFFFFFFFF )
+ WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
+
/* Get 16-bit hInstance/hTask from process */
pdb = PROCESS_IdToPDB( info.dwProcessId );
tdb = pdb? (TDB *)GlobalLock16( pdb->task ) : NULL;
@@ -1289,7 +1293,7 @@
/***********************************************************************
- * GetModuleFileName32A (KERNEL32.235)
+ * GetModuleFileNameA (KERNEL32.235)
*/
DWORD WINAPI GetModuleFileNameA(
HMODULE hModule, /* [in] module handle (32bit) */
diff --git a/scheduler/process.c b/scheduler/process.c
index b30e24d..d9ff8fd 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -313,6 +313,7 @@
pdb->heap = pdb->system_heap; /* will be changed later on */
pdb->next = PROCESS_First;
pdb->winver = 0xffff; /* to be determined */
+ pdb->main_queue = INVALID_HANDLE_VALUE16;
PROCESS_First = pdb;
return pdb;
}
@@ -338,6 +339,7 @@
initial_pdb.priority = 8; /* Normal */
initial_pdb.flags = PDB32_WIN16_PROC;
initial_pdb.winver = 0xffff; /* to be determined */
+ initial_pdb.main_queue = INVALID_HANDLE_VALUE16;
/* Initialize virtual memory management */
if (!VIRTUAL_Init()) return FALSE;
@@ -352,6 +354,14 @@
if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
initial_pdb.system_heap = initial_pdb.heap = SystemHeap;
+ /* Create the idle event for the initial process
+ FIXME 1: Shouldn't we call UserSignalProc for the initial process too?
+ FIXME 2: It seems to me that the initial pdb becomes never freed, so I don't now
+ where to release the idle event for the initial process.
+ */
+ initial_pdb.idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL );
+ initial_pdb.idle_event = ConvertToGlobalHandle ( initial_pdb.idle_event );
+
/* Initialize signal handling */
if (!SIGNAL_Init()) return FALSE;
@@ -485,8 +495,9 @@
if ( Options.debug && TASK_AddTaskEntryBreakpoint )
TASK_AddTaskEntryBreakpoint( pdb->task );
- /* Now call the entry point */
- PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0, 0 );
+ /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
+ if ( type != PROC_WIN16 && (pdb->flags & PDB32_CONSOLE_PROC))
+ PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0, 0 );
switch ( type )
{
diff --git a/windows/message.c b/windows/message.c
index b21f809..91dc327 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -1933,6 +1933,7 @@
DWORD i;
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
DWORD ret;
+ PDB * pdb = PROCESS_Current();
HQUEUE16 hQueue = GetFastQueue16();
MESSAGEQUEUE *msgQueue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
@@ -1968,6 +1969,7 @@
/*
* Check the handles in the list.
*/
+ SetEvent ( pdb->idle_event );
ret = WaitForMultipleObjects(nCount, pHandles, fWaitAll, 5L);
/*
@@ -2000,9 +2002,13 @@
/* Add the thread event to the handle list */
for (i = 0; i < nCount; i++)
handles[i] = pHandles[i];
- handles[nCount] = msgQueue->hEvent;
+ handles[nCount] = msgQueue->hEvent;
- ret = WaitForMultipleObjects( nCount+1, handles, fWaitAll, dwMilliseconds );
+ if ( pdb->main_queue == INVALID_HANDLE_VALUE16 ) pdb->main_queue = hQueue;
+ if ( pdb->main_queue == hQueue ) SetEvent ( pdb->idle_event );
+ ret = WaitForMultipleObjects( nCount+1, handles, fWaitAll, dwMilliseconds );
+ if ( pdb->main_queue == hQueue ) ResetEvent ( pdb->idle_event );
+
}
QUEUE_Unlock( msgQueue );
@@ -2488,8 +2494,7 @@
{
struct timeval t;
gettimeofday( &t, NULL );
- /* make extremely compatible: granularity is 25 msec */
- return ((t.tv_sec * 1000) + (t.tv_usec / 25000) * 25) - MSG_WineStartTicks;
+ return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
}
diff --git a/windows/queue.c b/windows/queue.c
index cc71032..3b88261 100644
--- a/windows/queue.c
+++ b/windows/queue.c
@@ -5,6 +5,7 @@
#include <string.h>
#include <signal.h>
+#include <assert.h>
#include "wine/winbase16.h"
#include "wine/winuser16.h"
#include "miscemu.h"
@@ -18,7 +19,6 @@
#include "heap.h"
#include "thread.h"
#include "process.h"
-#include <assert.h>
#include "debugtools.h"
#include "spy.h"
@@ -467,7 +467,7 @@
if (msgQueue->hEvent == 0)
{
- WARN_(msg)("CreateEvent32A is not able to create an event object");
+ WARN_(msg)("CreateEventA is not able to create an event object");
return 0;
}
msgQueue->hEvent = ConvertToGlobalHandle( msgQueue->hEvent );
@@ -672,14 +672,19 @@
{
MESSAGEQUEUE *queue;
DWORD curTime = 0;
+ HQUEUE16 hQueue;
+ PDB * pdb;
TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
if ( THREAD_IsWin16( NtCurrentTeb() ) && (timeout != INFINITE) )
curTime = GetTickCount();
- if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
+ hQueue = GetFastQueue16();
+ if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return 0;
+ pdb = PROCESS_Current();
+
for (;;)
{
if (queue->changeBits & bits)
@@ -716,7 +721,24 @@
TRACE_(msg)("bHasWin16Lock=TRUE\n");
ReleaseThunkLock( &dwlc );
}
+
+
+ if ( pdb->main_queue == INVALID_HANDLE_VALUE16 )
+ {
+ pdb->main_queue = hQueue;
+ }
+ if ( pdb->main_queue == hQueue )
+ {
+ SetEvent ( pdb->idle_event );
+ }
+
WaitForSingleObject( queue->hEvent, timeout );
+
+ if ( pdb->main_queue == hQueue )
+ {
+ ResetEvent ( pdb->idle_event );
+ }
+
if ( bHasWin16Lock )
{
RestoreThunkLock( dwlc );
@@ -724,6 +746,8 @@
}
else
{
+ SetEvent ( pdb->idle_event );
+
if ( timeout == INFINITE )
WaitEvent16( 0 ); /* win 16 thread, use WaitEvent */
else
@@ -1395,7 +1419,7 @@
/***********************************************************************
- * SetMessageQueue32 (USER32.494)
+ * SetMessageQueue (USER32.494)
*/
BOOL WINAPI SetMessageQueue( INT size )
{
@@ -1409,7 +1433,7 @@
}
/***********************************************************************
- * InitThreadInput (USER.409)
+ * InitThreadInput16 (USER.409)
*/
HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
{
@@ -1430,7 +1454,7 @@
{
WARN_(msg)("failed!\n");
return FALSE;
- }
+ }
/* Link new queue into list */
queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
@@ -1496,12 +1520,54 @@
*/
DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
{
- FIXME_(msg)("(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
+ PDB * pdb;
+ DWORD cur_time, ret, pid = MapProcessHandle ( hProcess );
+ /* Check whether the calling process is a command line application */
+ if (!THREAD_IsWin16(NtCurrentTeb() ) &&
+ (PROCESS_Current()->flags & PDB32_CONSOLE_PROC))
+ {
+ TRACE_(msg)("not a win32 GUI application!\n" );
+ return 0;
+ }
+
+ pdb = PROCESS_IdToPDB( pid );
+
+ /* check whether we are waiting for a win32 process or the win16 subsystem */
+ if ( pdb->flags & PDB32_WIN16_PROC ) {
+ if ( THREAD_IsWin16(NtCurrentTeb()) ) return 0;
+ }
+ else { /* target is win32 */
+ if ( pdb->flags & PDB32_CONSOLE_PROC ) return 0;
+ if ( GetFastQueue16() == pdb->main_queue ) return 0;
+ }
+
+ cur_time = GetTickCount();
+
+ TRACE_(msg)("waiting for %x\n", pdb->idle_event );
+ while ( dwTimeOut > GetTickCount() - cur_time || dwTimeOut == INFINITE ) {
+
+ ret = MsgWaitForMultipleObjects ( 1, &pdb->idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
+ if ( ret == ( WAIT_OBJECT_0 + 1 )) {
+ MESSAGEQUEUE * queue;
+ if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0xFFFFFFFF;
+ QUEUE_ReceiveMessage ( queue );
+ QUEUE_Unlock ( queue );
+ continue;
+ }
+ if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF ) {
+ TRACE_(msg)("timeout or error\n");
+ return ret;
+ }
+ else {
+ TRACE_(msg)("finished\n");
+ return 0;
+ }
+
+ }
return WAIT_TIMEOUT;
}
-
/***********************************************************************
* GetInputState32 (USER32.244)
*/
diff --git a/windows/user.c b/windows/user.c
index fc3e1b6..68f380e 100644
--- a/windows/user.c
+++ b/windows/user.c
@@ -207,7 +207,9 @@
WORD WINAPI UserSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
DWORD dwFlags, HMODULE16 hModule )
{
+ static HANDLE win16_idle_event;
HINSTANCE16 hInst;
+ PDB * pdb;
/* FIXME: Proper reaction to most signals still missing. */
@@ -234,18 +236,48 @@
break;
case USIG_PROCESS_CREATE:
+ pdb = PROCESS_IdToPDB( dwThreadOrProcessID );
+
+ /* Create the idle event for the process. We have just one idle_event for all
+ win16 processes, while each win32 process has its own */
+
+ if ( pdb->flags & PDB32_WIN16_PROC )
+ {
+ if (!win16_idle_event)
+ {
+ win16_idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL );
+ win16_idle_event = ConvertToGlobalHandle ( win16_idle_event );
+ }
+ pdb->idle_event = win16_idle_event;
+ }
+ else { /* win32 process */
+ pdb->idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL );
+ pdb->idle_event = ConvertToGlobalHandle ( pdb->idle_event );
+ TRACE_(win)("created win32 idle event: %x\n", pdb->idle_event );
+ }
+ break;
+
case USIG_PROCESS_INIT:
case USIG_PROCESS_LOADED:
+ break;
case USIG_PROCESS_RUNNING:
+ pdb = PROCESS_IdToPDB ( dwThreadOrProcessID );
+ SetEvent ( pdb->idle_event );
break;
case USIG_PROCESS_EXIT:
break;
- case USIG_PROCESS_DESTROY:
- hInst = GetProcessDword( dwThreadOrProcessID, GPD_HINSTANCE16 );
- USER_AppExit( hInst );
- break;
+ case USIG_PROCESS_DESTROY:
+ hInst = GetProcessDword( dwThreadOrProcessID, GPD_HINSTANCE16 );
+ USER_AppExit( hInst );
+
+ pdb = PROCESS_IdToPDB( dwThreadOrProcessID );
+ if ( ! (pdb->flags & PDB32_WIN16_PROC) ) {
+ TRACE_(win)("destroying win32 idle event: %x\n", pdb->idle_event );
+ CloseHandle ( pdb->idle_event );
+ }
+ break;
default:
FIXME_(win)("(%04x, %08lx, %04lx, %04x)\n",