Check all Callouts function pointers for NULL before using them.
Don't load USER dll if not needed by the application.
diff --git a/dlls/gdi/printdrv.c b/dlls/gdi/printdrv.c
index 8bd2dcd..4ecb1e9 100644
--- a/dlls/gdi/printdrv.c
+++ b/dlls/gdi/printdrv.c
@@ -617,15 +617,26 @@
return nRet;
}
+typedef INT WINAPI (*MSGBOX_PROC)( HWND, LPCSTR, LPCSTR, UINT );
+
/**********************************************************************
* WriteDialog (GDI.242)
*
*/
INT16 WINAPI WriteDialog16(HPJOB16 hJob, LPSTR lpMsg, INT16 cchMsg)
{
+ HMODULE mod;
+ MSGBOX_PROC pMessageBoxA;
+ INT16 ret = 0;
+
TRACE("%04x %04x '%s'\n", hJob, cchMsg, lpMsg);
- return Callout.MessageBoxA(0, lpMsg, "Printing Error", MB_OKCANCEL);
+ if ((mod = GetModuleHandleA("user32.dll")))
+ {
+ if ((pMessageBoxA = (MSGBOX_PROC)GetProcAddress( mod, "MessageBoxA" )))
+ ret = pMessageBoxA(0, lpMsg, "Printing Error", MB_OKCANCEL);
+ }
+ return ret;
}
diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c
index defa7e0..c6da61c 100644
--- a/dlls/kernel/comm.c
+++ b/dlls/kernel/comm.c
@@ -340,7 +340,7 @@
/* send notifications, if any */
if (ptr->wnd && mask) {
TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
- Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
+ if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
}
}
diff --git a/if1632/thunk.c b/if1632/thunk.c
index 3aa43ec..3a1dbcd 100644
--- a/if1632/thunk.c
+++ b/if1632/thunk.c
@@ -43,7 +43,6 @@
/* GetMessageA */ NULL,
/* SendMessageA */ NULL,
/* PostMessageA */ NULL,
- /* PostAppMessage16 */ NULL,
/* TranslateMessage */ NULL,
/* DispatchMessageA */ NULL,
/* RedrawWindow */ NULL,
@@ -168,7 +167,7 @@
HMODULE hModule;
NE_MODULE *pModule;
- hModule = LoadLibraryA( "user32.dll" );
+ hModule = GetModuleHandleA( "user32.dll" );
if ( hModule )
{
#define GETADDR( name ) \
@@ -188,21 +187,21 @@
GETADDR( MessageBoxW );
#undef GETADDR
}
+ else WARN("no 32-bit USER\n");
- pModule = NE_GetPtr( LoadLibrary16( "USER.EXE" ) );
+ pModule = NE_GetPtr( GetModuleHandle16( "USER.EXE" ) );
if ( pModule )
{
#define GETADDR( var, name, thk ) \
*(FARPROC *)&Callout.var = THUNK_GetCalloutThunk( pModule, name, \
(RELAY)THUNK_CallTo16_##thk )
- GETADDR( PostAppMessage16, "PostAppMessage", word_wwwl );
GETADDR( FinalUserInit16, "FinalUserInit", word_ );
GETADDR( InitThreadInput16, "InitThreadInput", word_ww );
GETADDR( UserYield16, "UserYield", word_ );
GETADDR( DestroyIcon32, "DestroyIcon32", word_ww );
GETADDR( UserSignalProc, "SignalProc32", word_lllw );
-
#undef GETADDR
}
+ else WARN("no 16-bit USER\n");
}
diff --git a/include/callback.h b/include/callback.h
index 9ba7016..7813e40 100644
--- a/include/callback.h
+++ b/include/callback.h
@@ -31,7 +31,6 @@
BOOL WINAPI (*GetMessageA)( MSG*, HWND, UINT, UINT );
LRESULT WINAPI (*SendMessageA)( HWND, UINT, WPARAM, LPARAM );
BOOL WINAPI (*PostMessageA)( HWND, UINT, WPARAM, LPARAM );
- BOOL16 WINAPI (*PostAppMessage16)( HTASK16, UINT16, WPARAM16, LPARAM );
BOOL WINAPI (*TranslateMessage)( const MSG *msg );
LONG WINAPI (*DispatchMessageA)( const MSG* msg );
BOOL WINAPI (*RedrawWindow)( HWND, const RECT *, HRGN, UINT );
diff --git a/include/task.h b/include/task.h
index cb666eb..75cdc59 100644
--- a/include/task.h
+++ b/include/task.h
@@ -147,7 +147,7 @@
extern BOOL TASK_Create( struct _NE_MODULE *pModule, UINT16 cmdShow,
struct _TEB *teb, LPCSTR cmdline, BYTE len );
-extern void TASK_KillTask( HTASK16 hTask );
+extern void TASK_ExitTask(void);
extern HTASK16 TASK_GetNextTask( HTASK16 hTask );
extern void TASK_Reschedule(void);
extern void TASK_InstallTHHook( THHOOK *pNewThook );
diff --git a/loader/dos/dosvm.c b/loader/dos/dosvm.c
index ba52f4a..0097f14 100644
--- a/loader/dos/dosvm.c
+++ b/loader/dos/dosvm.c
@@ -420,12 +420,15 @@
objc=hObject?2:1;
do {
/* check for messages (waste time before the response check below) */
- while (Callout.PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) {
- /* got a message */
- DOSVM_ProcessMessage(&msg);
- /* we don't need a TranslateMessage here */
- Callout.DispatchMessageA(&msg);
- got_msg = TRUE;
+ if (Callout.PeekMessageA)
+ {
+ while (Callout.PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) {
+ /* got a message */
+ DOSVM_ProcessMessage(&msg);
+ /* we don't need a TranslateMessage here */
+ Callout.DispatchMessageA(&msg);
+ got_msg = TRUE;
+ }
}
if (!got_msg) {
/* check for console input */
@@ -448,7 +451,11 @@
break;
}
/* nothing yet, block while waiting for something to do */
- waitret=Callout.MsgWaitForMultipleObjects(objc,objs,FALSE,INFINITE,QS_ALLINPUT);
+ if (Callout.MsgWaitForMultipleObjects)
+ waitret = Callout.MsgWaitForMultipleObjects(objc,objs,FALSE,INFINITE,QS_ALLINPUT);
+ else
+ waitret = WaitForMultipleObjects(objc,objs,FALSE,INFINITE);
+
if (waitret==(DWORD)-1) {
ERR_(module)("dosvm wait error=%ld\n",GetLastError());
}
diff --git a/loader/module.c b/loader/module.c
index e1978cf..ae2d298 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -827,7 +827,8 @@
0, NULL, NULL, &startup, &info ))
{
/* Give 30 seconds to the app to come up */
- if (Callout.WaitForInputIdle ( info.hProcess, 30000 ) == 0xFFFFFFFF)
+ if (Callout.WaitForInputIdle &&
+ Callout.WaitForInputIdle( info.hProcess, 30000 ) == 0xFFFFFFFF)
WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
hInstance = 33;
/* Close off the handles */
@@ -884,7 +885,8 @@
params->lpEnvAddress, NULL, &startup, &info ))
{
/* Give 30 seconds to the app to come up */
- if ( Callout.WaitForInputIdle ( info.hProcess, 30000 ) == 0xFFFFFFFF )
+ if (Callout.WaitForInputIdle &&
+ Callout.WaitForInputIdle( info.hProcess, 30000 ) == 0xFFFFFFFF )
WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
hInstance = 33;
/* Close off the handles */
diff --git a/loader/task.c b/loader/task.c
index 4db25a2..e6bafa0 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -379,78 +379,62 @@
/***********************************************************************
* TASK_KillTask
*/
-void TASK_KillTask( HTASK16 hTask )
+void TASK_ExitTask(void)
{
TDB *pTask;
+ DWORD lockCount;
/* Enter the Win16Lock to protect global data structures */
SYSLEVEL_EnterWin16Lock();
- if ( !hTask ) hTask = GetCurrentTask();
- pTask = (TDB *)GlobalLock16( hTask );
+ pTask = (TDB *)GlobalLock16( GetCurrentTask() );
if ( !pTask )
{
SYSLEVEL_LeaveWin16Lock();
return;
}
- TRACE("Killing task %04x\n", hTask );
+ TRACE("Killing task %04x\n", pTask->hSelf );
/* Perform USER cleanup */
- TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask );
+ TASK_CallTaskSignalProc( USIG16_TERMINATION, pTask->hSelf );
PROCESS_CallUserSignalProc( USIG_PROCESS_EXIT, 0 );
PROCESS_CallUserSignalProc( USIG_THREAD_EXIT, 0 );
PROCESS_CallUserSignalProc( USIG_PROCESS_DESTROY, 0 );
- if (nTaskCount <= 1)
+ /* Remove the task from the list to be sure we never switch back to it */
+ TASK_UnlinkTask( pTask->hSelf );
+
+ if (!nTaskCount || (nTaskCount == 1 && hFirstTask == initial_task))
{
TRACE("this is the last task, exiting\n" );
+ ERR("done\n");
ExitKernel16();
}
- /* FIXME: Hack! Send a message to the initial task so that
- * the GetMessage wakes up and the initial task can check whether
- * it is the only remaining one and terminate itself ...
- * The initial task should probably install hooks or something
- * to get informed about task termination :-/
- */
- Callout.PostAppMessage16( initial_task, WM_NULL, 0, 0 );
-
- /* Remove the task from the list to be sure we never switch back to it */
- TASK_UnlinkTask( hTask );
if( nTaskCount )
{
TDB* p = (TDB *)GlobalLock16( hFirstTask );
while( p )
{
- if( p->hYieldTo == hTask ) p->hYieldTo = 0;
+ if( p->hYieldTo == pTask->hSelf ) p->hYieldTo = 0;
p = (TDB *)GlobalLock16( p->hNext );
}
}
pTask->nEvents = 0;
- if ( hLockedTask == hTask )
+ if ( hLockedTask == pTask->hSelf )
hLockedTask = 0;
- TASK_DeleteTask( hTask );
+ TASK_DeleteTask( pTask->hSelf );
- /* When deleting the current task ... */
- if ( hTask == hCurrentTask )
- {
- DWORD lockCount;
+ /* ... schedule another one ... */
+ TASK_Reschedule();
- /* ... schedule another one ... */
- TASK_Reschedule();
-
- /* ... and completely release the Win16Lock, just in case. */
- ReleaseThunkLock( &lockCount );
-
- return;
- }
-
- SYSLEVEL_LeaveWin16Lock();
+ /* ... and completely release the Win16Lock, just in case. */
+ ReleaseThunkLock( &lockCount );
}
/***********************************************************************
@@ -838,7 +822,7 @@
TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
if (pCurTask) pCurTask->hYieldTo = 0;
- if (pCurTask && pCurTask->hQueue) Callout.UserYield16();
+ if (pCurTask && pCurTask->hQueue && Callout.UserYield16) Callout.UserYield16();
else OldYield16();
}
@@ -1148,7 +1132,7 @@
TEB *teb = NtCurrentTeb();
if (!teb) return 0;
- if (!teb->queue)
+ if (!teb->queue && Callout.InitThreadInput16)
Callout.InitThreadInput16( 0, THREAD_IsWin16(teb)? 4 : 5 );
if (!teb->queue)
diff --git a/miscemu/main.c b/miscemu/main.c
index b8bd8cd..da547d9 100644
--- a/miscemu/main.c
+++ b/miscemu/main.c
@@ -23,6 +23,13 @@
HINSTANCE16 instance;
STARTUPINFOA info;
+ if (!LoadLibraryA( "user32.dll" ))
+ {
+ MESSAGE( "Cannot load user32.dll\n" );
+ ExitProcess( GetLastError() );
+ }
+ THUNK_InitCallout();
+
GetStartupInfoA( &info );
if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = SW_SHOWNORMAL;
diff --git a/objects/palette.c b/objects/palette.c
index 4655819..3a634aa 100644
--- a/objects/palette.c
+++ b/objects/palette.c
@@ -787,14 +787,16 @@
if (!(dc = DC_GetDCPtr( hDC ))) return 0;
size = dc->devCaps->sizePalette;
GDI_ReleaseObj( hDC );
- hWnd = Callout.WindowFromDC( hDC );
+ if (Callout.WindowFromDC)
+ {
+ hWnd = Callout.WindowFromDC( hDC );
- /* Docs say that we have to remap current drawable pixel by pixel
- * but it would take forever given the speed of XGet/PutPixel.
- */
- if (hWnd && size)
- Callout.RedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
-
+ /* Docs say that we have to remap current drawable pixel by pixel
+ * but it would take forever given the speed of XGet/PutPixel.
+ */
+ if (hWnd && size)
+ Callout.RedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
+ }
return 0x666;
}
diff --git a/scheduler/process.c b/scheduler/process.c
index 44a56cd..f6bc48a 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -237,39 +237,6 @@
/***********************************************************************
- * load_system_dlls
- *
- * Load system DLLs into the initial process (and initialize them)
- */
-static int load_system_dlls(void)
-{
- /* Load KERNEL */
- if (!LoadLibraryA( "KERNEL32" )) return 0;
-
- /* Get pointers to USER routines called by KERNEL */
- THUNK_InitCallout();
-
- /* Call FinalUserInit routine */
- Callout.FinalUserInit16();
-
- /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
- * context of the parent process. Actually, the USER signal proc
- * doesn't really care about that, but it *does* require that the
- * startup parameters are correctly set up, so that GetProcessDword
- * works. Furthermore, before calling the USER signal proc the
- * 16-bit stack must be set up, which it is only after TASK_Create
- * in the case of a 16-bit process. Thus, we send the signal here.
- */
- PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 );
- PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );
- PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
- PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );
-
- return 1;
-}
-
-
-/***********************************************************************
* build_command_line
*
* Build the command line of a process from the argv array.
@@ -361,14 +328,29 @@
goto error;
wm->refCount++;
- /* Load the system dlls */
- if (!load_system_dlls()) goto error;
-
EnterCriticalSection( ¤t_process.crit_section );
PE_InitTls();
MODULE_DllProcessAttach( current_process.exe_modref, (LPVOID)1 );
LeaveCriticalSection( ¤t_process.crit_section );
+ /* Get pointers to USER routines called by KERNEL */
+ THUNK_InitCallout();
+
+ /* Call FinalUserInit routine */
+ if (Callout.FinalUserInit16) Callout.FinalUserInit16();
+
+ /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
+ * context of the parent process. Actually, the USER signal proc
+ * doesn't really care about that, but it *does* require that the
+ * startup parameters are correctly set up, so that GetProcessDword
+ * works. Furthermore, before calling the USER signal proc the
+ * 16-bit stack must be set up, which it is only after TASK_Create
+ * in the case of a 16-bit process. Thus, we send the signal here.
+ */
+ PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 );
+ PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );
+ PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
+ PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );
/* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
if (console_app) PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 );
diff --git a/scheduler/thread.c b/scheduler/thread.c
index 9647432..4b0f128 100644
--- a/scheduler/thread.c
+++ b/scheduler/thread.c
@@ -374,7 +374,7 @@
else
{
MODULE_DllThreadDetach( NULL );
- if (!(NtCurrentTeb()->tibflags & TEBF_WIN32)) TASK_KillTask( 0 );
+ if (!(NtCurrentTeb()->tibflags & TEBF_WIN32)) TASK_ExitTask();
SYSDEPS_ExitThread( code );
}
}
diff --git a/win32/except.c b/win32/except.c
index ecfe933..4ed1033 100644
--- a/win32/except.c
+++ b/win32/except.c
@@ -282,7 +282,10 @@
void WINAPI FatalAppExitA( UINT action, LPCSTR str )
{
WARN("AppExit\n");
- Callout.MessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
+ if (Callout.MessageBoxA)
+ Callout.MessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
+ else
+ ERR( "%s\n", debugstr_a(str) );
ExitProcess(0);
}
@@ -293,6 +296,9 @@
void WINAPI FatalAppExitW( UINT action, LPCWSTR str )
{
WARN("AppExit\n");
- Callout.MessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
+ if (Callout.MessageBoxW)
+ Callout.MessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
+ else
+ ERR( "%s\n", debugstr_w(str) );
ExitProcess(0);
}