This patch is really sketchy but it worked for me so I'll share ->


Theory behind the NT Fix for Final Liberation by AQRIT
----------------------------------------------------------
The game crashes when it is minimized... 

If we pause execution of the game in some way while it is minimized
we can prevent the game from doing whatever it is doing that causes a crash?

so hook PeekMessage() and watch for a message thats says
'hey minimize your window'

then keep the game trapped in an infinte loop
until a message comes across that says 
'hey restore your window'

if "Run this program in compatibility mode:" ... is enabled
the PeekMessage IAT is hook by AcLayers pre-runtime...
so after disabling compatibility mode...

Start looking at the messages returned by PeekMessage
there is no WM_SIZE message coming across?
(is this message being eaten/redirected to directX?)
(or is it being sent directly to the wndproc and not being posted?)

So instead watch for a WM_PALETTECHANGED message
to signal that the window has been minimized

---
and watch for a WM_SYSCOMMAND specifing SC_RESTORE
to signal that the window should be restored

which means if you choose the 'bring to front' option in task manager
the program will still be frozen after its restored... :(


// call IDirectDraw::TestCooperativeLevel if Interface v4?

---


// here is my PeekMessageA Hook for testing purposes
bool __stdcall PeekMsgHook( MSG * pMsg, HWND hWnd, 
	UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
{
	bool bResult;
	if(bResult = PeekMsg( pMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg )){
		if(pMsg->message == WM_PALETTECHANGED){ // if minimizing
			while(true){ // trap in an infinite loop
				DispatchMsg(pMsg);
				Snooze(100);
				if(bResult = PeekMsg(pMsg,0,0,0,1)){
					if(pMsg->message == WM_SYSCOMMAND)
						if(pMsg->wParam == SC_RESTORE)
							return bResult; // escape from loop
				}
			}
		}
	}
	return bResult;
}


The game itself no longer crashes when flipping between windows
but when the DoVideo option is re-enabled the movies no longer play
its just a blank screen...

So I broke out my debugger :)

//// revised 07/09 ////
// I ended up looking at a call the game makes to ddrawSurface->Lock()
//
// The game checks the returned value of this function
// against 887601C2 ( DDERR_SURFACELOST )
// and calls ddrawSurface->Restore() if DDERR_SURFACELOST 

A quick hack to get the movies working
is to patch the code when SmackOpen() is called
changing the test against 887601C2 to a test against some value
other than zero and 887601C2 ( like 0xDEADBEEF )
and restoring the orginal test when SmackClosed() is called...

of course when writting a release I don't want to be hooking the IAT and
I don't want to be writting to write protected memory...
 
I need to know when a movie is playing and when its not...
so I fire up a memory scanner and find a memory location
which appears to signify whether or not a movie is playing

and I make an assumption based on its value :P
 
The patch code was written byte-by-byte so the source isn't much to look at :)
but here it is anyways:
-------------------------------------------------------------------------

/*** hook test of PeekMessage return value: ***/
004561AD    0F85 736C0200     JNZ Epic40k.0047CE26
(ESP is a pointer to a MSG struct)

/*** Msg hook proc (in code cave): ***/
0047CE26    817C24 04 11030000   CMP DWORD PTR SS:[ESP+4],311         ; WM_PALETTECHANGED
0047CE2E    75 3B                JNZ SHORT Epic40k.0047CE6B
0047CE30    54                   PUSH ESP
0047CE31    E8 44FDFFFF          CALL <JMP.&USER32.TranslateMessage>  ; call 0047CB7A
0047CE36    54                   PUSH ESP
0047CE37    E8 38FDFFFF          CALL <JMP.&USER32.DispatchMessageA>  ; call 0047CB74
0047CE3C    6A 64                PUSH 64
0047CE3E    E8 4FFDFFFF          CALL <JMP.&KERNEL32.Sleep>           ; call 0047CB92
0047CE43    8BC4                 MOV EAX,ESP
0047CE45    6A 01                PUSH 1
0047CE47    6A 00                PUSH 0
0047CE49    6A 00                PUSH 0
0047CE4B    6A 00                PUSH 0
0047CE4D    50                   PUSH EAX
0047CE4E    E8 2DFDFFFF          CALL <JMP.&USER32.PeekMessageA>      ; call 0047CB80
0047CE53    84C0                 TEST AL,AL
0047CE55    74 E5                JE SHORT Epic40k.0047CE3C
0047CE57    817C24 04 12010000   CMP DWORD PTR SS:[ESP+4],112         ; WM_SYSCOMMAND
0047CE5F    75 CF                JNZ SHORT Epic40k.0047CE30
0047CE61    817C24 08 20F10000   CMP DWORD PTR SS:[ESP+8],0F120       ; SC_RESTORE
0047CE69    75 C5                JNZ SHORT Epic40k.0047CE30
0047CE6B    E9 9094FDFF          JMP Epic40k.00456300

81 7C 24 04 11 03 00 00 75 3B 54 E8 44 FD FF FF 54 E8 38 FD FF FF 6A 64 E8 4F FD FF FF 8B C4 6A
01 6A 00 6A 00 6A 00 50 E8 2D FD FF FF 84 C0 74 E5 81 7C 24 04 12 01 00 00 75 CF 81 7C 24 08 20
F1 00 00 75 C5 E9 90 94 FD FF

-----------------------------------------------------------------------------------------------


/* Hook test of DDRAW->Lock() return value */

/*** Hook Code: ***/
00453D0F      E8 5C920200   CALL Epic40k.0047CF70

/*** Hook Proc (in code cave): ***/
0047CF70        50              PUSH EAX                    ; preserve EAX (for now :p)
0047CF71        8BC4            MOV EAX,ESP                 ;;;  
0047CF73        83C0 04         ADD EAX,4                   ;;; this is so we have a    
0047CF76        8B00            MOV EAX,DWORD PTR DS:[EAX]  ;;; relative address... 
0047CF78        05 F0030600     ADD EAX,603F0               ;;; 004B4104 - video playing flag?
0047CF7D        8338 01         CMP DWORD PTR DS:[EAX],1    ; test if a movie is playing
0047CF80        58              POP EAX                     ; restore eax
0047CF81        74 06           JE SHORT Epic40k.0047CF89   ; if a movie is playing jump over the next two lines
0047CF83        3D C2017688     CMP EAX,887601C2            ; else do the orginal code (which was overwritten)
0047CF88        C3              RETN                        ; return to normal program flow
0047CF89        58              POP EAX                     ; kill the return address
0047CF8A        E9 AA6DFDFF     JMP Epic40k.00453D39        ; transfer flow to play the movie code...

50 8B C4 83 C0 04 8B 00 05 F0 03 06 00 83 38 01 58 74 06 3D C2 01 76 88 C3 58 E9 AA 6D FD FF