summaryrefslogtreecommitdiffstats
path: root/private/mvdm/wow32
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/mvdm/wow32/debug.c2063
-rw-r--r--private/mvdm/wow32/fastwow.h81
-rw-r--r--private/mvdm/wow32/i386/callpr32.asm124
-rw-r--r--private/mvdm/wow32/i386/fastwow.asm891
-rw-r--r--private/mvdm/wow32/i386/sources3
-rw-r--r--private/mvdm/wow32/isvwow.h85
-rw-r--r--private/mvdm/wow32/isz.h53
-rw-r--r--private/mvdm/wow32/makefile13
-rw-r--r--private/mvdm/wow32/makefile.inc10
-rw-r--r--private/mvdm/wow32/mapembed.c503
-rw-r--r--private/mvdm/wow32/mapembed.h75
-rw-r--r--private/mvdm/wow32/precomp.h116
-rw-r--r--private/mvdm/wow32/sources153
-rw-r--r--private/mvdm/wow32/sz.src45
-rw-r--r--private/mvdm/wow32/thunkdll.txt22
-rw-r--r--private/mvdm/wow32/waccel.c412
-rw-r--r--private/mvdm/wow32/waccel.h34
-rw-r--r--private/mvdm/wow32/walias.c686
-rw-r--r--private/mvdm/wow32/walias.h416
-rw-r--r--private/mvdm/wow32/walloc16.c271
-rw-r--r--private/mvdm/wow32/wcall16.c819
-rw-r--r--private/mvdm/wow32/wcall16.h50
-rw-r--r--private/mvdm/wow32/wcall32.c352
-rw-r--r--private/mvdm/wow32/wcall32.h29
-rw-r--r--private/mvdm/wow32/wcmdgtbl.h48
-rw-r--r--private/mvdm/wow32/wcntl32.c1116
-rw-r--r--private/mvdm/wow32/wcntl32.h53
-rw-r--r--private/mvdm/wow32/wcommdlg.c2489
-rw-r--r--private/mvdm/wow32/wcommdlg.h26
-rw-r--r--private/mvdm/wow32/wctlm32.c232
-rw-r--r--private/mvdm/wow32/wctlm32.h15
-rw-r--r--private/mvdm/wow32/wcurcash.c197
-rw-r--r--private/mvdm/wow32/wcurcash.h31
-rw-r--r--private/mvdm/wow32/wcuricon.c1114
-rw-r--r--private/mvdm/wow32/wcuricon.h96
-rw-r--r--private/mvdm/wow32/wdde.c1138
-rw-r--r--private/mvdm/wow32/wdde.h120
-rw-r--r--private/mvdm/wow32/wddeml32.c1360
-rw-r--r--private/mvdm/wow32/wddeml32.h68
-rw-r--r--private/mvdm/wow32/wddetbl2.h62
-rw-r--r--private/mvdm/wow32/wdib.c859
-rw-r--r--private/mvdm/wow32/wdib.h86
-rw-r--r--private/mvdm/wow32/wdos.c823
-rw-r--r--private/mvdm/wow32/wdos.h24
-rw-r--r--private/mvdm/wow32/wgdi.c4496
-rw-r--r--private/mvdm/wow32/wgdi.h162
-rw-r--r--private/mvdm/wow32/wgdi31.c1105
-rw-r--r--private/mvdm/wow32/wgdi31.h107
-rw-r--r--private/mvdm/wow32/wgfont.c466
-rw-r--r--private/mvdm/wow32/wgfont.h43
-rw-r--r--private/mvdm/wow32/wgman.c18
-rw-r--r--private/mvdm/wow32/wgman.h12
-rw-r--r--private/mvdm/wow32/wgmeta.c562
-rw-r--r--private/mvdm/wow32/wgmeta.h39
-rw-r--r--private/mvdm/wow32/wgpal.c292
-rw-r--r--private/mvdm/wow32/wgpal.h27
-rw-r--r--private/mvdm/wow32/wgprnset.c574
-rw-r--r--private/mvdm/wow32/wgprnset.h23
-rw-r--r--private/mvdm/wow32/wgtbl.h23
-rw-r--r--private/mvdm/wow32/wgtbl2.h602
-rw-r--r--private/mvdm/wow32/wgtext.c294
-rw-r--r--private/mvdm/wow32/wgtext.h27
-rw-r--r--private/mvdm/wow32/wheap.c48
-rw-r--r--private/mvdm/wow32/wheap.h36
-rw-r--r--private/mvdm/wow32/win30api.xlsbin0 -> 106689 bytes
-rw-r--r--private/mvdm/wow32/winsockp.h195
-rw-r--r--private/mvdm/wow32/winspldl.h28
-rw-r--r--private/mvdm/wow32/wintype.xlsbin0 -> 3726 bytes
-rw-r--r--private/mvdm/wow32/witbl.h23
-rw-r--r--private/mvdm/wow32/wkbdtbl2.h177
-rw-r--r--private/mvdm/wow32/wkbman.c225
-rw-r--r--private/mvdm/wow32/wkbman.h31
-rw-r--r--private/mvdm/wow32/wkbtbl.h23
-rw-r--r--private/mvdm/wow32/wkernel.c816
-rw-r--r--private/mvdm/wow32/wkernel.h89
-rw-r--r--private/mvdm/wow32/wkfileio.c2214
-rw-r--r--private/mvdm/wow32/wkfileio.h63
-rw-r--r--private/mvdm/wow32/wkglobal.c341
-rw-r--r--private/mvdm/wow32/wkglobal.h33
-rw-r--r--private/mvdm/wow32/wkgthunk.c583
-rw-r--r--private/mvdm/wow32/wkgthunk.h18
-rw-r--r--private/mvdm/wow32/wklocal.c224
-rw-r--r--private/mvdm/wow32/wklocal.h27
-rw-r--r--private/mvdm/wow32/wkman.c4970
-rw-r--r--private/mvdm/wow32/wkman.h140
-rw-r--r--private/mvdm/wow32/wkmem.c170
-rw-r--r--private/mvdm/wow32/wkmem.h20
-rw-r--r--private/mvdm/wow32/wktbl.h23
-rw-r--r--private/mvdm/wow32/wktbl2.h383
-rw-r--r--private/mvdm/wow32/wmdisp32.c2602
-rw-r--r--private/mvdm/wow32/wmdisp32.h130
-rw-r--r--private/mvdm/wow32/wmmalias.c373
-rw-r--r--private/mvdm/wow32/wmmalias.h95
-rw-r--r--private/mvdm/wow32/wmmedia.c357
-rw-r--r--private/mvdm/wow32/wmmedia.h311
-rw-r--r--private/mvdm/wow32/wmmedia1.c555
-rw-r--r--private/mvdm/wow32/wmmedia2.c3382
-rw-r--r--private/mvdm/wow32/wmmstru1.c1579
-rw-r--r--private/mvdm/wow32/wmmstru2.c539
-rw-r--r--private/mvdm/wow32/wmmstruc.c762
-rw-r--r--private/mvdm/wow32/wmmstruc.h146
-rw-r--r--private/mvdm/wow32/wmmtbl.h23
-rw-r--r--private/mvdm/wow32/wmmtbl2.h18
-rw-r--r--private/mvdm/wow32/wmsg16.c1534
-rw-r--r--private/mvdm/wow32/wmsg16.h55
-rw-r--r--private/mvdm/wow32/wmsgbm.c97
-rw-r--r--private/mvdm/wow32/wmsgbm.h27
-rw-r--r--private/mvdm/wow32/wmsgcb.c198
-rw-r--r--private/mvdm/wow32/wmsgcb.h21
-rw-r--r--private/mvdm/wow32/wmsgem.c288
-rw-r--r--private/mvdm/wow32/wmsgem.h21
-rw-r--r--private/mvdm/wow32/wmsglb.c243
-rw-r--r--private/mvdm/wow32/wmsglb.h21
-rw-r--r--private/mvdm/wow32/wmsgsbm.c136
-rw-r--r--private/mvdm/wow32/wmsgsbm.h21
-rw-r--r--private/mvdm/wow32/wmtbl32.c1324
-rw-r--r--private/mvdm/wow32/wmtbl32.h34
-rw-r--r--private/mvdm/wow32/wole2.c371
-rw-r--r--private/mvdm/wow32/wole2.h24
-rw-r--r--private/mvdm/wow32/wow32.c2376
-rw-r--r--private/mvdm/wow32/wow32.def43
-rw-r--r--private/mvdm/wow32/wow32.h675
-rw-r--r--private/mvdm/wow32/wow32.prf409
-rw-r--r--private/mvdm/wow32/wow32.rc26
-rw-r--r--private/mvdm/wow32/wow32.tt125
-rw-r--r--private/mvdm/wow32/wow32fax.c1063
-rw-r--r--private/mvdm/wow32/wowdde.h20
-rw-r--r--private/mvdm/wow32/wowhooks.c1997
-rw-r--r--private/mvdm/wow32/wowhooks.h185
-rw-r--r--private/mvdm/wow32/wowtable.h21
-rw-r--r--private/mvdm/wow32/wowtbl.c260
-rw-r--r--private/mvdm/wow32/wowtbl.h58
-rw-r--r--private/mvdm/wow32/wparam.c666
-rw-r--r--private/mvdm/wow32/wparam.h85
-rw-r--r--private/mvdm/wow32/wreldc.c289
-rw-r--r--private/mvdm/wow32/wreldc.h41
-rw-r--r--private/mvdm/wow32/wres16.c654
-rw-r--r--private/mvdm/wow32/wres16.h48
-rw-r--r--private/mvdm/wow32/wres32.c126
-rw-r--r--private/mvdm/wow32/wres32.h21
-rw-r--r--private/mvdm/wow32/wsdata.c1875
-rw-r--r--private/mvdm/wow32/wsdynmc.h53
-rw-r--r--private/mvdm/wow32/wsext.c893
-rw-r--r--private/mvdm/wow32/wshell.c1178
-rw-r--r--private/mvdm/wow32/wshell.h51
-rw-r--r--private/mvdm/wow32/wshltbl.h25
-rw-r--r--private/mvdm/wow32/wshtbl2.h138
-rw-r--r--private/mvdm/wow32/wsman.c25
-rw-r--r--private/mvdm/wow32/wsman.h20
-rw-r--r--private/mvdm/wow32/wsocktbl.h71
-rw-r--r--private/mvdm/wow32/wspool.c326
-rw-r--r--private/mvdm/wow32/wspool.h63
-rw-r--r--private/mvdm/wow32/wsraw.c2290
-rw-r--r--private/mvdm/wow32/wstbl.h23
-rw-r--r--private/mvdm/wow32/wstbl2.h34
-rw-r--r--private/mvdm/wow32/wstruc.c1681
-rw-r--r--private/mvdm/wow32/wstruc.h313
-rw-r--r--private/mvdm/wow32/wsubcls.c587
-rw-r--r--private/mvdm/wow32/wsubcls.h41
-rw-r--r--private/mvdm/wow32/wthman.c20
-rw-r--r--private/mvdm/wow32/wthman.h15
-rw-r--r--private/mvdm/wow32/wthtbl.h24
-rw-r--r--private/mvdm/wow32/wthtbl2.h16
-rw-r--r--private/mvdm/wow32/wuansi.h23
-rw-r--r--private/mvdm/wow32/wucaret.c336
-rw-r--r--private/mvdm/wow32/wucaret.h23
-rw-r--r--private/mvdm/wow32/wuclass.c1052
-rw-r--r--private/mvdm/wow32/wuclass.h27
-rw-r--r--private/mvdm/wow32/wuclip.c1245
-rw-r--r--private/mvdm/wow32/wuclip.h57
-rw-r--r--private/mvdm/wow32/wucomm.c2616
-rw-r--r--private/mvdm/wow32/wucomm.h315
-rw-r--r--private/mvdm/wow32/wucursor.c395
-rw-r--r--private/mvdm/wow32/wucursor.h22
-rw-r--r--private/mvdm/wow32/wudlg.c1489
-rw-r--r--private/mvdm/wow32/wudlg.h42
-rw-r--r--private/mvdm/wow32/wuhook.c642
-rw-r--r--private/mvdm/wow32/wuhook.h26
-rw-r--r--private/mvdm/wow32/wulang.c371
-rw-r--r--private/mvdm/wow32/wulang.h33
-rw-r--r--private/mvdm/wow32/wuman.c287
-rw-r--r--private/mvdm/wow32/wuman.h21
-rw-r--r--private/mvdm/wow32/wumenu.c1613
-rw-r--r--private/mvdm/wow32/wumenu.h35
-rw-r--r--private/mvdm/wow32/wumsg.c2225
-rw-r--r--private/mvdm/wow32/wumsg.h43
-rw-r--r--private/mvdm/wow32/wuser.c3555
-rw-r--r--private/mvdm/wow32/wuser.h93
-rw-r--r--private/mvdm/wow32/wuser31.c931
-rw-r--r--private/mvdm/wow32/wuser31.h87
-rw-r--r--private/mvdm/wow32/wusercli.c711
-rw-r--r--private/mvdm/wow32/wusercli.h98
-rw-r--r--private/mvdm/wow32/wutbl.h24
-rw-r--r--private/mvdm/wow32/wutbl2.h659
-rw-r--r--private/mvdm/wow32/wutext.c72
-rw-r--r--private/mvdm/wow32/wutext.h17
-rw-r--r--private/mvdm/wow32/wutmr.c686
-rw-r--r--private/mvdm/wow32/wutmr.h72
-rw-r--r--private/mvdm/wow32/wuwind.c3092
-rw-r--r--private/mvdm/wow32/wuwind.h68
-rw-r--r--private/mvdm/wow32/wwstbl2.h198
201 files changed, 94573 insertions, 0 deletions
diff --git a/private/mvdm/wow32/debug.c b/private/mvdm/wow32/debug.c
new file mode 100644
index 000000000..98a534760
--- /dev/null
+++ b/private/mvdm/wow32/debug.c
@@ -0,0 +1,2063 @@
+/******************************Module*Header*******************************\
+* Module Name: debug.c
+*
+* This file is for debugging tools and extensions.
+*
+* Created: 24-Jan-1992
+* Author: John Colleran
+*
+* History:
+* Feb 17 92 Matt Felton (mattfe) lots of additional exentions for filtering
+* Jul 13 92 (v-cjones) Added API & MSG profiling debugger extensions, fixed
+* other extensions to handle segment motion correctly,
+* & cleaned up the file in general
+*
+*
+* Copyright (c) 1992 Microsoft Corporation
+\**************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <winerror.h>
+#include <excpt.h>
+#include <ntstatus.h>
+#include <ntdbg.h>
+#define NOEXTAPI // wesw is a bonehead sometimes
+#include <wdbgexts.h>
+#include <ctype.h>
+
+//
+// Local function prototypes
+//
+
+INT WDahtoi(LPSZ lpsz);
+
+
+//
+// fWinDbg tells us if the debugger calling us uses the WinDbg or Ntsd
+// interface.
+//
+BOOL fWinDbg;
+
+/****** macros common to all versions *******/
+#define ARGLIST HANDLE hCurrentProcess, \
+ HANDLE hCurrentThread, \
+ DWORD dwCurrentPc, \
+ PWINDBG_EXTENSION_APIS lpExtensionApis, \
+ LPSTR lpArgumentString
+
+#define UNREFERENCED_PARAMETERS() \
+ UNREFERENCED_PARAMETER(hCurrentProcess); \
+ UNREFERENCED_PARAMETER(hCurrentThread); \
+ UNREFERENCED_PARAMETER(dwCurrentPc); \
+ UNREFERENCED_PARAMETER(lpExtensionApis); \
+ UNREFERENCED_PARAMETER(lpArgumentString); \
+ fWinDbg = (lpExtensionApis->nSize >= sizeof(WINDBG_EXTENSION_APIS));
+
+
+
+
+
+/***************************/
+/*** DEBUG_OR_WOWPROFILE ***/
+/***************************/
+#ifdef DEBUG_OR_WOWPROFILE
+
+/********* define the WINDBG API pointers *********/
+PWINDBG_OUTPUT_ROUTINE Print;
+PWINDBG_GET_EXPRESSION GetExpression;
+PWINDBG_GET_SYMBOL GetSymbol;
+
+PWINDBG_READ_PROCESS_MEMORY_ROUTINE ReadMem;
+PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE WriteMem;
+
+
+/********* define several handy macros *********/
+
+
+#define READMEM( Handle, Src, Dst, Size, ReadCount ) \
+ if ( fWinDbg ) { \
+ ReadMem = lpExtensionApis->lpReadProcessMemoryRoutine; \
+ ReadMem( (DWORD)Src, Dst, Size, ReadCount ); \
+ } else { \
+ ReadProcessMemory( Handle, Src, Dst, Size, ReadCount ); \
+ }
+
+#define WRITEMEM( Handle, Dst, Src, Size, WriteCount ) \
+ if ( fWinDbg ) { \
+ WriteMem = lpExtensionApis->lpWriteProcessMemoryRoutine; \
+ WriteMem( (DWORD)Src, Dst, Size, WriteCount ); \
+ } else { \
+ WriteProcessMemory( Handle, Dst, Src, Size, WriteCount ); \
+ }
+
+
+#define READWOW(dst, src)\
+try {\
+ Print = lpExtensionApis->lpOutputRoutine;\
+ READMEM( hCurrentProcess, (LPVOID)(src), (LPVOID)&(dst), sizeof(dst), NULL);\
+} except (EXCEPTION_EXECUTE_HANDLER) {\
+ Print("ReadProcessMemory Failed !\n");\
+ return;\
+}
+
+
+#define READWOW2(dst, src, ret)\
+try {\
+ Print = lpExtensionApis->lpOutputRoutine;\
+ READMEM(hCurrentProcess, (LPVOID) (src), (LPVOID)&(dst), sizeof(dst), NULL);\
+} except (EXCEPTION_EXECUTE_HANDLER) {\
+ Print("ReadProcessMemory Failed !\n");\
+ return ret;\
+}
+
+
+#define WRITEWOW(dst, src)\
+try {\
+ Print = lpExtensionApis->lpOutputRoutine;\
+ WRITEMEM(hCurrentProcess, (LPVOID)(dst), (LPVOID)&(src), sizeof(src), NULL);\
+} except (EXCEPTION_EXECUTE_HANDLER) {\
+ Print("WriteProcessMemory Failed !\n");\
+ return;\
+}
+
+#define WRITENWOW(dst, src, n)\
+try {\
+ Print = lpExtensionApis->lpOutputRoutine;\
+ WRITEMEM(hCurrentProcess, (LPVOID)(dst), (LPVOID)(src), n, NULL);\
+} except (EXCEPTION_EXECUTE_HANDLER) {\
+ Print("WriteProcessMemory Failed !\n");\
+ return;\
+}
+
+
+#define GETEXPRVALUE(dst, expr, typ) \
+{\
+ GetExpression = lpExtensionApis->lpGetExpressionRoutine;\
+ if (fWinDbg) {\
+ dst = (typ)GetExpression(expr);\
+ } else {\
+ PVOID lpA = (PVOID)GetExpression(expr);\
+ READWOW(dst, lpA);\
+ }\
+}
+
+#define GETEXPRADDR(dst, expr) \
+{\
+ GetExpression = lpExtensionApis->lpGetExpressionRoutine;\
+ if (fWinDbg) {\
+ LPSTR lps = malloc_w(strlen(expr)+2);\
+ *lps = '&';\
+ strcpy(lps+1, expr);\
+ dst = (PVOID)GetExpression(lps);\
+ free_w(lps);\
+ } else {\
+ dst = (PVOID)GetExpression(expr);\
+ }\
+}
+
+
+
+
+
+/*********** WOW debugger extension API's ************/
+//
+// HELP !
+//
+void help( ARGLIST )
+{
+
+ UNREFERENCED_PARAMETERS();
+
+ // set up function pointer
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ Print("WOW32 Debugger Extensions:\n");
+
+ Print(" at 0xXXXX - shows name associated with hex atom #\n");
+ Print(" cia - Dumps cursor/icon alias list\n");
+ Print(" ddte <addr> - Dump dispatch table entry pointed to by <addr>\n");
+ Print(" dt <addr> - Dump TD at <addr> or all if blank\n");
+ Print(" dwp <addr> - Dump WOWPORT structure pointed to by <addr>\n");
+ Print(" ww hwnd16 - Given a hwnd16 it dumps the WOW Window structure\n");
+ Print(" wc hwnd16 - Given a hwnd16 it dumps the WOW Class structure\n");
+ Print(" ClearFilter - All Filters Are turned OFF\n");
+ Print(" ClearFilterSpecific - Clears FilterSpecific function\n");
+ Print(" FilterGDI - Toggles Filtering of GDI Calls On/Off\n");
+ Print(" FilterKernel - Toggles Filtering of Kernel Calls On/Off\n");
+ Print(" FilterKernel16 - Toggles Filtering of Kernel16 Calls On/Off\n");
+ Print(" FilterKeyboard - Toggles Filtering of Keyboard Calls On/Off\n");
+ Print(" FilterMMedia - Toggles Filtering of MMedia Calls On/Off\n");
+ Print(" FilterWinsock - Toggles Filtering of Winsock Calls On/Off\n");
+ Print(" FilterSound - Toggles Filtering of Sound Calls On/Off\n");
+ Print(" FilterCommdlg - Toggles Filtering of Commdlg Calls On/Off\n");
+ Print(" FilterSpecific xxxx - Adds api to list to be filtered\n");
+ Print(" FilterTask xxxx - Filter on a Specific TaskID\n");
+ Print(" FilterUser - Toggles Filtering of User Calls On/Off\n");
+ Print(" FilterVerbose - Toggles Verbose Mode On/Off\n");
+ Print(" LastLog - Dumps Last Logged APIs from Circular Buffer\n");
+ Print(" LogFile [filespec] - Create/close toggle for iloglevel capture to file\n");
+ Print(" (no filespec defaults to c:\\ilog.log)\n");
+ Print(" ResetFilter - All Filters are turned ON\n");
+ Print(" SetLogLevel xx - Sets the WOW Logging Level\n");
+ Print(" StepTrace - Toggles Single Step Tracing On/Off\n");
+
+ Print(" APIProfClr - Clears the WOW API profiler table\n");
+ Print(" APIProfDmp help - Dumps the WOW API profiler table\n");
+ Print(" MSGProfClr - Clears the WOW MSG profiler table\n");
+ Print(" MSGProfDmp help - Dumps the WOW MSG profiler table\n");
+ Print(" MSGProfRT - Toggles MSG prof round trip/thunks only\n");
+
+ return;
+}
+
+//
+// 16:16 to flat pointer translation functions for debugger extensions.
+//
+
+#ifndef _X86_
+DWORD pIntelBase = 0;
+
+VOID WDInitIntelBase(HANDLE hCurrentProcess, PWINDBG_EXTENSION_APIS lpExtensionApis)
+{
+ GETEXPRVALUE(pIntelBase, "wow32!IntelMemoryBase", DWORD);
+}
+
+#define WD_INTEL_MEMORY_BASE (pIntelBase)
+#define WD_INIT_INTEL_BASE_IF_NEEDED \
+{ \
+ if (!pIntelBase) { \
+ WDInitIntelBase(hCurrentProcess, lpExtensionApis); \
+ } \
+}
+#else
+#define WD_INTEL_MEMORY_BASE (0)
+#define WD_INIT_INTEL_BASE_IF_NEEDED {}
+#endif
+
+
+#define FlatFromReal(vp) FlatFromRealPtr(lpExtensionApis, hCurrentProcess, (vp))
+PVOID FlatFromRealPtr(PWINDBG_EXTENSION_APIS lpExtensionApis, HANDLE hCurrentProcess, DWORD vp)
+{
+ UNREFERENCED_PARAMETER(hCurrentProcess); // On x86 only.
+
+ WD_INIT_INTEL_BASE_IF_NEEDED;
+
+ return (PVOID) (WD_INTEL_MEMORY_BASE + (((vp) & 0xFFFF0000) >> 12) +
+ ((vp) & 0xFFFF));
+}
+
+
+#define FlatFromProt(vp) FlatFromProtPtr(lpExtensionApis, hCurrentProcess, (vp))
+PVOID FlatFromProtPtr(PWINDBG_EXTENSION_APIS lpExtensionApis, HANDLE hCurrentProcess, DWORD vp)
+{
+ PDWORD WDFlatAddress;
+ DWORD FlatAddrEntry;
+
+ GETEXPRADDR(WDFlatAddress, "ntvdm!FlatAddress");
+ READWOW2(FlatAddrEntry, (WDFlatAddress + (vp >> 19)), NULL);
+
+ return FlatAddrEntry
+ ? (PVOID)(FlatAddrEntry + (vp & 0xFFFF))
+ : NULL;
+}
+
+
+VOID dwp( ARGLIST )
+{
+ PWOWPORT pwp;
+ WOWPORT wp;
+
+
+ UNREFERENCED_PARAMETERS();
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ while (' ' == lpArgumentString[0]) {
+ lpArgumentString++;
+ }
+
+ pwp = (PWOWPORT) WDahtoi(lpArgumentString);
+
+ Print("Dump of WOWPORT structure at 0x%x:\n\n", (unsigned)pwp);
+
+
+ try {
+
+ READWOW(wp, pwp);
+
+ } except (EXCEPTION_ACCESS_VIOLATION == GetExceptionCode()
+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+
+ Print("Access violation reading WOWPORT structure!\n\n");
+ return;
+ }
+
+ Print("idComDev 0x%x\n", (unsigned)wp.idComDev);
+ Print("h32 0x%x\n", (unsigned)wp.h32);
+ Print("hREvent 0x%x\n", (unsigned)wp.hREvent);
+ Print("csWrite OwningThread 0x%x RecursionCount 0x%x\n",
+ (unsigned)wp.csWrite.OwningThread, (unsigned)wp.csWrite.RecursionCount);
+ Print("pchWriteBuf 0x%x\n", (unsigned)wp.pchWriteBuf);
+ Print("cbWriteBuf 0x%x\n", (unsigned)wp.cbWriteBuf);
+ Print("pchWriteHead 0x%x\n", (unsigned)wp.pchWriteHead);
+ Print("pchWriteTail 0x%x\n", (unsigned)wp.pchWriteTail);
+ Print("cbWriteFree 0x%x\n", (unsigned)wp.cbWriteFree);
+ Print("hWriteThread 0x%x\n", (unsigned)wp.hWriteThread);
+ Print("hWriteEvent 0x%x\n", (unsigned)wp.hWriteEvent);
+ Print("dwThreadID 0x%x\n", (unsigned)wp.dwThreadID);
+ Print("dwErrCode 0x%x\n", (unsigned)wp.dwErrCode);
+ Print("COMSTAT addr: 0x%x\n", (unsigned)(((char *)&wp.cs - (char *)&wp) + (char *)pwp));
+ Print("fChEvt 0x%x\n", (unsigned)wp.fChEvt);
+ Print("pdcb16 0x%x\n", (unsigned)wp.pdcb16);
+ Print("fUnGet %s\n", wp.fUnGet ? "TRUE" : "FALSE");
+ Print("cUnGet 0x%x (%c)\n", (unsigned)wp.cUnGet, wp.cUnGet);
+ Print("hMiThread 0x%x\n", (unsigned)wp.hMiThread);
+ Print("fClose %s\n", wp.fClose ? "TRUE" : "FALSE");
+ Print("dwComDEB16 0x%x\n", (unsigned)wp.dwComDEB16);
+ Print("lpComDEB16 0x%x\n", (unsigned)wp.lpComDEB16);
+
+ Print("\n");
+
+ return;
+}
+
+
+VOID dt( ARGLIST ) // dump WOW32 task database entry
+{
+
+ TD td;
+ PTD ptd;
+ PWOAINST pWOA, pWOALast;
+ PTDB ptdb;
+ BOOL fAll = FALSE;
+ BYTE SavedByte;
+
+ UNREFERENCED_PARAMETERS();
+
+ Print = lpExtensionApis->lpOutputRoutine;
+ GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
+
+ while (' ' == lpArgumentString[0]) {
+ lpArgumentString++;
+ }
+
+ ptd = (PTD) WDahtoi(lpArgumentString);
+
+
+ if (!ptd) {
+
+ fAll = TRUE;
+ GETEXPRVALUE(ptd, "wow32!gptdTaskHead", PTD);
+ if (!ptd) {
+ Print("Could not get wow32!gptdTaskHead");
+ return;
+ }
+ Print("Dump WOW task list\n\n");
+
+ }
+
+ do {
+
+ Print("Dump of TD at 0x%08x:\n\n", (unsigned)ptd);
+
+ try {
+
+ READWOW(td, ptd);
+
+ } except (1) {
+
+ Print("Exception 0x%08x reading TD at 0x%08x!\n\n",
+ GetExceptionCode(), ptd);
+ return;
+ }
+
+
+ Print("vpStack %04x:%04x\n", HIWORD(td.vpStack), LOWORD(td.vpStack));
+ Print("vpCBStack %04x:%04x\n", HIWORD(td.vpCBStack), LOWORD(td.vpCBStack));
+ Print("ptdNext 0x%08x\n", td.ptdNext);
+ Print("dwFlags 0x%08x\n", td.dwFlags);
+
+ //
+ // Dump symbolic names for TDF_ manifests
+ //
+
+ if (td.dwFlags & TDF_INITCALLBACKSTACK) {
+ Print(" TDF_INITCALLBACKSTACK\n");
+ }
+ if (td.dwFlags & TDF_IGNOREINPUT) {
+ Print(" TDF_IGNOREINPUT\n");
+ }
+
+ Print("VDMInfoiTaskID 0x%08x\n", td.VDMInfoiTaskID);
+ Print("CommDlgTd (ptr) 0x%08x\n", td.CommDlgTd);
+
+ //
+ // Dump CommDlgTd structure if present
+ //
+
+ if (td.CommDlgTd) {
+
+ COMMDLGTD CommDlgTd;
+ BOOL fCopySuccessful = TRUE;
+
+ try {
+
+ READWOW(CommDlgTd, td.CommDlgTd);
+
+ } except (1) {
+
+ fCopySuccessful = FALSE;
+ Print("Exception 0x%08x reading COMMDLGTD at 0x%08x!\n\n",
+ GetExceptionCode(), td.CommDlgTd);
+ }
+
+ if (fCopySuccessful) {
+
+ Print("\n");
+ Print(" Dump of CommDlgTd at 0x%08x:\n", td.CommDlgTd);
+ Print(" hdlg 0x04x\n", CommDlgTd.hdlg);
+ Print(" vpfnHook 0x04x:0x04x\n", HIWORD(CommDlgTd.vpfnHook), LOWORD(CommDlgTd.vpfnHook));
+ Print(" vpData 0x04x:0x04x\n", HIWORD(CommDlgTd.vpData), LOWORD(CommDlgTd.vpData));
+ Print(" ExtendedErr 0x08x\n", CommDlgTd.ExtendedErr);
+ Print(" vpfnSetupHook (union) 0x04x:0x04x\n", HIWORD(CommDlgTd.vpfnSetupHook), LOWORD(CommDlgTd.vpfnSetupHook));
+ Print(" pRes (union) 0x08x\n", CommDlgTd.pRes);
+ Print(" SetupHwnd 0x04x\n", CommDlgTd.SetupHwnd);
+ Print(" Previous 0x08x\n", CommDlgTd.Previous);
+ Print(" pData32 0x08x\n", CommDlgTd.pData32);
+ Print(" Flags 0x08x\n", CommDlgTd.Flags);
+
+ //
+ // Dump symbolic names for WOWCD_ manifests
+ //
+
+ if (CommDlgTd.Flags & WOWCD_ISCHOOSEFONT) {
+ Print(" WOWCD_ISCHOOSEFONT\n");
+ }
+ if (CommDlgTd.Flags & WOWCD_ISOPENFILE) {
+ Print(" WOWCD_ISOPENFILE\n");
+ }
+
+ Print("\n");
+
+ }
+ }
+
+
+ Print("dwWOWCompatFlags 0x%08x\n", td.dwWOWCompatFlags);
+ Print("dwWOWCompatFlagsEx 0x%08x\n", td.dwWOWCompatFlags);
+ Print("dwThreadID 0x%08x\n", td.dwThreadID);
+ Print("hThread 0x%08x\n", td.hThread);
+ Print("hIdleHook 0x%08x\n", td.hIdleHook);
+ Print("hrgnClip 0x%08x\n", td.hrgnClip);
+ Print("ulLastDesktophDC 0x%08x\n", td.ulLastDesktophDC);
+ Print("pWOAList 0x%08x\n", td.pWOAList);
+
+ //
+ // Dump WOATD structure if present
+ //
+
+ pWOALast = NULL;
+ pWOA = td.pWOAList;
+
+ while (pWOA && pWOA != pWOALast) {
+
+ union {
+ WOAINST WOA;
+ char buf[128+2+16];
+ } u;
+
+ BOOL fCopySuccessful = TRUE;
+
+ try {
+
+ READWOW(u.buf, pWOA);
+
+ } except (1) {
+
+ fCopySuccessful = FALSE;
+ Print("Exception 0x%08x reading WOAINST at 0x%08x!\n\n",
+ GetExceptionCode(), pWOA);
+ }
+
+ if (fCopySuccessful) {
+
+ Print("\n");
+ Print(" Dump of WOAINST at 0x%08x:\n", pWOA);
+ Print(" pNext 0x%08x\n", u.WOA.pNext);
+ Print(" ptdWOA 0x%08x\n", u.WOA.ptdWOA);
+ Print(" dwChildProcessID 0x%08x\n", u.WOA.dwChildProcessID);
+ Print(" hChildProcess 0x%08x\n", u.WOA.hChildProcess);
+ Print(" szModuleName %s\n", u.WOA.szModuleName);
+ Print("\n");
+
+ pWOALast = pWOA;
+ pWOA = u.WOA.pNext;
+
+ } else {
+
+ pWOA = NULL;
+
+ }
+
+ }
+
+ Print("htask16 0x%04x (use \"!dtdb %x\" for complete dump)\n", td.htask16, td.htask16);
+
+ //
+ // Dump the most interesting TDB fields
+ //
+
+ if (ptdb = FlatFromProt(td.htask16 << 16)) {
+
+ TDB tdb;
+ BOOL fCopySuccessful = TRUE;
+
+ try {
+
+ READWOW(tdb, ptdb);
+
+ } except (1) {
+
+ fCopySuccessful = FALSE;
+ Print("Exception 0x%08x reading TDB at 0x%08x!\n\n",
+ GetExceptionCode(), ptdb);
+ }
+
+ if (fCopySuccessful) {
+
+ Print("\n");
+ Print(" Highlights of TDB at 0x%08x:\n", ptdb);
+
+ if (tdb.TDB_sig != TDB_SIGNATURE) {
+ Print(" TDB_sig signature is 0x%04x instead of 0x%04x, halting dump.\n",
+ tdb.TDB_sig, TDB_SIGNATURE);
+ } else {
+
+ PDOSPDB pPDB;
+ DOSPDB PDB;
+ PBYTE pJFT;
+ BYTE JFT[256];
+ WORD cbJFT;
+ PDOSSF pSFTHead, pSFTHeadCopy;
+ DOSSF SFTHead;
+ PDOSSFT pSFT;
+ WORD fh;
+ WORD SFN;
+ WORD i;
+ DWORD cb;
+ PDOSWOWDATA pDosWowData;
+ DOSWOWDATA DosWowData;
+
+ SavedByte = tdb.TDB_ModName[8];
+ tdb.TDB_ModName[8] = 0;
+ Print(" Module name \"%s\"\n", tdb.TDB_ModName);
+ tdb.TDB_ModName[8] = SavedByte;
+
+ Print(" ExpWinVer 0x%04x\n", tdb.TDB_ExpWinVer);
+ Print(" Directory \"%s\"\n", tdb.TDB_Directory);
+ Print(" PDB (aka PSP) 0x%04x\n", tdb.TDB_PDB);
+
+ //
+ // Dump open file handle info
+ //
+
+ pPDB = (PDOSPDB) FlatFromProt(tdb.TDB_PDB << 16);
+ READWOW(PDB, pPDB);
+
+ pJFT = (PBYTE) FlatFromReal(PDB.PDB_JFN_Pointer);
+ cbJFT = PDB.PDB_JFN_Length;
+
+ Print(" JFT %04x:%04x size 0x%x\n",
+ HIWORD(PDB.PDB_JFN_Pointer),
+ LOWORD(PDB.PDB_JFN_Pointer),
+ cbJFT);
+
+ try {
+ READMEM(hCurrentProcess, pJFT, JFT, cbJFT, NULL);
+ } except (1) {
+ Print("Unable to read JFT from 0x%08x!\n", pJFT);
+ return;
+ }
+
+ for (fh = 0; fh < cbJFT; fh++) {
+
+ if (JFT[fh] != 0xFF) {
+
+ //
+ // Walk the SFT chain to find Nth entry
+ // where N == JFT[fh]
+ //
+
+ SFN = 0;
+ i = 0;
+
+ GETEXPRVALUE(pSFTHead, "ntvdm!pSFTHead", PDOSSF);
+
+ GETEXPRADDR(pDosWowData, "wow32!DosWowData");
+ READWOW(DosWowData, pDosWowData);
+
+ if ((DWORD)pSFTHead != DosWowData.lpSftAddr) {
+ Print("ntvdm!pSFTHead is 0x%08x, DosWowData.lpSftAddr ix 0x%08x.\n",
+ pSFTHead, DosWowData.lpSftAddr);
+ }
+
+ try {
+ READMEM(hCurrentProcess, pSFTHead, &SFTHead, sizeof(SFTHead), NULL);
+ } except (1) {
+ Print("Unable to read SFTHead from 0x%08x!\n", pSFTHead);
+ return;
+ }
+
+ cb = sizeof(DOSSF) + SFTHead.SFCount * sizeof(DOSSFT);
+ pSFTHeadCopy = malloc_w(cb);
+
+ //Print("First DOSSF at 0x%08x, SFCount 0x%x, SFLink 0x%08x.\n",
+ // pSFTHead, SFTHead.SFCount, SFTHead.SFLink);
+
+ try {
+ READMEM(hCurrentProcess, pSFTHead, pSFTHeadCopy, cb, NULL);
+ } except (1) {
+ Print("Unable to read SFTHead from 0x%08x!\n", pSFTHead);
+ return;
+ }
+
+ pSFT = (PDOSSFT) &(pSFTHeadCopy->SFTable);
+
+ while (SFN < JFT[fh]) {
+ SFN++;
+ i++;
+ pSFT++;
+ if (i >= pSFTHeadCopy->SFCount) {
+
+ if (pSFTHeadCopy->SFLink & 0xFFFF == 0xFFFF) {
+ SFN = JFT[fh] - 1;
+ break;
+ }
+
+ pSFTHead = FlatFromReal(pSFTHeadCopy->SFLink);
+ i = 0;
+
+ try {
+ READMEM(hCurrentProcess, pSFTHead, &SFTHead, sizeof(SFTHead), NULL);
+ } except (1) {
+ Print("Unable to read SFTHead from 0x%08x!\n", pSFTHead);
+ return;
+ }
+
+ cb = sizeof(DOSSF) + SFTHead.SFCount * sizeof(DOSSFT);
+ free_w(pSFTHeadCopy);
+ pSFTHeadCopy = malloc_w(cb);
+
+ //Print("Next DOSSF at 0x%08x, SFCount 0x%x, SFLink 0x%08x.\n",
+ // pSFTHead, SFTHead.SFCount, SFTHead.SFLink);
+
+ try {
+ READMEM(hCurrentProcess, pSFTHead, pSFTHeadCopy, cb, NULL);
+ } except (1) {
+ Print("Unable to read SFTHead from 0x%08x!\n", pSFTHead);
+ return;
+ }
+
+ pSFT = (PDOSSFT) &(pSFTHeadCopy->SFTable);
+ }
+ }
+
+ if (SFN != JFT[fh]) {
+ Print(" Unable to local SFT entry 0x%x for handle 0x%x.\n",
+ pJFT[fh], fh);
+ } else {
+ Print(" Handle 0x%02x SFN 0x%02x Refs 0x%x Mode 0x%04x Attr 0x%04x NT Handle 0x%08x\n",
+ fh, SFN, pSFT->SFT_Ref_Count, pSFT->SFT_Mode, pSFT->SFT_Attr, pSFT->SFT_NTHandle);
+ }
+
+ free_w(pSFTHeadCopy);
+ }
+ }
+
+ Print("\n");
+ }
+ }
+
+ }
+
+ Print("hInst16 0x%04x\n", td.hInst16);
+ Print("hMod16 0x%04x\n", td.hMod16);
+
+ Print("\n");
+
+ ptd = td.ptdNext;
+
+ } while (fAll && ptd);
+
+ return;
+}
+
+
+VOID ddte( ARGLIST ) // dump dispatch table entry
+{
+
+ W32 dte;
+ PW32 pdte;
+ char szW32[32];
+ char szSymbol[256];
+ DWORD dwOffset;
+
+
+ UNREFERENCED_PARAMETERS();
+
+ Print = lpExtensionApis->lpOutputRoutine;
+ GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
+
+ while (' ' == lpArgumentString[0]) {
+ lpArgumentString++;
+ }
+
+ pdte = (PW32) WDahtoi(lpArgumentString);
+
+
+ if (pdte) {
+
+ Print("Dump of dispatch table entry at 0x%08x:\n\n", (unsigned)pdte);
+
+ } else {
+
+ GETEXPRADDR(pdte, "wow32!aw32WOW");
+ Print("Dump of first dispatch table entry at 0x%08x:\n\n", (unsigned)pdte);
+
+ }
+
+ try {
+
+ READWOW(dte, pdte);
+
+ if (dte.lpszW32) {
+ READWOW(szW32, dte.lpszW32);
+ dte.lpszW32 = szW32;
+ szW32[sizeof(szW32)-1] = '\0';
+ }
+
+ } except (1) {
+
+ Print("Exception 0x%08x reading dispatch table entry at 0x%08x!\n\n",
+ GetExceptionCode(), pdte);
+ return;
+ }
+
+ Print("Dispatches to address 0x%08x, ", (unsigned)dte.lpfnW32);
+ Print("supposedly function '%s'.\n", dte.lpszW32);
+
+ szSymbol[0] = '\0';
+ GetSymbol((LPVOID)dte.lpfnW32, szSymbol, &dwOffset);
+
+ Print("Debugger finds symbol '%s' for that address.\n", szSymbol);
+ Print("\n");
+
+ return;
+}
+
+
+
+/********* local functions for WOWPROFILE support *********/
+
+/******* function protoypes for local functions for WOWPROFILE support *******/
+BOOL WDGetAPIProfArgs(LPSZ lpszArgStr,
+ HANDLE hCurrentProcess,
+ PWINDBG_EXTENSION_APIS lpExtensionApis,
+ INT iThkTblMax,
+ PPA32 ppaThkTbls,
+ LPSZ lpszTab,
+ BOOL *bTblAll,
+ LPSZ lpszFun,
+ int *iFunInd);
+
+BOOL WDGetMSGProfArgs(LPSZ lpszArgStr,
+ LPSZ lpszMsg,
+ int *iMsgNum);
+
+INT WDParseArgStr(LPSZ lpszArgStr, CHAR **argv, INT iMax);
+
+
+
+
+
+INT WDParseArgStr(LPSZ lpszArgStr, CHAR **argv, INT iMax) {
+/*
+ * Parse a string looking for SPACE, TAB, & COMMA as delimiters
+ * INPUT:
+ * lpszArgStr - ptr to input arg string
+ * iMax - maximum number of substrings to parse
+ * OUTPUT:
+ * argv - ptrs to strings
+ *
+ * RETURN: # of vectors in argv
+ * NOTE: substrings are converted to uppercase
+ */
+ INT nArgs;
+ BOOL bStrStart;
+
+ nArgs = 0;
+ bStrStart = 1;
+ while( *lpszArgStr ) {
+ if( (*lpszArgStr == ' ') || (*lpszArgStr == '\t') || (*lpszArgStr == ',') ) {
+ *lpszArgStr = '\0';
+ bStrStart = 1;
+ }
+ else {
+ if( bStrStart ) {
+ if( nArgs >= iMax ) {
+ break;
+ }
+ argv[nArgs++] = lpszArgStr;
+ bStrStart = 0;
+ }
+ *lpszArgStr = toupper(*lpszArgStr);
+ }
+ lpszArgStr++;
+ }
+ return(nArgs);
+}
+
+
+
+
+BOOL WDGetAPIProfArgs(LPSZ lpszArgStr,
+ HANDLE hCurrentProcess,
+ PWINDBG_EXTENSION_APIS lpExtensionApis,
+ INT iThkTblMax,
+ PPA32 ppaThkTbls,
+ LPSZ lpszTab,
+ BOOL *bTblAll,
+ LPSZ lpszFun,
+ int *iFunInd) {
+/*
+ * Decomposes & interprets argument string to apiprofdmp extension.
+ * INPUT:
+ * lpszArgStr - ptr to input arg string
+ * iThkTblMax - # tables in the thunk tables
+ * ppaThkTbls - ptr to the thunk tables
+ * OUTPUT:
+ * lpszTab - ptr to table name
+ * bTblAll - 0 => dump specific table, 1 => dump all tables
+ * lpszFun - ptr to API name
+ * iFunInd - -1 => dump specific API name
+ * 0 => dump all API entires in table
+ * >0 => dump specific API number (decimal)
+ * RETURN: 0 => OK, 1 => input error (show Usage)
+ *
+ * legal forms: !wow32.apiprofdmp
+ * !wow32.apiprofdmp help
+ * !wow32.apiprofdmp user
+ * !wow32.apiprofdmp user createwindow
+ * !wow32.apiprofdmp user 41
+ * !wow32.apiprofdmp createwindow
+ * !wow32.apiprofdmp 41
+ */
+ INT i, nArgs;
+ CHAR *argv[2];
+
+
+ nArgs = WDParseArgStr(lpszArgStr, argv, 2);
+
+ /* if no arguments dump all entries in all tables */
+ if( nArgs == 0 ) {
+ *iFunInd = 0; // specify dump all API entires in the table
+ *bTblAll = 1; // specify dump all tables
+ return(0);
+ }
+
+ if( !_stricmp(argv[0], "HELP") ) {
+ return(1);
+ }
+
+ /* see if 1st arg is a table name */
+ *bTblAll = 1; // specify dump all tables
+
+
+ for (i = 0; i < nModNames; i++) {
+ if (!_stricmp(apszModNames[i], argv[0])) {
+
+ strcpy(lpszTab, apszModNames[i]);
+ *bTblAll = 0; // specify dump specific table
+
+ /* if we got a table name match & only one arg, we're done */
+ if( nArgs == 1 ) {
+ *iFunInd = 0; // specify dump all API entries in the table
+ return(0);
+ }
+ break;
+ }
+ }
+
+#if 0
+ for(i = 0; i < iThkTblMax; i++) {
+ CHAR temp[40], *TblEnt[2], szTabName[40];
+ PA32 awThkTbl;
+
+ /* get table name string from thunk tables */
+ READWOW2(awThkTbl, &ppaThkTbls[i], 0);
+ READWOW2(szTabName, awThkTbl.lpszW32, 0);
+
+ /* get rid of trailing spaces from table name string */
+ strcpy(temp, szTabName);
+ WDParseArgStr(temp, TblEnt, 1);
+
+ /* if we found a table name that matches the 1st arg...*/
+ if( !_stricmp(argv[0], TblEnt[0]) ) {
+
+ strcpy(lpszTab, szTabName);
+ *bTblAll = 0; // specify dump specific table
+
+ /* if we got a table name match & only one arg, we're done */
+ if( nArgs == 1 ) {
+ *iFunInd = 0; // specify dump all API entries in the table
+ return(0);
+ }
+ break;
+ }
+ }
+#endif
+
+ /* if 2 args && the 1st doesn't match a table name above => bad input */
+ if( (nArgs > 1) && (*bTblAll) ) {
+ return(1);
+ }
+
+ /* set index to API spec */
+ nArgs--;
+
+ /* try to convert API spec to a number */
+ *iFunInd = atoi(argv[nArgs]);
+ strcpy(lpszFun, argv[nArgs]);
+
+ /* if API spec is not a number => it's a name */
+ if( *iFunInd == 0 ) {
+ *iFunInd = -1; // specify API search by name
+ }
+
+ /* else if API number is bogus -- complain */
+ else if( *iFunInd < 0 ) {
+ return(1);
+ }
+
+ return(0);
+
+}
+
+
+
+BOOL WDGetMSGProfArgs(LPSZ lpszArgStr,
+ LPSZ lpszMsg,
+ int *iMsgNum) {
+/*
+ * Decomposes & interprets argument string to msgprofdmp extension.
+ * INPUT:
+ * lpszArgStr - ptr to input arg string
+ * OUTPUT:
+ * lpszMsg - ptr to message name
+ * iMsgNum - -1 => dump all message entries in the table
+ * -2 => lpszMsg contains specific MSG name
+ * >=0 => dump specific message number
+ * RETURN: 0 => OK, 1 => input error (show Usage)
+ */
+ INT nArgs;
+ CHAR *argv[2];
+
+
+ nArgs = WDParseArgStr(lpszArgStr, argv, 1);
+
+ /* if no arguments dump all entries in all tables */
+ if( nArgs == 0 ) {
+ *iMsgNum = -1; // specify dump all MSG entires in the table
+ return(0);
+ }
+
+ if( !_stricmp(argv[0], "HELP") )
+ return(1);
+
+ /* try to convert MSG spec to a number */
+ *iMsgNum = atoi(argv[0]);
+ strcpy(lpszMsg, argv[0]);
+
+ /* if MSG spec is not a number => it's a name */
+ if( *iMsgNum == 0 ) {
+ *iMsgNum = -2; // specify lpszMsg contains name to search for
+ }
+
+ /* else if MSG number is bogus -- complain */
+ else if( *iMsgNum < 0 ) {
+ return(1);
+ }
+
+ return(0);
+}
+
+
+
+
+/******* API profiler table functions ********/
+
+/* init some common strings */
+CHAR szAPI[] = "API# API Name";
+CHAR szMSG[] = "MSG Name - MSG #";
+CHAR szTITLES[] = "# Calls Tot. tics tics/call";
+CHAR szDASHES[] = "----------------------------------- ------- --------------- ---------------";
+CHAR szTOOBIG[] = "too large for table.";
+CHAR szNOTUSED[] = "Unused table index.";
+CHAR szAPIUSAGE[] = "Usage: !wow32.APIProfDmp [TblName] [APIspec]\n\n where: TblName = kernel | user | gdi | keyboard | sound | shell | mmed\n (no TblName implies 'all tables')\n\n APIspec = API # or API name";
+CHAR szMSGUSAGE[] = "Usage: !wow32.MsgProfDmp [MessageName | MessageNum (decimal)]\n (no argument implies 'all messages')";
+CHAR szRNDTRIP[] = "Round trip message profiling";
+CHAR szCLEAR[] = "Remember to clear the message profile tables.";
+
+
+VOID apiprofclr( ARGLIST )
+{
+ int iTab, iFun, iEntries;
+ INT iThkTblMax;
+ W32 awAPIEntry;
+ PW32 pawAPIEntryTbl;
+ PA32 awThkTbl;
+ PPA32 ppaThkTbls;
+ CHAR szTable[20];
+
+ UNREFERENCED_PARAMETERS();
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ GETEXPRVALUE(iThkTblMax, "wow32!iThunkTableMax", INT);
+ GETEXPRVALUE(ppaThkTbls, "wow32!pawThunkTables", PPA32);
+
+ Print("Clearing:");
+
+ for(iTab = 0; iTab < iThkTblMax; iTab++) {
+
+ READWOW(awThkTbl, &ppaThkTbls[iTab]);
+ READWOW(szTable, awThkTbl.lpszW32);
+ Print(" %s", szTable);
+
+ pawAPIEntryTbl = awThkTbl.lpfnA32;
+ READWOW(iEntries, awThkTbl.lpiFunMax);
+ for(iFun = 0; iFun < iEntries; iFun++) {
+ READWOW(awAPIEntry, &pawAPIEntryTbl[iFun]);
+ awAPIEntry.cCalls = 0L;
+ awAPIEntry.cTics = 0L;
+ WRITEWOW(&pawAPIEntryTbl[iFun], awAPIEntry);
+ }
+ }
+ Print("\n");
+
+ return;
+}
+
+
+
+VOID apiprofdmp( ARGLIST )
+{
+ BOOL bTblAll, bFound;
+ int i, iFun, iFunInd;
+ INT iThkTblMax;
+ W32 awAPIEntry;
+ PW32 pawAPIEntryTbl;
+ PA32 awThkTbl;
+ PPA32 ppaThkTbls;
+ CHAR szTab[20], szFun[40], szTable[20], szFunName[40];
+
+ UNREFERENCED_PARAMETERS();
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ GETEXPRVALUE(iThkTblMax, "wow32!iThunkTableMax", INT);
+ GETEXPRVALUE(ppaThkTbls, "wow32!pawThunkTables", PPA32);
+
+ if( WDGetAPIProfArgs(lpArgumentString,
+ hCurrentProcess,
+ lpExtensionApis,
+ iThkTblMax,
+ ppaThkTbls,
+ szTab,
+ &bTblAll,
+ szFun,
+ &iFunInd) ) {
+ Print("\n\n%s\n", szAPIUSAGE);
+ return;
+ }
+
+ bFound = FALSE;
+
+
+#if 0
+ for(iTab = 0; iTab < iThkTblMax; iTab++) {
+
+ READWOW(awThkTbl, &ppaThkTbls[iTab]);
+ READWOW(szTable, awThkTbl.lpszW32);
+
+
+ /* if dump all tables || dump this specific table */
+
+ if( bTblAll || !strcmp(szTab, szTable) ) {
+
+ pawAPIEntryTbl = awThkTbl.lpfnA32;
+#endif
+ for (i = 0; i < nModNames; i++) {
+
+ READWOW(awThkTbl, &ppaThkTbls[0]);
+ strcpy(szTable, apszModNames[i]);
+
+ /* if dump all tables || dump this specific table */
+
+ if (bTblAll || !_stricmp(szTab, apszModNames[i])) {
+
+ INT nFirst, nLast;
+
+ nFirst = TableOffsetFromName(apszModNames[i]);
+ if (i < nModNames - 1)
+ nLast = TableOffsetFromName(apszModNames[i+1]) - 1;
+ else
+ nLast = cAPIThunks - 1;
+
+ pawAPIEntryTbl = awThkTbl.lpfnA32;
+
+ /* if dump a specific API number */
+ if( iFunInd > 0 ) {
+ Print("\n>>>> %s\n", szTable);
+ Print("%s %s\n%s\n", szAPI, szTITLES, szDASHES);
+ //if( iFunInd >= *(awThkTbl.lpiFunMax) ) {
+ if( iFunInd > nLast - nFirst ) {
+ Print("Index #%d %s.\n", GetOrdinal(iFunInd), szTOOBIG);
+ }
+ else {
+ bFound = TRUE;
+ // READWOW(awAPIEntry, &pawAPIEntryTbl[iFunInd]);
+ READWOW(awAPIEntry, &pawAPIEntryTbl[nFirst + iFunInd]);
+ READWOW(szFunName, awAPIEntry.lpszW32);
+ if( szFunName[0] ) {
+ Print("%4d %30s ", GetOrdinal(iFunInd), szFunName);
+ }
+ else {
+ Print("%4d %30s ", GetOrdinal(iFunInd), szNOTUSED);
+ }
+ Print("%7ld %15ld ", awAPIEntry.cCalls, awAPIEntry.cTics);
+ if(awAPIEntry.cCalls) {
+ Print("%15ld\n", awAPIEntry.cTics/awAPIEntry.cCalls);
+ } else {
+ Print("%15ld\n", 0L);
+ }
+ }
+ }
+
+ /* else if dump an API by name */
+ else if ( iFunInd == -1 ) {
+ // READWOW(iEntries, awThkTbl.lpiFunMax);
+ // for(iFun = 0; iFun < iEntries; iFun++) {
+ for(iFun = nFirst; iFun <= nLast; iFun++) {
+ READWOW(awAPIEntry, &pawAPIEntryTbl[iFun]);
+ READWOW(szFunName, awAPIEntry.lpszW32);
+ if ( !_stricmp(szFun, szFunName) ) {
+ Print("\n>>>> %s\n", szTable);
+ Print("%s %s\n%s\n", szAPI, szTITLES, szDASHES);
+ Print("%4d %30s %7ld %15ld ",
+ GetOrdinal(iFun),
+ szFunName,
+ awAPIEntry.cCalls,
+ awAPIEntry.cTics);
+ if(awAPIEntry.cCalls) {
+ Print("%15ld\n", awAPIEntry.cTics/awAPIEntry.cCalls);
+ } else {
+ Print("%15ld\n", 0L);
+ }
+ return;
+ }
+ }
+ }
+
+ /* else dump all the API's in the table */
+ else {
+ Print("\n>>>> %s\n", szTable);
+ Print("%s %s\n%s\n", szAPI, szTITLES, szDASHES);
+ bFound = TRUE;
+ // READWOW(iEntries, awThkTbl.lpiFunMax);
+ // for(iFun = 0; iFun < iEntries; iFun++) {
+ for(iFun = nFirst; iFun <= nLast; iFun++) {
+ READWOW(awAPIEntry, &pawAPIEntryTbl[iFun]);
+ READWOW(szFunName, awAPIEntry.lpszW32);
+ if(awAPIEntry.cCalls) {
+ Print("%4d %30s %7ld %15ld %15ld\n",
+ GetOrdinal(iFun),
+ szFunName,
+ awAPIEntry.cCalls,
+ awAPIEntry.cTics,
+ awAPIEntry.cTics/awAPIEntry.cCalls);
+ }
+ }
+ if( !bTblAll ) {
+ return;
+ }
+ }
+ }
+ }
+ if( !bFound ) {
+ Print("\nCould not find ");
+ if( !bTblAll ) {
+ Print("%s ", szTab);
+ }
+ Print("API: %s\n", szFun);
+ Print("\n%s\n", szAPIUSAGE);
+ }
+
+ return;
+}
+
+
+
+/******* MSG profiler table functions ********/
+
+VOID msgprofclr( ARGLIST )
+{
+ int iMsg;
+ INT iMsgMax;
+ M32 awM32;
+ PM32 paw32Msg;
+
+ UNREFERENCED_PARAMETERS();
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ GETEXPRVALUE(iMsgMax, "wow32!iMsgMax", INT);
+ GETEXPRVALUE(paw32Msg, "wow32!paw32Msg", PM32);
+
+ Print("Clearing Message profile table");
+
+
+ for(iMsg = 0; iMsg < iMsgMax; iMsg++) {
+ READWOW(awM32, &paw32Msg[iMsg]);
+ awM32.cCalls = 0L;
+ awM32.cTics = 0L;
+ WRITEWOW(&paw32Msg[iMsg], awM32);
+ }
+
+ Print("\n");
+
+ return;
+}
+
+
+
+VOID msgprofdmp( ARGLIST )
+{
+ int iMsg, iMsgNum;
+ INT iMsgMax;
+ BOOL bFound;
+ M32 aw32Msg;
+ PM32 paw32Msg;
+ CHAR szMsg[40], *argv[2], szMsg32[40], szMsgName[40];
+
+ UNREFERENCED_PARAMETERS();
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ GETEXPRVALUE(iMsgMax, "wow32!iMsgMax", INT);
+ GETEXPRVALUE(paw32Msg, "wow32!paw32Msg", PM32);
+
+ if( WDGetMSGProfArgs(lpArgumentString, szMsg, &iMsgNum) ) {
+ Print("\n\n%s\n", szMSGUSAGE);
+ return;
+ }
+
+ Print("%35s %s\n%s\n", szMSG, szTITLES, szDASHES);
+
+ if( iMsgNum > iMsgMax ) {
+ Print("MSG #%4d %s.\n", iMsgNum, szTOOBIG);
+ return;
+ }
+
+ bFound = 0;
+ for(iMsg = 0; iMsg < iMsgMax; iMsg++) {
+
+ READWOW(aw32Msg, &paw32Msg[iMsg]);
+ READWOW(szMsgName, aw32Msg.lpszW32);
+
+ /* if specific msg name, parse name from "WM_MSGNAME 0x00XX" format */
+ if( iMsgNum == -2 ) {
+ strcpy(szMsg32, szMsgName);
+ WDParseArgStr(szMsg32, argv, 1);
+ }
+
+ /* if 'all' msgs || specific msg # || specific msg name */
+ if( (iMsgNum == -1) || (iMsg == iMsgNum) ||
+ ( (iMsgNum == -2) && (!strcmp(szMsg, argv[0])) ) ) {
+ bFound = 1;
+ if(aw32Msg.cCalls) {
+ Print("%35s %7ld %15ld %15ld\n", szMsgName,
+ aw32Msg.cCalls,
+ aw32Msg.cTics,
+ aw32Msg.cTics/aw32Msg.cCalls);
+ }
+ /* else if MSG wasn't sent & we're not dumping the whole table */
+ else if( iMsgNum != -1 ) {
+ Print("%35s %7ld %15ld %15ld\n", szMsgName, 0L, 0L, 0L);
+ }
+
+ /* if we're not dumping the whole table, we're done */
+ if( iMsgNum != -1 ) {
+ return;
+ }
+ }
+ }
+ if( !bFound ) {
+ Print("\nCould not find MSG: %s\n", szMsg);
+ Print("\n%s\n", szMSGUSAGE);
+ }
+
+ return;
+}
+
+
+
+void msgprofrt( ARGLIST )
+{
+ INT fWMsgProfRT;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ GETEXPRADDR(lpAddress, "wow32!fWMsgProfRT");
+
+ READWOW(fWMsgProfRT, lpAddress);
+ fWMsgProfRT = 1 - fWMsgProfRT;
+ WRITEWOW(lpAddress, fWMsgProfRT);
+
+ if( fWMsgProfRT ) {
+ Print("\n%s ENABLED.\n%s\n\n", szRNDTRIP, szCLEAR);
+ }
+ else {
+ Print("\n%s DISABLED.\n%s\n\n", szRNDTRIP, szCLEAR);
+ }
+
+ return;
+}
+
+
+PSTR aszWOWCLASS[] =
+{
+ "UNKNOWN",
+ "WIN16",
+ "BUTTON",
+ "COMBOBOX",
+ "EDIT",
+ "LISTBOX",
+ "MDICLIENT",
+ "SCROLLBAR",
+ "STATIC",
+ "DESKTOP",
+ "DIALOG",
+ "MENU",
+ "ACCEL",
+ "CURSOR",
+ "ICON",
+ "DC",
+ "FONT",
+ "METAFILE",
+ "RGN",
+ "BITMAP",
+ "BRUSH",
+ "PALETTE",
+ "PEN",
+ "OBJECT"
+};
+
+
+INT WDahtoi(LPSZ lpsz)
+{
+ char c;
+ int tot, pow, len, dig, i;
+
+
+ len = strlen(lpsz) - 1;
+ tot = 0;
+ pow = 1;
+
+ for(i = len; i >= 0; i--) {
+
+ c = toupper(lpsz[i]);
+
+ if(c == '0') dig = 0;
+ else if(c == '1') dig = 1;
+ else if(c == '2') dig = 2;
+ else if(c == '3') dig = 3;
+ else if(c == '4') dig = 4;
+ else if(c == '5') dig = 5;
+ else if(c == '6') dig = 6;
+ else if(c == '7') dig = 7;
+ else if(c == '8') dig = 8;
+ else if(c == '9') dig = 9;
+ else if(c == 'A') dig = 10;
+ else if(c == 'B') dig = 11;
+ else if(c == 'C') dig = 12;
+ else if(c == 'D') dig = 13;
+ else if(c == 'E') dig = 14;
+ else if(c == 'F') dig = 15;
+ else return(-1);
+
+ if(pow > 1) {
+ tot += pow * dig;
+ }
+ else {
+ tot = dig;
+ }
+ pow *= 16;
+ }
+ return(tot);
+}
+
+
+
+
+void at ( ARGLIST )
+{
+ UINT i;
+ ATOM atom;
+ CHAR pszGAtomName[128];
+ CHAR pszLAtomName[128];
+ CHAR pszCAtomName[128];
+ CHAR *argv[2], *psz;
+
+ UNREFERENCED_PARAMETERS();
+
+ // set up function pointer
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ if(WDParseArgStr(lpArgumentString, argv, 1) == 1) {
+
+ atom = (ATOM)LOWORD(WDahtoi(argv[0]));
+
+ pszGAtomName[0] = 'G'; // put a random value in 1st byte so we can
+ pszLAtomName[0] = 'L'; // tell if it got replaced with a '\0' for
+ pszCAtomName[0] = 'C'; // an "undetermined" type
+
+ psz = NULL;
+ Print("\n%s: ", argv[0]);
+ if(GlobalGetAtomName(atom, pszGAtomName, 128) > 0) {
+ Print("<Global atom> \"%s\" ", pszGAtomName);
+ psz = pszGAtomName;
+ }
+ else if(GetAtomName(atom, pszLAtomName, 128) > 0) {
+ Print("<Local atom> \"%s\" ", pszLAtomName);
+ psz = pszLAtomName;
+ }
+ else if(GetClipboardFormatName((UINT)atom, pszCAtomName, 128) > 0) {
+ Print("<Clipboard format> \"%s\" ", pszCAtomName);
+ psz = pszCAtomName;
+ }
+ if(psz) {
+ i = 0;
+ while(psz[i] && i < 128) {
+ Print(" %2X", psz[i++] & 0x000000FF);
+ }
+ }
+ else {
+ Print("<Undetermined type>\n");
+ Print(" GlobalGetAtomName string: \"%c\" ", pszGAtomName[0]);
+ for(i = 0; i < 8; i++) {
+ Print(" %2X", pszGAtomName[i] & 0x000000FF);
+ }
+ Print("\n GetAtomName string: \"%c\" ", pszLAtomName[0]);
+ for(i = 0; i < 8; i++) {
+ Print(" %2X", pszLAtomName[i] & 0x000000FF);
+ }
+ Print("\n GetClipboardFormatName string: \"%c\" ", pszCAtomName[0]);
+ for(i = 0; i < 8; i++) {
+ Print(" %2X", pszCAtomName[i] & 0x000000FF);
+ }
+ }
+ Print("\n\n");
+ }
+ else {
+ Print("Usage: at hex_atom_number\n");
+ }
+}
+
+
+
+
+void ww ( ARGLIST )
+{
+ PWW pww;
+ INT h16;
+ CHAR *argv[2];
+
+ UNREFERENCED_PARAMETERS();
+
+ // set up function pointer
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ if(WDParseArgStr(lpArgumentString, argv, 1)) {
+
+ if((h16 = WDahtoi(argv[0])) >= 0) {
+
+ try {
+
+ pww = (PWW)GetWindowLong((HWND)HWND32((HAND16)h16),GWL_WOWWORDS);
+
+ Print("16:16 WndProc : %08lX\n", pww->vpfnWndProc);
+ Print("16:16 DlgProc : %08lX\n", pww->vpfnDlgProc);
+ Print("iClass : %#lx (%s) \n", pww->iClass, aszWOWCLASS[pww->iClass]);
+ Print("dwStyle : %08lX\n", pww->dwStyle);
+ Print("hInstance : %08lX\n", pww->hInstance);
+ Print("16 bit handle : %#x\n", h16);
+
+ }
+ except (EXCEPTION_ACCESS_VIOLATION == GetExceptionCode()) {
+
+ Print("!wow32.ww: Invalid HWND16 %04x\n", h16);
+
+ }
+ }
+ else {
+ Print("Usage: ww hwnd16\n");
+ }
+ }
+ else {
+ Print("Usage: ww hwnd16\n");
+ }
+}
+
+
+
+void wc ( ARGLIST )
+{
+ PWC pwc;
+
+ INT h16;
+ CHAR *argv[2];
+
+ UNREFERENCED_PARAMETERS();
+
+ // set up function pointer
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ if(WDParseArgStr(lpArgumentString, argv, 1)) {
+
+ if((h16 = WDahtoi(argv[0])) >= 0){
+
+ try {
+
+ pwc = (PWC)GetClassLong((HWND)HWND32((HAND16)h16),GCL_WOWWORDS);
+
+ Print("16:16 WndProc : %08lX\n", pwc->vpfnWndProc);
+ Print("VPSZ : %08lX\n", pwc->vpszMenu);
+ Print("PWC : %08lX\n\n", pwc);
+
+ }
+ except (EXCEPTION_ACCESS_VIOLATION == GetExceptionCode()) {
+
+ Print("!wow32.wc: Invalid HWND16 %04x\n", h16);
+
+ }
+ }
+ else {
+ Print("Usage: wc hwnd16\n");
+ }
+ }
+ else {
+ Print("Usage: wc hwnd16\n");
+ }
+}
+
+
+
+
+
+/******* Misc filtering functions ********/
+//
+// Set Filter Filtering of Specific APIs ON
+//
+void filterspecific( ARGLIST )
+{
+ INT i;
+ INT fLogFilter;
+ WORD wfLogFunctionFilter;
+ LPVOID lpAddress;
+ PWORD pawfLogFunctionFilter;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRVALUE(pawfLogFunctionFilter, "wow32!pawfLogFunctionFilter", PWORD);
+
+ GetExpression = lpExtensionApis->lpGetExpressionRoutine;
+
+ for (i = 0; i < FILTER_FUNCTION_MAX ; i++) {
+
+ // Find Empty Position In Array
+ READWOW(wfLogFunctionFilter, &pawfLogFunctionFilter[i]);
+ if ((wfLogFunctionFilter == 0xffff) ||
+ (wfLogFunctionFilter == 0x0000)) {
+
+ // Add New Filter to Array
+ wfLogFunctionFilter = (WORD)GetExpression(lpArgumentString);
+ WRITEWOW(&pawfLogFunctionFilter[i], wfLogFunctionFilter);
+ break;
+ }
+ }
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ fLogFilter = 0xffffffff;
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+
+//
+// Clear Filter Specific Array
+//
+void clearfilterspecific( ARGLIST )
+{
+ INT i;
+ WORD NEG1 = (WORD) -1;
+ WORD ZERO = 0;
+ PWORD pawfLogFunctionFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRVALUE(pawfLogFunctionFilter, "wow32!pawfLogFunctionFilter", PWORD);
+
+ WRITEWOW(&pawfLogFunctionFilter[0], NEG1);
+ for (i=1; i < FILTER_FUNCTION_MAX ; i++) {
+ WRITEWOW(&pawfLogFunctionFilter[i], ZERO);
+ }
+
+ GETEXPRADDR(lpAddress, "wow32!iLogFuncFiltIndex");
+ WRITEWOW(lpAddress, ZERO);
+
+ return;
+}
+
+
+//
+// Dump Last Logged APIs
+//
+void lastlog( ARGLIST )
+{
+ INT iCircBuffer;
+ CHAR achTmp[TMP_LINE_LEN], *pachTmp;
+ INT i;
+
+ UNREFERENCED_PARAMETERS();
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ GETEXPRVALUE(iCircBuffer, "wow32!iCircBuffer", INT);
+ GETEXPRVALUE(pachTmp, "wow32!pachTmp", PCHAR);
+
+ for (i = iCircBuffer; i >= 0; i--) {
+ READWOW(achTmp, &pachTmp[i*TMP_LINE_LEN]);
+ Print("%s",achTmp);
+ }
+
+ for (i = CIRC_BUFFERS-1; i > iCircBuffer; i--) {
+ READWOW(achTmp, &pachTmp[i*TMP_LINE_LEN]);
+ Print("%s",achTmp);
+ }
+
+ return;
+}
+
+
+// creates/closes toggle for logfile for iloglevel logging in c:\ilog.log
+void logfile( ARGLIST )
+{
+ INT nArgs;
+ CHAR *argv[2], szLogFile[128];
+ DWORD fLog;
+ LPVOID lpfLog, lpszLogFile;
+
+ UNREFERENCED_PARAMETERS();
+
+
+ nArgs = WDParseArgStr(lpArgumentString, argv, 1);
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ GETEXPRADDR(lpfLog, "wow32!fLog");
+ READWOW(fLog, lpfLog);
+
+ if(nArgs) {
+ strcpy(szLogFile, argv[0]);
+ }
+ else {
+ strcpy(szLogFile, "c:\\ilog.log");
+ }
+
+ if(fLog == 0) {
+ fLog = 2;
+
+ Print("\nCreating ");
+ Print(szLogFile);
+ Print("\n\n");
+ }
+ else {
+ fLog = 3;
+ Print("\nClosing logfile\n\n");
+ }
+
+ WRITEWOW(lpfLog, fLog);
+
+ GETEXPRADDR(lpszLogFile, "wow32!szLogFile");
+ WRITENWOW(lpszLogFile, szLogFile, strlen(szLogFile)+1);
+
+ return;
+}
+
+
+//
+// Set TaskID Filtering
+//
+void filtertask( ARGLIST )
+{
+ INT fLogTaskFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogTaskFilter");
+ GetExpression = lpExtensionApis->lpGetExpressionRoutine;
+ fLogTaskFilter = (INT)GetExpression(lpArgumentString);
+ WRITEWOW(lpAddress, fLogTaskFilter);
+
+ return;
+}
+
+
+
+//
+// Turn All filtering ON
+//
+void resetfilter( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ fLogFilter = 0xffffffff;
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+
+//
+// Turn All filtering OFF
+//
+void clearfilter( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ fLogFilter = 0x00000000;
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+
+
+//
+// Set iLogLevel from Debugger Extension
+//
+void setloglevel( ARGLIST )
+{
+ INT iLogLevel;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!iLogLevel");
+ GetExpression = lpExtensionApis->lpGetExpressionRoutine;
+ iLogLevel = (INT)GetExpression(lpArgumentString);
+ WRITEWOW(lpAddress, iLogLevel);
+
+ return;
+}
+
+
+//
+// Toggle Single Step Trace Mode
+//
+void steptrace( ARGLIST )
+{
+ INT localfDebugWait;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fDebugWait");
+ READWOW(localfDebugWait, lpAddress);
+ localfDebugWait = ~localfDebugWait;
+ WRITEWOW(lpAddress, localfDebugWait);
+
+ return;
+}
+
+
+//
+// Toggle Verbose API Tracing
+//
+void filterverbose( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ READWOW(fLogFilter, lpAddress);
+ if ((fLogFilter & FILTER_VERBOSE) == 0) {
+ fLogFilter |= FILTER_VERBOSE;
+ } else {
+ fLogFilter &= ~FILTER_VERBOSE;
+ }
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+
+//
+// Toggle Kernel API Tracing
+//
+void filterkernel16( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ READWOW(fLogFilter, lpAddress);
+ if ((fLogFilter & FILTER_KERNEL16) == 0) {
+ fLogFilter |= FILTER_KERNEL16;
+ } else {
+ fLogFilter &= ~FILTER_KERNEL16;
+ }
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+
+void filterkernel( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ READWOW(fLogFilter, lpAddress);
+ if ((fLogFilter & FILTER_KERNEL) == 0) {
+ fLogFilter |= FILTER_KERNEL;
+ } else {
+ fLogFilter &= ~FILTER_KERNEL;
+ }
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+
+void filteruser( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ READWOW(fLogFilter, lpAddress);
+ if ((fLogFilter & FILTER_USER) == 0) {
+ fLogFilter |= FILTER_USER;
+ } else {
+ fLogFilter &= ~FILTER_USER;
+ }
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+void filtergdi( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ READWOW(fLogFilter, lpAddress);
+ if ((fLogFilter & FILTER_GDI) == 0) {
+ fLogFilter |= FILTER_GDI;
+ } else {
+ fLogFilter &= ~FILTER_GDI;
+ }
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+void filterkeyboard( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ READWOW(fLogFilter, lpAddress);
+ if ((fLogFilter & FILTER_KEYBOARD) == 0) {
+ fLogFilter |= FILTER_KEYBOARD;
+ } else {
+ fLogFilter &= ~FILTER_KEYBOARD;
+ }
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+
+void filtermmedia( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ READWOW(fLogFilter, lpAddress);
+ if ((fLogFilter & FILTER_MMEDIA) == 0) {
+ fLogFilter |= FILTER_MMEDIA;
+ } else {
+ fLogFilter &= ~FILTER_MMEDIA;
+ }
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+void filterwinsock( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ READWOW(fLogFilter, lpAddress);
+ if ((fLogFilter & FILTER_WINSOCK) == 0) {
+ fLogFilter |= FILTER_WINSOCK;
+ } else {
+ fLogFilter &= ~FILTER_WINSOCK;
+ }
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+
+
+void filtersound( ARGLIST )
+{
+ INT fLogFilter;
+ LPVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ READWOW(fLogFilter, lpAddress);
+ if ((fLogFilter & FILTER_SOUND) == 0) {
+ fLogFilter |= FILTER_SOUND;
+ } else {
+ fLogFilter &= ~FILTER_SOUND;
+ }
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+void filtercommdlg( ARGLIST )
+{
+ INT fLogFilter;
+ PVOID lpAddress;
+
+ UNREFERENCED_PARAMETERS();
+
+ GETEXPRADDR(lpAddress, "wow32!fLogFilter");
+ READWOW(fLogFilter, lpAddress);
+ if ((fLogFilter & FILTER_COMMDLG) == 0) {
+ fLogFilter |= FILTER_COMMDLG;
+ } else {
+ fLogFilter &= ~FILTER_COMMDLG;
+ }
+ WRITEWOW(lpAddress, fLogFilter);
+
+ return;
+}
+
+void cia( ARGLIST )
+{
+ CURSORICONALIAS cia;
+ PVOID lpAddress;
+ INT maxdump = 500;
+
+ Print = lpExtensionApis->lpOutputRoutine;
+
+ GETEXPRADDR(lpAddress, "wow32!lpCIAlias");
+ READWOW(lpAddress, lpAddress);
+
+ if (!lpAddress) {
+
+ Print("Cursor/Icon alias list is empty.\n");
+
+ } else {
+
+ Print("Alias tp H16 H32 inst mod task res szname\n");
+
+ READWOW(cia, lpAddress);
+
+ while ((lpAddress != NULL) && --maxdump) {
+
+ if (cia.fInUse) {
+ Print("%08X", lpAddress);
+ Print(" %02X", cia.flType);
+ Print(" %04X", cia.h16);
+ Print(" %08X", cia.h32);
+ Print(" %04X", cia.hInst16);
+ Print(" %04X", cia.hMod16);
+ Print(" %04X", cia.hTask16);
+ Print(" %04X", cia.hRes16);
+ Print(" %08X\n", cia.lpszName);
+ }
+
+ lpAddress = cia.lpNext;
+ READWOW(cia, lpAddress);
+
+ }
+
+ if (!maxdump) {
+ Print("Dump ended prematurely - possible infinite loop \n");
+ }
+ }
+
+}
+#endif
diff --git a/private/mvdm/wow32/fastwow.h b/private/mvdm/wow32/fastwow.h
new file mode 100644
index 000000000..bbadc1293
--- /dev/null
+++ b/private/mvdm/wow32/fastwow.h
@@ -0,0 +1,81 @@
+/*++ BUILD Version: 0003
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, 1992, 1993 Microsoft Corporation
+ *
+ * FASTWOW.H
+ * WOW32 x86 fast callback/API support
+ *
+ * History:
+ * Created 4-Dec-1992 by barry bradie (barryb)
+--*/
+
+#if defined(i386) && !defined(DEBUG_OR_WOWPROFILE)
+
+#define FASTBOPPING 1
+
+#else
+
+#define FASTBOPPING 0
+
+#endif
+
+#if FASTBOPPING
+extern BYTE fKernelCSIPFixed;
+// Used by the monitor to dispatch interupts. Updated for callbacks and bops
+extern DECLSPEC_IMPORT PVOID CurrentMonitorTeb;
+#endif
+
+#if FASTBOPPING
+VOID WOWBopEntry(VOID);
+VPVOID FastBopVDMStack(void);
+VOID FastBopSetVDMStack(VPVOID vp);
+VOID FastWOWCallbackCall(VOID);
+VOID FastWOWCallbackRet(VOID);
+#define FASTVDMSTACK() FastBopVDMStack()
+#define SETFASTVDMSTACK(vp) FastBopSetVDMStack(vp)
+#endif
+
+//#if FASTBOPPING
+//
+// Used to put lock prefixes in appropriate places for MP machines
+//
+extern VOID FastWowFirstCode(VOID);
+extern VOID FixLocks(VOID);
+//#endif
+
+#if 0
+
+How to set a 16-bit register from the 32-bit side:
+
+WOW16Call is called by all API thunks. this routine sets up a stack
+frame (the VDMFRAME) before getting over to WOW32. the VDMFRAME is where
+all the registers are stored - whenever a task has crossed over to WOW32
+either via an API call or by returning from a callback, it saves
+its registers in the frame. immediately upon returning from WOW32
+it pops the stuff off the stack back into the registers. the way
+to get a value into a specific register when the task starts executing
+16-bit code again is to put it in the frame.
+
+ *** do not use the setAX(), setDX(), etc. functions for this purpose ***
+
+those routines update a context block. when the app re-enters 16-bit
+code the registers will have the requested values but will be
+immediately overwritten by the values on the stack.
+
+similarly, to retrieve a value that was in a register at the time
+of the API call you should fetch it out of the frame.
+note that this is only valid for a few registers, because the
+validation layer may modify the general-purpose registers.
+
+upon returning from a callback everything on the 16-bit stack
+should be valid. to get the value that was in a register
+after a callback, pull it out of the callback frame. note that
+there are general-purpose words in the callback frame for passing
+extra data from the 16-bit callback routine to WOW32.
+
+
+ *** do not use the getAX(), getDX(), etc. functions for this purpose ***
+
+#endif
diff --git a/private/mvdm/wow32/i386/callpr32.asm b/private/mvdm/wow32/i386/callpr32.asm
new file mode 100644
index 000000000..d6c7b8f92
--- /dev/null
+++ b/private/mvdm/wow32/i386/callpr32.asm
@@ -0,0 +1,124 @@
+ title "x86-only Helper routine for generic thunk interface CallProc32[Ex]W"
+;++
+;
+; Copyright (c) 1996 Microsoft Corporation
+;
+; Module Name:
+;
+; callpr32.asm
+;
+; Abstract:
+;
+; WK32ICallProc32MakeCall is a helper routine for wkgthunk.c's
+; WK32ICallProc32, the common thunk for CallProc32W and
+; CallProc32ExW, the two generic thunk routines which allow
+; 16-bit code to call any 32-bit function.
+;
+; Author:
+;
+; Dave Hart (davehart) 23-Jan-96
+;--
+.386p
+
+include callconv.inc
+;include wow.inc
+
+if DBG
+DEBUG equ 1
+endif
+
+ifdef DEBUG
+DEBUG_OR_WOWPROFILE equ 1
+endif
+ifdef WOWPROFILE
+DEBUG_OR_WOWPROFILE equ 1
+endif
+
+_TEXT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+
+; EXTRNP _DispatchInterrupts,0
+
+_TEXT ENDS
+
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+; extrn _aw32WOW:Dword
+
+_DATA ENDS
+
+
+
+
+_TEXT SEGMENT
+
+ page ,132
+ subttl "WK32ICallProc32MakeCall"
+;++
+;
+; Routine Description:
+;
+; WK32ICallProc32MakeCall is a helper routine for wkgthunk.c's
+; WK32ICallProc32, the common thunk for CallProc32W and
+; CallProc32ExW, the two generic thunk routines which allow
+; 16-bit code to call any 32-bit function.
+;
+; Like Win95's implementation, this code allows the called
+; routine to fail to restore esp (for example, if we are
+; told the routine is STDCALL but it's really CDECL).
+; A number of Works 95's Wizards don't work otherwise.
+;
+; Arguments:
+;
+; pfn procedure to call
+; cArgs count of DWORDs
+; pArgs Argument array
+; fDestCDECL 1 if 32-bit routine is CDECL
+;
+; Returns:
+;
+; return value of called routine.
+;
+
+ assume DS:_DATA,ES:Nothing,SS:_DATA
+ALIGN 16
+cPublicProc _WK32ICallProc32MakeCall,3
+
+ push edi
+ push esi
+
+pfn equ [esp+0Ch]
+cArgs equ [esp+10h]
+pArgs equ [esp+14h]
+
+ mov edx,pfn
+ mov ecx,cArgs
+ mov eax,esp ; Save ESP so routine can trash it
+ or ecx,ecx
+ mov ebx,ecx
+ jz DoneArgs
+ shl ebx,2 ; convert dwords to bytes
+
+ cld ; "push" the arguments
+ mov esi,pArgs
+ sub esp,ebx ; parm macros are invalid
+ mov edi,esp
+ rep movsd
+DoneArgs:
+
+ mov edi,eax ; Save ESP so routine can trash it
+ call edx
+ mov esp,edi
+
+ pop esi
+ pop edi
+ stdRET _WK32ICallProc32MakeCall
+
+stdENDP _WK32ICallProc32MakeCall
+
+
+_TEXT ends
+
+ end
+
diff --git a/private/mvdm/wow32/i386/fastwow.asm b/private/mvdm/wow32/i386/fastwow.asm
new file mode 100644
index 000000000..aa5f04506
--- /dev/null
+++ b/private/mvdm/wow32/i386/fastwow.asm
@@ -0,0 +1,891 @@
+ title "Fast Protected Mode services"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; fastwow.asm
+;
+; Abstract:
+;
+; This module implements a fast mechanism for WOW apps to go back
+; and forth from app code (protected mode, 16-bit segmented) to
+; WOW32.DLL (flat).
+;
+;
+; Author:
+;
+; Bob Day (bobday) 07-29-92
+; copied from FASTPM.ASM written by Dave Hastings (daveh) 26-Jul-91
+;
+; barryb 11-nov-92 added fast callback mechanism, pared
+; WOWBopEntry to the bare essentials (hopefully)
+;
+;
+; rules of thumb:
+; - monitor context gets saved on monitor stack on entry to
+; FastWOWCallbackCall and restored on the way out of FastWOWCallbackRet
+; - no need to save any VDM general registers - krnl286 uses the
+; WOW16Call stack frame for this
+; - you can't save anything on the 16-bit stack because the stack
+; gets tinkered with by DispatchInterrupts
+;
+; WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+; these routines are optimized for the straight-through case, no
+; interrupt being dispatched, so there's duplicate code in the
+; routines. if you add stuff, be sure to add it to both paths.
+; WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+;
+; sudeepb 09-Dec-1992
+; Changed all the refernces to virtual interrupt flag in the VDMTIB
+; to fixed DOS location.
+;--
+.386p
+
+include ks386.inc
+include bop.inc
+include wow.inc
+include callconv.inc
+include vint.inc
+include vdmtb.inc
+
+if DBG
+DEBUG equ 1
+endif
+
+ifdef DEBUG
+DEBUG_OR_WOWPROFILE equ 1
+endif
+ifdef WOWPROFILE
+DEBUG_OR_WOWPROFILE equ 1
+endif
+
+; If ON All APIs performand with Try Except (decreases performance)
+FASTCALL equ 1
+
+ EXTRN __imp__CurrentMonitorTeb:DWORD
+ EXTRN __imp__ExpVdmTib:DWORD
+ EXTRN __imp__FlatAddress:DWORD
+
+_TEXT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:NOTHING, ES:NOTHING, SS:FLAT, FS:NOTHING, GS:NOTHING
+
+ EXTRNP _DispatchInterrupts,0
+
+if NO_W32TRYCALL
+ if FASTCALL
+ EXTRNP @W32PatchCodeWithLpfnw32, 2
+ else
+ EXTRNP _W32PatchCodeWithLpfnw32, 2
+ endif
+else
+ ifdef FASTCALL
+ EXTRNP @W32TryCall, 2
+ else ; FASTCALL
+ EXTRNP _W32TryCall, 2
+ endif
+endif
+
+ifdef DEBUG
+ EXTRNP _logargs,2
+ EXTRNP _logreturn,3
+endif
+
+_TEXT ENDS
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+ extrn _aw32WOW:Dword
+
+ public _WowpLockPrefixTable
+_WowpLockPrefixTable label dword
+ dd offset FLAT:_wowlock1
+ dd offset FLAT:_wowlock2
+ dd offset FLAT:_wowlock3
+ dd offset FLAT:_wowlock4
+ dd offset FLAT:_wowlock5
+ dd offset FLAT:_wowlock6
+ dd 0
+_DATA ENDS
+
+_DATA SEGMENT
+
+Stack16 LABEL DWORD
+_savesp16 DW 0
+_savess16 DW 0
+
+_saveip16 DD 0
+_savecs16 DD 0
+
+_saveebp32 DD 0
+
+_saveeax DD 0
+_saveebx DD 0
+_saveecx DD 0
+_saveedx DD 0
+
+_fKernelCSIPFixed DB 0
+_DATA ENDS
+
+public _saveeax
+public _saveebx
+public _saveecx
+public _saveedx
+
+public _savesp16
+public _savess16
+public _savecs16
+public _saveip16
+public _saveebp32
+public _fKernelCSIPFixed
+public Stack16
+
+;
+; The variable fKernelCSIPFixed is used so the fastbop/callback mechanism
+; knows when it no longer needs to pop the 16-bit return address off the
+; 16-bit stack on entry to WOWBopEntry and FastWOWCallbackRet because kernel
+; has booted and the address won't be changing.
+;
+;
+; The assumption is that we're always coming from the same place in kernel.
+; It also saves a jmp when returning to kernel.
+;
+
+
+_TEXT SEGMENT
+
+ page ,132
+ subttl "WOWBopEntry"
+;++
+;
+; Routine Description:
+;
+; This routine switches from the VDM context to the monitor context.
+; Then executes the appropriate WOW api call.
+; Then returns back to the VDM context.
+;
+; Arguments:
+;
+; none
+;
+; Returns:
+;
+; puts result of WOW api call (EAX) into pFrame->wDX, pFrame->wAX
+;
+; [LATER] add a field to the frame and set it to !0 if a task switch
+; has occurred. kernel can read this off the stack instead
+; of having to load the kernelDS to look at wCurTDB
+;
+
+ assume DS:Nothing,ES:Nothing,SS:Nothing
+ALIGN 16
+cPublicProc _WOWBopEntry,0
+ mov bx,KGDT_R3_DATA OR RPL_MASK ; Move back to Flat DS
+ mov ds,bx ; so push and pop size same
+ assume ds:_DATA
+ mov _saveeax,eax ; Multi Media Apps call api's
+ mov _saveebx,ebx ; at interrupt time which trash
+ mov _saveecx,ecx ; the high parts of the 32 bit
+ mov _saveedx,edx ; registers. [LATER] this
+ ; should be moved to fame
+ pushfd ; Save them flags
+
+ ; we make here the assumption that the c compiler always keeps the
+ ; direction flag clear. We clear it here instead of restoring it
+ ; from the context for performance
+ cld
+
+ mov ebx, dword ptr [__imp__ExpVdmTib] ; get pointer to contexts
+
+ ;
+ ; start saving some of the 16-bit context
+ ;
+
+ ; Interrupts are always enabled in WOW, but if we are trying
+ ; to simulate the fact that they are disabled, we need to
+ ; turn them off in the structure.
+
+ pop eax
+ mov edx,dword ptr ds:FIXED_NTVDMSTATE_LINEAR ; Get simulated bits
+ or edx,NOT VDM_VIRTUAL_INTERRUPTS
+ and eax,edx ; Pass on interrupt bit if it was on
+ mov dword ptr [ebx].VtVdmContext.CsEFlags,eax
+
+ ; Save the calling address
+ ; this address remains constant once krnl286 has booted.
+ ; these three instructions are cheaper than saving it
+ ; [LATER] this can be reduced. how?
+
+ cmp _fKernelCSIPFixed, 0
+ je wbegetretaddress
+ add esp, 8 ; pop cs, ip
+
+wbe10:
+ ; Save the stack (pre-call)
+ mov _savess16,di ; 16-bit SS put in di by krnl286
+ mov _savesp16,sp
+
+ ; switch Stacks
+
+.errnz (CsEsp + 4 - CsSegSS)
+ lss esp, [ebx].VtMonitorContext.CsEsp
+
+ ; Now running on Monitor stack
+
+ ; save hiword of ESI, EDI
+ ; note that di has already been trashed
+ ;
+ ; [LATER] move this to the vdmframe, don't need to push it twice
+
+ push esi
+ push edi
+ push ebp
+
+
+ ; Set up flat segment registers
+
+ mov edx,KGDT_R3_DATA OR RPL_MASK
+ mov es,dx ; Make them all point to DS
+ mov gs,dx ; [LATER] do we really have to set up GS?
+
+ mov eax,KGDT_R3_TEB OR RPL_MASK ; restore flat FS
+ mov fs,ax
+
+ mov ebp, _saveebp32
+
+ ; Update the CURRENTPTD->vpStack
+ mov eax,fs:[PcTeb]
+ mov ecx,[eax+TbWOW32Reserved]
+ mov esi, [Stack16]
+ mov dword ptr [ecx],esi ; PTD->vpStack = vpCurrentStack
+
+ ; Convert the 16:16 SS:SP pointer into a 32-bit flat pointer
+ ; DI = 16-bit SS, put there by kernel
+
+ and esi, 0FFFFh ; esi = 16-bit sp
+ and edi, 0FFFFh ; remove junk from high word
+ shr edi, 3 ; remove ring and table bits
+
+ mov edx, dword ptr [__imp__FlatAddress]
+ add esi, dword ptr [edx+edi*4]
+
+ ; esi is now a flat pointer to the frame
+
+ifdef DEBUG
+ push ecx
+ stdCall _logargs,<3,esi>
+ pop ecx
+endif
+
+
+ ; Convert the wCallID into a Thunk routine address.
+
+ mov edx, dword ptr [esi].vf_wCallID
+
+ ; esi = pFrame
+if NO_W32TRYCALL
+ mov [ecx].WtdFastWowEsp, esp
+ test edx, 0ffff0000h
+ jnz short @f
+ ifdef FASTCALL
+ mov ecx, esi ; ecx = pFrame & edx = lpfnW32
+ call @W32PatchCodeWithLpfnw32@8
+ else
+ stdCall _W32PatchCodeWithLpfnw32, <esi, edx>
+ endif
+ mov edx, eax
+@@:
+ mov ecx, esi ; ecx = pFrame & edx = lpfnW32
+ call edx
+ApiReturnAddress:
+else
+ ifdef FASTCALL
+ mov ecx, esi ; ecx = pFrame & edx = lpfnW32
+ call @W32TryCall@8
+ else
+ stdCall _W32TryCall,<esi,edx>
+ endif
+endif
+
+;
+; IMPORTANT NOTE: Upon retruned from wow32 worker routine, the
+; non-volatile registers may be destroyed if it is returned via
+; try-except handler.
+;
+ mov ebx, dword ptr [__imp__CurrentMonitorTeb]
+ mov ecx,fs:[PcTeb]
+ mov [ebx], ecx ; Tell NTVDM which is the active thread
+ mov ecx,[ecx+TbWOW32Reserved]
+
+ifdef DEBUG
+ push ecx
+ push eax
+
+ movzx esi, word ptr [ecx] ; offset
+ movzx edi, word ptr [ecx+2] ; selector
+ shr edi, 3 ; remove ring and table bits
+ mov ebx, dword ptr [__imp__FlatAddress]
+ add esi, dword ptr [ebx+edi*4] ; esi = offset + base
+
+ stdCall _logreturn,<5, esi, eax>
+
+ pop eax
+ pop ecx
+endif
+ mov ebx, dword ptr [__imp__ExpVdmTib]
+
+ push dword ptr [ebx].VtVdmContext.CsEFlags ;get 16-bit flags
+ popfd ; in case the direction flag was set
+
+
+ test dword ptr ds:FIXED_NTVDMSTATE_LINEAR,dword ptr VDM_INTERRUPT_PENDING
+ jnz wl70
+
+wl40:
+ mov _saveebp32, ebp
+
+ pop ebp
+ pop edi
+ pop esi
+
+ mov [ebx].VtMonitorContext.CsEsp,esp
+ mov [ecx].WtdFastWowEsp,esp
+
+ ; return to vdm stack
+ push word ptr [ecx+2]
+ push word ptr 0
+ push word ptr [ecx]
+ lss esp,[esp]
+
+ ; stick the API return value in the stack for kernel to pop.
+ ; it's been in EAX since we called the thunk routine.
+
+ mov bx, sp ; for temporary addressing
+ mov dword ptr ss:[bx].vf_wAX, eax
+
+ ; return to VDM, fake a far jump
+ push _savecs16
+ push _saveip16
+
+ mov eax,_saveeax ; Retore High parts of regs
+ mov ebx,_saveebx
+ mov ecx,_saveecx
+ mov edx,_saveedx
+
+ retf
+
+ ;
+wl60: ; Interrupts are disabled, turn them off in the virtual flags
+ ;
+_wowlock1:
+ lock and dword ptr ds:FIXED_NTVDMSTATE_LINEAR,NOT VDM_VIRTUAL_INTERRUPTS
+ jmp wl40
+
+ ;
+wl70: ; Interrupt came in, dispatch it
+ ;
+
+ ; translate the interrupt flag to the virtual interrupt flag
+ ; if interrupts are disabled then blow it off
+
+ test [ebx].VtVdmContext.CsEFlags,dword ptr EFLAGS_INTERRUPT_MASK
+ jz wl60
+_wowlock2:
+ lock or dword ptr ds:FIXED_NTVDMSTATE_LINEAR,dword ptr VDM_VIRTUAL_INTERRUPTS
+
+
+ push eax ; save API return value
+ push ebx
+ push ecx
+
+ ;
+ ; refresh VdmTib.VtVdmContext so DispatchInterrupts can party
+ ;
+
+ ; ecx points to CURRENTPTD->vpStack 16-bit ss:sp
+
+ mov si, [ecx + 2]
+ xor edi,edi
+ mov di, [ecx]
+
+ mov eax, _saveip16
+ mov dword ptr [ebx].VtVdmContext.CsEip, eax
+ mov eax, _savecs16
+ mov dword ptr [ebx].VtVdmContext.CsSegCs, eax
+
+ mov word ptr [ebx].VtVdmContext.CsSegSs, si
+ mov dword ptr [ebx].VtVdmContext.CsEsp, edi
+
+ stdCall _DispatchInterrupts
+ test dword ptr [ebx].VtVdmContext.CsEFlags,VDM_VIRTUAL_INTERRUPTS
+ jnz wl80
+_wowlock3:
+ lock and dword ptr ds:FIXED_NTVDMSTATE_LINEAR,NOT VDM_VIRTUAL_INTERRUPTS
+
+wl80: pop ecx ; points to ptd->vpStack
+ pop ebx
+ pop eax ; eax = API return value
+
+ mov _saveebp32, ebp
+
+ ; restore the hiwords of esi, edi
+ pop ebp
+ pop edi
+ pop esi
+
+ mov dword ptr [ebx].VtMonitorContext.CsEsp,esp
+ mov [ecx].WtdFastWowEsp,esp
+
+ ;
+ ; switch to 16-bit stack (probably an interrupt stack)
+ ;
+
+.errnz (CsEsp + 4 - CsSegSS)
+ lss esp, [ebx].VtVdmContext.CsEsp
+
+ ;
+ ; fake far jump to the 16-bit interrupt routine
+ ;
+
+ push dword ptr [ebx].VtVdmContext.CsEflags
+ push dword ptr [ebx].VtVdmContext.CsSegCs
+ push dword ptr [ebx].VtVdmContext.CsEip
+
+ ; stick the API return value in the stack for kernel to pop.
+ ; it's been in EAX since we called the thunk routine.
+
+ ; les bx, Stack16
+ les bx, [ecx]
+ mov dword ptr es:[bx].vf_wAX, eax
+
+ mov eax,_saveeax ; Retore High parts of regs
+ mov ebx,_saveebx
+ mov ecx,_saveecx
+ mov edx,_saveedx
+
+ iretd
+
+wbegetretaddress:
+
+ pop eax
+ mov _saveip16, eax
+ pop edx
+ mov _savecs16, edx
+
+ jmp wbe10
+
+
+stdENDP _WOWBopEntry
+
+if NO_W32TRYCALL
+cPublicProc _PostExceptionHandler,0
+ assume ds:_DATA
+
+;
+; Fixed up Exception registration pointer (just in case)
+;
+
+ mov eax, fs:[PcExceptionList]
+peh00:
+ cmp eax, esp
+ jb short @f
+
+ mov fs:[PcExceptionList], eax
+ xor eax, eax
+ jmp ApiReturnAddress
+
+@@:
+ mov eax, [eax] ; move to next reg record
+ jmp short peh00
+
+stdENDP _PostExceptionHandler
+
+;++
+;
+; VOID
+; W32SetExceptionContext (
+; PCONTEXT ContextRecord
+; );
+;
+; Routine Description:
+;
+; This functions updates exception context to our predefined
+; post-exception handler such that if we continue exception
+; execution the control will continue on our post-exception
+; handling code.
+;
+; Arguments:
+;
+; ContextRecord - supplies a pointer to the exception context.
+;
+; Returns:
+;
+; Exception context updated.
+;--
+
+cPublicProc _W32SetExceptionContext,1
+ assume ds:_DATA
+
+ mov ecx, dword ptr [__imp__ExpVdmTib]
+ mov edx, [esp+4] ; (edx) = Context Record
+ mov ecx, dword ptr [ecx].VtMonitorContext.CsEsp
+ mov [edx].CsEsp, ecx
+ mov [edx].CsEip, offset FLAT:_PostExceptionHandler
+ stdRET _W32SetExceptionContext
+
+stdENDP _W32SetExceptionContext
+
+
+;++
+;
+; BOOLEAN
+; IsW32WorkerException (
+; VOID
+; );
+;
+; Routine Description:
+;
+; This function checks if the exception occurred in WOW32 API.
+;
+; Arguments:
+;
+; None
+;
+; Returns:
+;
+; returns a BOOLEAN value to indicate if this is WOW32 API exception.
+;
+;--
+
+cPublicProc _IsW32WorkerException, 0
+ assume ds:_DATA
+
+ mov ecx, fs:[PcTeb]
+ mov ecx, [ecx].TbWOW32Reserved
+ mov eax, dword ptr [ecx].WtdFastWowEsp
+ or eax, eax
+ jz @f ; FastWowEsp is zero, not worker exception
+ mov edx, [eax-4]
+ cmp edx, offset FLAT:ApiReturnAddress
+ ; eax is still monitor esp, so it's nonzero
+ je short @f
+ xor eax, eax
+@@: stdRET _IsW32WorkerException
+
+stdENDP _IsW32WorkerException
+
+endif ; NO_W32TRYCALL
+
+_TEXT ends
+
+ page ,132
+ subttl "FastWOWCallbackCall"
+;++
+;
+; Routine Description:
+;
+; This routine is a fast callback from WOW32 to 16-bit code.
+; It assumes that the 16-bit stack pointer is already in Stack16.
+; The caller must set this up with FastBopSetVDMStack() before
+; calling this routine.
+;
+; WARNING: only the minimal set of registers are saved/restored
+; as a speed optimization.
+;
+; Arguments:
+;
+; none
+;
+; Returns:
+;
+; nothing.
+;
+
+
+_TEXT SEGMENT
+
+ assume DS:FLAT
+cPublicProc _FastWOWCallbackCall,0
+
+ ; Save monitor general registers on monitor stack
+ ; we'll pick em back up on the way out of FastWOWCallbackRet
+
+ push esi
+ push edi
+ push ebx
+
+ mov ebx, dword ptr [__imp__ExpVdmTib]
+
+ ; translate the interrupt flag to the virtual interrupt flag
+
+ test [ebx].VtVdmContext.CsEFlags,dword ptr EFLAGS_INTERRUPT_MASK
+ jz fe10
+_wowlock4:
+ lock or dword ptr ds:FIXED_NTVDMSTATE_LINEAR,dword ptr VDM_VIRTUAL_INTERRUPTS
+
+ test dword ptr ds:FIXED_NTVDMSTATE_LINEAR,dword ptr VDM_INTERRUPT_PENDING
+ jnz fe70
+
+ jmp fe20
+
+fe10:
+_wowlock5:
+ lock and dword ptr ds:FIXED_NTVDMSTATE_LINEAR, NOT VDM_VIRTUAL_INTERRUPTS
+fe20:
+
+ mov _saveebp32, ebp
+
+ mov ecx, fs:[PcTeb]
+ mov ecx, [ecx].TbWOW32Reserved
+ mov [ebx].VtMonitorContext.CsEsp,esp
+ mov [ecx].WtdFastWowEsp,esp
+
+ pushfd
+ pop ecx
+ mov [ebx].VtMonitorContext.CsEflags,ecx
+
+ ; switch to vdm stack
+ push _savess16
+ push word ptr 0
+ push _savesp16
+ lss esp, [esp]
+
+ ; before going to 16 bit, patch ebp to zero the high bits
+ ; hijaak pro app is relying upon hiword of ebp being 0
+ and ebp, 0ffffh
+
+ ; put flags, cs, and ip onto the 16-bit stack so we can iret to krnl286
+
+ push dword ptr [ebx].VtVdmContext.CsEflags
+ push _savecs16
+ push _saveip16
+
+ ; return to krnl286
+ iretd
+
+
+fe70: ; Interrupt pending, dispatch it
+ ;
+
+ push ebx
+ push eax
+
+ ;
+ ; refresh VdmTib.VtVdmContext so DispatchInterrupts can party
+ ;
+
+ mov eax, _saveip16
+ mov edx, _savecs16
+ mov dword ptr [ebx].VtVdmContext.CsEip, eax
+ mov dword ptr [ebx].VtVdmContext.CsSegCs, edx
+
+ mov ax, _savess16
+ xor edx,edx
+ mov dx, _savesp16
+ mov word ptr [ebx].VtVdmContext.CsSegSs, ax
+ mov dword ptr [ebx].VtVdmContext.CsEsp, edx
+
+ stdCall _DispatchInterrupts
+
+ test dword ptr [ebx].VtVdmContext.CsEFlags,VDM_VIRTUAL_INTERRUPTS
+ jnz fe80
+
+_wowlock6:
+ lock and dword ptr ds:FIXED_NTVDMSTATE_LINEAR,NOT VDM_VIRTUAL_INTERRUPTS
+
+fe80: pop eax
+ pop ebx
+
+ mov _saveebp32, ebp
+
+ mov ecx, fs:[PcTeb]
+ mov ecx, [ecx].TbWOW32Reserved
+ mov [ebx].VtMonitorContext.CsEsp,esp
+ mov [ecx].WtdFastWowEsp,esp
+
+ pushfd
+ pop ecx
+ mov [ebx].VtMonitorContext.CsEflags,ecx
+
+
+ ; switch to vdm stack
+ push word ptr [ebx].VtVdmContext.CsSegSs
+ push dword ptr [ebx].VtVdmContext.CsEsp
+ lss esp, [esp]
+
+ ; put flags, cs, and ip onto the 16-bit stack so we can iret to krnl286
+
+ ; before interrupts are dispatched, patch ebp to zero the high bits
+ ; hijaak pro app is relying upon hiword of ebp being 0
+ and ebp, 0ffffh
+
+ push dword ptr [ebx].VtVdmContext.CsEflags
+ push dword ptr [ebx].VtVdmContext.CsSegCs
+ push dword ptr [ebx].VtVdmContext.CsEip
+
+ ; return to krnl or interrupt routine
+ iretd
+
+
+stdENDP _FastWOWCallbackCall
+
+
+;++
+;
+; Routine Description:
+;
+; This routine is called by krnl286 upon returning from a
+; callback.
+;
+; Arguments:
+;
+; none
+;
+; Returns:
+;
+; nothing
+;
+; WARNING: only the minimal set of registers are saved/restored
+; as a speed optimization.
+;
+;
+ assume DS:Nothing,ES:Nothing,SS:Nothing
+ALIGN 16
+cPublicProc _FastWOWCallbackRet,0
+
+ mov ebx,KGDT_R3_DATA OR RPL_MASK
+ mov ds,bx
+ assume ds:_DATA
+ mov ebx, dword ptr [__imp__ExpVdmTib]
+ pushfd
+ pop eax
+ mov dword ptr [ebx].VtVdmContext.CsEFlags,eax
+
+
+ ; the words at top of stack are the return address of our
+ ; caller (krnl286).
+ ; this address remains constant once krnl286 has booted.
+ ; these three instructions are cheaper than saving it
+
+ cmp _fKernelCSIPFixed, 0
+ je fwcbrgetretaddress
+
+ add esp, 8 ; pop cs, ip
+
+fwcbr10:
+
+ ; refresh CURRENTPTD->vpStack with the current stack
+
+ mov ecx, KGDT_R3_TEB OR RPL_MASK
+ mov fs, cx
+ mov eax, fs:[PcTeb]
+ mov ecx, [eax+TbWOW32Reserved]
+
+ mov _savess16,ss
+ mov _savesp16,sp
+
+ mov esi, [Stack16]
+ mov [ecx], esi
+
+ movzx esi,si
+
+ mov dword ptr [ebx].VtVdmContext.CsEsp, esi
+ mov word ptr [ebx].VtVdmContext.CsSegSs, ss
+
+ ; switch Stacks
+.errnz (CsEsp + 4 - CsSegSS)
+ lss esp, [ebx].VtMonitorContext.CsEsp
+
+ ; Now running on Monitor stack
+
+ test dword ptr ds:FIXED_NTVDMSTATE_LINEAR,dword ptr VDM_VIRTUAL_INTERRUPTS
+ jz fl10
+
+ or [ebx].VtVdmContext.CsEFlags,dword ptr EFLAGS_INTERRUPT_MASK
+ jmp fl20
+
+fl10: and dword ptr [ebx].VtVdmContext.CsEFlags, NOT EFLAGS_INTERRUPT_MASK
+fl20:
+
+ ; set up Monitor regs
+
+ mov esi, KGDT_R3_DATA OR RPL_MASK
+ mov es, si
+ ; [LATER] do we really have to set up the GS?
+ mov gs, si
+
+ ; set up Monitor general regs
+
+ mov ebp, _saveebp32
+
+ ; return
+
+ pop ebx
+ pop edi
+ pop esi
+ ret
+
+fwcbrgetretaddress:
+
+ pop eax
+ pop edx
+
+ mov _saveip16, eax
+ mov _savecs16, edx
+
+ jmp fwcbr10
+
+stdENDP _FastWOWCallbackRet
+
+
+;++
+;
+; Routine Description:
+;
+; This returns the current task's 16-bit ss:sp (vpStack)
+;
+; Arguments:
+;
+; none
+;
+; Returns:
+;
+; returns a 32-bit value that can be passed to GetVDMPointer
+;
+
+ assume DS:_DATA,SS:Nothing
+cPublicProc _FastBopVDMStack,0
+ mov eax, [Stack16]
+ stdRET _FastBopVDMStack
+
+stdENDP _FastBopVDMStack
+
+
+;++
+;
+; Routine Description:
+;
+; This sets the current task's 16-bit ss:sp (vpStack),
+; used only when FASTSTACK is enabled.
+;
+; Arguments:
+;
+; vpStack (32-bit ss:sp, not a flat pointer)
+;
+; Returns:
+;
+; none
+;
+
+cPublicProc _FastBopSetVDMStack,1
+
+ mov eax, [esp+4]
+ mov [Stack16], eax
+ stdRET _FastBopSetVDMStack
+
+stdENDP _FastBopSetVDMStack
+
+_TEXT ends
+
+ end
+
diff --git a/private/mvdm/wow32/i386/sources b/private/mvdm/wow32/i386/sources
new file mode 100644
index 000000000..c783d0019
--- /dev/null
+++ b/private/mvdm/wow32/i386/sources
@@ -0,0 +1,3 @@
+I386_SOURCES= \
+ i386\fastwow.asm \
+ i386\callpr32.asm
diff --git a/private/mvdm/wow32/isvwow.h b/private/mvdm/wow32/isvwow.h
new file mode 100644
index 000000000..68b8072b8
--- /dev/null
+++ b/private/mvdm/wow32/isvwow.h
@@ -0,0 +1,85 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * ISVWOW.H
+ * WOW32 ISV Support. Public Functions and Macros for Multi-Media extensions
+ * to the WOW thunking mechanism.
+ *
+ * History:
+ * Created 18-Feb-1992 by Stephen Estrop (StephenE)
+--*/
+
+
+/*
+** Public functions that allow for extensions to the WOW thunking
+** system. These two functions enable extension thunk dlls such as
+** Multi-Media video recording to callback into 16 bit code to simulate
+** a hardware interrupt callback and to use the same handle mapping that
+** WOW uses.
+*/
+LPVOID
+WOW32ResolveMemory(
+ VPVOID vp
+ );
+
+BOOL APIENTRY
+WOW32DriverCallback(
+ DWORD dwCallback,
+ DWORD dwFlags,
+ WORD wID,
+ WORD wMsg,
+ DWORD dwUser,
+ DWORD dw1,
+ DWORD dw2
+ );
+
+BOOL APIENTRY
+WOW32ResolveHandle(
+ UINT uHandleType,
+ UINT uMappingDirection,
+ WORD wHandle16_In,
+ LPWORD lpwHandle16_Out,
+ DWORD dwHandle32_In,
+ LPDWORD lpdwHandle32_Out
+ );
+
+
+/*
+** Constants for use with WOW32ResolveHandle
+*/
+
+#define WOW32_DIR_16IN_32OUT 0x0001
+#define WOW32_DIR_32IN_16OUT 0x0002
+
+#define WOW32_USER_HANDLE 0x0001 // Generic user handle
+#define WOW32_GDI_HANDLE 0x0002 // Generic gdi handle
+ // Kernel handles are not mapped
+
+#define WOW32_WAVEIN_HANDLE 0x0003
+#define WOW32_WAVEOUT_HANDLE 0x0004
+#define WOW32_MIDIOUT_HANDLE 0x0005
+#define WOW32_MIDIIN_HANDLE 0x0006
+
+
+
+/*
+** These MultiMedia messages expect dwParam1 to be a generic pointer and
+** dwParam2 to be a generic DWORD. auxOutMessage, waveInMessage,
+** waveOutMessage, midiInMessage and midiOutMessage all respect this
+** convention and are thunked accordingly on WOW.
+*/
+#define DRV_BUFFER_LOW (DRV_USER - 0x1000) // 0x3000
+#define DRV_BUFFER_USER (DRV_USER - 0x0800) // 0x3800
+#define DRV_BUFFER_HIGH (DRV_USER - 0x0001) // 0x3FFF
+
+
+/*
+** The flags are extensions to those normally used with GetWindowFlags,
+** they allow 16 bit applications to detect if they are running on NT
+** and if the Intel cpu is being emulated.
+*/
+#define WF1_WINNT 0x40 // You are running on NT WOW
+#define WF1_CPUEM 0x01 // NT WOW on MIPS or Alpha
diff --git a/private/mvdm/wow32/isz.h b/private/mvdm/wow32/isz.h
new file mode 100644
index 000000000..0e2b0818b
--- /dev/null
+++ b/private/mvdm/wow32/isz.h
@@ -0,0 +1,53 @@
+//---------------------------------------------------------------------------
+// Isz.h : String resource IDs for WOW32
+//
+// Copyright (c) Microsoft Corporation, 1990-1995
+//---------------------------------------------------------------------------
+
+#define CCH_MAX_STRING_RESOURCE 512
+
+//
+// String resource IDs must start at 0 and continue consecutively until
+// the the last critical string, so that they can be used to index
+// aszCriticalStrings in the most straightforward fashion.
+//
+
+#define iszApplicationError 0x0
+#define iszTheWin16Subsystem 0x1
+#define iszChooseClose 0x2
+#define iszChooseCancel 0x3
+#define iszChooseIgnore 0x4
+#define iszCausedException 0x5
+#define iszCausedAV 0x6
+#define iszCausedStackOverflow 0x7
+#define iszCausedAlignmentFault 0x8
+#define iszCausedIllegalInstr 0x9
+#define iszCausedInPageError 0xa
+#define iszCausedIntDivideZero 0xb
+#define iszCausedFloatException 0xc
+#define iszChooseIgnoreAlignment 0xd
+
+#define CRITICAL_STRING_COUNT 0xe
+
+#define iszWIN16InternalError 0x100
+#define iszSystemError 0x101
+#define iszCantEndTask 0x102
+#define iszUnableToEndSelTask 0x103
+#define iszNotResponding 0x104
+#define iszEventHook 0x105
+#define iszApplication 0x106
+#define iszStartupFailed 0x107
+#define iszOLEMemAllocFailedFatal 0x108
+#define iszOLEMemAllocFailed 0x109
+
+#define iszWowFaxLocalPort 0x10a
+
+//
+// Macro to fetch critical string pointer based on name without preceeding isz
+//
+
+#define CRITSTR(name) (aszCriticalStrings[isz##name])
+
+#ifndef WOW32_C
+extern LPSTR aszCriticalStrings[];
+#endif
diff --git a/private/mvdm/wow32/makefile b/private/mvdm/wow32/makefile
new file mode 100644
index 000000000..3d6593833
--- /dev/null
+++ b/private/mvdm/wow32/makefile
@@ -0,0 +1,13 @@
+# WOW32 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Jeff Parsons (jeffpar)
+# Created.
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/mvdm/wow32/makefile.inc b/private/mvdm/wow32/makefile.inc
new file mode 100644
index 000000000..d48e5b44c
--- /dev/null
+++ b/private/mvdm/wow32/makefile.inc
@@ -0,0 +1,10 @@
+obj\$(TARGET_DIRECTORY)\wowtbl.obj: wktbl2.h \
+ wutbl2.h \
+ wgtbl2.h \
+ wkbdtbl2.h \
+ wstbl2.h \
+ wshtbl2.h \
+ wwstbl2.h \
+ wthtbl2.h \
+ wmmtbl2.h \
+ wcmdgtbl.h
diff --git a/private/mvdm/wow32/mapembed.c b/private/mvdm/wow32/mapembed.c
new file mode 100644
index 000000000..0b38bf44a
--- /dev/null
+++ b/private/mvdm/wow32/mapembed.c
@@ -0,0 +1,503 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ mapembed.c
+
+Abstract:
+
+ This module contains the functions that perform the mapping
+ between the "embedding" section of win.ini, and the subkeys
+ of HKEY_CLASSES_ROOT.
+
+ This mapping is a hack implemented on Win3.1, that must also
+ exist on NT.
+ It is implemnted in the WOW layer, since only some win16 apps
+ that read or write to the "embedding" section ( WinWord and
+ MsMail) depend on it.
+
+
+
+Author:
+
+
+ Jaime F. Sasson (jaimes) 25-Nov-1992
+
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(mapembed.c);
+
+
+#define WININITIMEOUT 2000
+#define BUFFER_SIZE 128
+
+#define EMPTY_STRING ""
+
+DWORD _LastTimeUpdated = 0;
+
+
+
+BOOL
+IsWinIniHelper(
+ IN LPSTR FileName
+ )
+
+
+/*++
+
+Routine Description:
+
+ Determine if the name passed as argument refers to the file win.ini.
+ Used by IS_WIN_INI macro, which assures the argument is non-null and
+ deals with exact match of "win.ini".
+
+Arguments:
+
+ FileName - File name to be examined.
+
+
+Return Value:
+
+ BOOL - Returns TRUE if 'Name' refers to win.ini.
+ Otherwise, returns FALSE.
+
+--*/
+
+{
+ CHAR BufferForFullPath[MAX_PATH];
+ PSTR PointerToName;
+ DWORD SizeOfFullPath;
+
+ BOOL Result;
+
+#ifdef DEBUG
+ //
+ // Filename argument must already be lowercase. Be sure.
+ //
+
+ {
+ char Lowercase[MAX_PATH];
+
+ WOW32ASSERT(strlen(FileName) < MAX_PATH-1);
+ strcpy(Lowercase, FileName);
+ _strlwr(Lowercase);
+ WOW32ASSERT(!strcmp(FileName, Lowercase));
+ }
+#endif
+
+ if (!strcmp(FileName, szWinDotIni)) {
+ Result = TRUE;
+ goto Done;
+ }
+
+ SizeOfFullPath = GetFullPathName( FileName,
+ sizeof BufferForFullPath,
+ BufferForFullPath,
+ &PointerToName );
+
+ if (SizeOfFullPath == 0) {
+ Result = FALSE;
+ goto Done;
+ }
+
+ WOW32ASSERT( (SizeOfFullPath + 1) <= sizeof BufferForFullPath );
+
+ WOW32ASSERTMSG(pszWinIniFullPath && pszWinIniFullPath[0],
+ "WOW32 ERROR pszWinIniFullPath not initialized.\n");
+
+ Result = !_stricmp( pszWinIniFullPath, BufferForFullPath );
+
+Done:
+ return Result;
+}
+
+
+
+VOID
+UpdateEmbeddingAllKeys(
+ )
+
+/*++
+
+Routine Description:
+
+ Update the "embedding" section of win.ini based on the information
+ stored on the subkeys of HKEY_CLASSES_ROOT.
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LONG iClass;
+ CHAR szClass[MAX_PATH + 1];
+ LONG Status;
+
+ for (iClass = 0;
+ (Status = RegEnumKey(HKEY_CLASSES_ROOT,iClass,szClass,sizeof( szClass ))) != ERROR_NO_MORE_ITEMS;
+ iClass++)
+ {
+ if( Status == ERROR_SUCCESS ) {
+ UpdateEmbeddingKey( szClass );
+ }
+ }
+}
+
+
+
+
+VOID
+UpdateEmbeddingKey(
+ IN LPSTR KeyName
+ )
+
+
+/*++
+
+Routine Description:
+
+ Update one key of the "embedding" section of win.ini based on the
+ information stored on the correspondent subkey of HKEY_CLASSES_ROOT.
+
+ The code below is an improved version of the function
+ "UpdateWinIni" extracted from Win 3.1 (shell\library\dbf.c).
+
+Arguments:
+
+ KeyName - Name of the key to be updated.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LONG Status;
+ HKEY Key;
+ PSTR szClass;
+
+ LPSTR szClassName;
+ CHAR BufferForClassName[BUFFER_SIZE];
+// char szClassName[60];
+
+ LPSTR szServer;
+ CHAR BufferForServer[BUFFER_SIZE];
+// char szServer[64];
+
+ LPSTR szLine;
+ CHAR BufferForLine[2*BUFFER_SIZE];
+// char szLine[128];
+
+ char szOldLine[2*BUFFER_SIZE];
+// char szOldLine[128];
+ LPSTR lpDesc, lpForms;
+ int nCommas;
+
+ LONG cchClassNameSize;
+ LONG cchServerSize;
+ LONG cchLineSize;
+
+
+ if( KeyName == NULL ) {
+ return;
+ }
+
+ szClass = KeyName;
+ Key = NULL;
+
+ szClassName = BufferForClassName;
+ cchClassNameSize = sizeof( BufferForClassName );
+
+ szServer = BufferForServer;
+ cchServerSize = sizeof( BufferForServer );
+
+ szLine = BufferForLine;
+
+
+ if( RegOpenKey( HKEY_CLASSES_ROOT, szClass, &Key ) != ERROR_SUCCESS )
+ goto NukeClass;
+
+ Status = RegQueryValue(Key,NULL,szClassName,&cchClassNameSize);
+ if( ( Status != ERROR_SUCCESS ) &&
+ ( Status != ERROR_MORE_DATA ) )
+ goto NukeClass;
+
+ if( Status == ERROR_MORE_DATA ) {
+ cchClassNameSize++;
+ szClassName = ( PSTR )malloc_w( cchClassNameSize );
+ if( szClassName == NULL )
+ goto NukeClass;
+
+ Status = RegQueryValue(Key,NULL,szClassName,&cchClassNameSize);
+ if( Status != ERROR_SUCCESS )
+ goto NukeClass;
+ }
+
+ if (!*szClassName)
+ goto NukeClass;
+
+
+ Status = RegQueryValue(Key,szServerKey,szServer,&cchServerSize);
+ if( ( Status != ERROR_SUCCESS ) &&
+ ( Status != ERROR_MORE_DATA ) )
+ goto NukeClass;
+
+ if( Status == ERROR_MORE_DATA ) {
+ cchServerSize++;
+ szServer = malloc_w( cchServerSize );
+ if( szServer == NULL )
+ goto NukeClass;
+
+ Status = RegQueryValue(Key,szServerKey,szServer,&cchServerSize);
+ if( Status != ERROR_SUCCESS )
+ goto NukeClass;
+ }
+
+ if (!*szServer)
+ goto NukeClass;
+
+
+ if (GetProfileString(szEmbedding, szClass, EMPTY_STRING,
+ szOldLine, sizeof(szOldLine)))
+ {
+ for (lpForms=szOldLine, nCommas=0; ; lpForms=AnsiNext(lpForms))
+ {
+ while (*lpForms == ',')
+ {
+ *lpForms++ = '\0';
+ if (++nCommas == 3)
+ goto FoundForms;
+ }
+ if (!*lpForms)
+ goto DoDefaults;
+ }
+FoundForms:
+ lpDesc = szOldLine;
+ }
+ else
+ {
+DoDefaults:
+ lpDesc = szClassName;
+ lpForms = szPicture;
+ }
+
+ // we have a class, a classname, and a server, so its an le class
+
+ cchLineSize = strlen( lpDesc ) +
+ strlen( szClassName ) +
+ strlen( szServer ) +
+ strlen( lpForms ) +
+ 3 +
+ 1;
+
+ if( cchLineSize > sizeof( BufferForLine ) ) {
+ szLine = malloc_w( cchLineSize );
+ if( szLine == NULL )
+ goto NukeClass;
+ }
+ wsprintf(szLine, "%s,%s,%s,%s",
+ lpDesc, (LPSTR)szClassName, (LPSTR)szServer, lpForms);
+
+ WriteProfileString(szEmbedding, szClass, szLine);
+ if( Key != NULL ) {
+ RegCloseKey( Key );
+ }
+ if( szClassName != BufferForClassName ) {
+ free_w( szClassName );
+ }
+ if( szServer != BufferForServer ) {
+ free_w( szServer );
+ }
+ if( szLine != BufferForLine ) {
+ free_w( szLine );
+ }
+ return;
+
+NukeClass:
+/*
+ Don't nuke the class because someone else may use it!
+
+*/
+ if( Key != NULL ) {
+ RegCloseKey( Key );
+ }
+ if( szClassName != BufferForClassName ) {
+ free_w( szClassName );
+ }
+ if( szServer != BufferForServer ) {
+ free_w( szServer );
+ }
+ if( szLine != BufferForLine ) {
+ free_w( szLine );
+ }
+ WriteProfileString(szEmbedding,szClass,NULL);
+}
+
+
+
+VOID
+UpdateClassesRootSubKey(
+ IN LPSTR KeyName,
+ IN LPSTR Value
+ )
+
+/*++
+
+Routine Description:
+
+ Update a subkeys of HKEY_CLASSES_ROOT, based on the corresponding
+ key in the "embedding" section of win.ini.
+
+ The code below is an improved version of the function
+ "UpdateFromWinIni" extracted from Win 3.1 (shell\library\dbf.c).
+
+Arguments:
+
+ KeyName - Name of the subkey to be updated
+
+ Value - The value associated to the key, that was already written
+ to the "embedding" section of win.ini.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPSTR szLine;
+ LPSTR lpClass,lpServer,lpClassName;
+ LPSTR lpT;
+ HKEY key = NULL;
+ HKEY key1 = NULL;
+
+ if( ( KeyName == NULL ) || ( Value == NULL ) ) {
+ return;
+ }
+
+ lpClass = KeyName;
+ szLine = Value;
+
+ if (!(lpClassName=strchr(szLine, ',')))
+ return;
+ // get the server name and null terminate the class name
+ if (!(lpServer=strchr(++lpClassName, ','))) {
+ return;
+ }
+ *lpServer++ = '\0';
+
+ // null terminate the server
+ if (!(lpT=strchr(lpServer, ','))) {
+ return;
+ }
+ *lpT++ = '\0';
+
+ // make sure the classname is nonblank
+ while (*lpClassName == ' ')
+ lpClassName++;
+ if (!*lpClassName)
+ return;
+
+ // make sure the server name is nonblank
+ while (*lpServer == ' ')
+ lpServer++;
+ if (!*lpServer)
+ return;
+
+ // we now have a valid entry
+ key = NULL;
+ if( ( RegCreateKey( HKEY_CLASSES_ROOT, lpClass, &key ) != ERROR_SUCCESS ) ||
+ ( RegSetValue( key, NULL, REG_SZ, lpClassName, strlen( lpClassName ) ) != ERROR_SUCCESS ) ) {
+ if( key != NULL ) {
+ RegCloseKey( key );
+ }
+ return;
+ }
+ if( ( RegCreateKey( key, szServerKey, &key1 ) != ERROR_SUCCESS ) ||
+ ( RegSetValue( key1, NULL, REG_SZ, lpServer, strlen( lpServer ) ) != ERROR_SUCCESS ) ) {
+ if( key != NULL ) {
+ RegCloseKey( key );
+ }
+ if( key1 != NULL ) {
+ RegCloseKey( key1 );
+ }
+ return;
+ }
+ RegCloseKey( key );
+ RegCloseKey( key1 );
+}
+
+
+
+VOID
+SetLastTimeUpdated(
+ )
+
+/*++
+
+Routine Description:
+
+ Set the variable that contains the information of when the "embedding"
+ section of win.ini was last updated.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _LastTimeUpdated = GetTickCount();
+}
+
+
+
+BOOL
+WasSectionRecentlyUpdated(
+ )
+
+/*++
+
+Routine Description:
+
+ Inform the caller whether the "embedding" section of win.ini
+ was recently updated ( less than 2 seconds ).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the "embedding" section was updated less than
+ 2 seconds ago.
+
+--*/
+
+{
+ DWORD Now;
+
+ Now = GetTickCount();
+ return( ( ( Now - _LastTimeUpdated ) < WININITIMEOUT ) ? TRUE : FALSE );
+}
diff --git a/private/mvdm/wow32/mapembed.h b/private/mvdm/wow32/mapembed.h
new file mode 100644
index 000000000..1d1d25607
--- /dev/null
+++ b/private/mvdm/wow32/mapembed.h
@@ -0,0 +1,75 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ mapembed.c
+
+Abstract:
+
+ This module contains the the prototypes of the functions that
+ perform the mapping between the "embedding" section of win.ini,
+ and the subkeys of HKEY_CLASSES_ROOT.
+
+ This mapping is a hack implemented on Win3.1, that must also
+ exist on NT.
+ It is implemnted in the WOW layer, since only some win16 apps
+ that read or write to the "embedding" section ( Excel and
+ MsMail) depend on it.
+
+
+
+Author:
+
+
+ Jaime F. Sasson (jaimes) 25-Nov-1992
+
+
+
+--*/
+
+#if !defined( _MAP_EMBEDDING_SECTION_ )
+
+#define _MAP_EMBEDDING_SECTION_
+
+#define IS_EMBEDDING_SECTION(pszSection) \
+ ( ! (pszSection == NULL || _stricmp( pszSection, szEmbedding )) )
+
+BOOL
+IsWinIniHelper(
+ IN LPSTR Filename
+ );
+
+//
+// WARNING Filename argument to IS_WIN_INI must already be lowercase.
+//
+
+#define IS_WIN_INI(Filename) ( \
+ (Filename) \
+ ? (strstr((Filename), szWinDotIni) \
+ ? IsWinIniHelper((Filename)) \
+ : FALSE) \
+ : FALSE)
+
+VOID
+UpdateEmbeddingAllKeys( VOID );
+
+VOID
+SetLastTimeUpdated( VOID );
+
+VOID
+UpdateEmbeddingKey(
+ IN LPSTR KeyName
+ );
+
+VOID
+UpdateClassesRootSubKey(
+ IN LPSTR KeyName,
+ IN LPSTR Value
+ );
+
+BOOL
+WasSectionRecentlyUpdated( VOID );
+
+#endif
diff --git a/private/mvdm/wow32/precomp.h b/private/mvdm/wow32/precomp.h
new file mode 100644
index 000000000..60286b82f
--- /dev/null
+++ b/private/mvdm/wow32/precomp.h
@@ -0,0 +1,116 @@
+/*++ BUILD Version: 0001
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * precomp.h
+ * Combined precompiled header source
+ *
+ * This file is a collection of all the common .h files used by the
+ * various source files in this directory. It is precompiled by the
+ * build process to speed up the overall build time.
+ *
+ * Put new .h files in here if it has to be seen by multiple source files.
+ * Keep in mind that the definitions in these .h files are potentially
+ * visible to all source files in this project.
+ *
+ * History:
+ * Created 19-Oct-1993 by Neil Sandlin (neilsa)
+--*/
+
+#include <stddef.h>
+#include <nt.h>
+#include "wow32.h"
+#include "wowtbl.h"
+#include "doswow.h"
+#include "wdos.h"
+#include "wmdisp32.h"
+#include "mapembed.h"
+#include "wowusr.h"
+#include "waccel.h"
+#include "wcall16.h"
+#include "wuclass.h"
+#include "wsubcls.h"
+#include <mmsystem.h>
+#include "wkman.h"
+#include "fastwow.h"
+#include "wcall32.h"
+#include "wudlg.h"
+#include "tdb16.h"
+#include "wcntl32.h"
+#include "wcuricon.h"
+#include "wmsg16.h"
+#include "wmsgbm.h"
+#include "wmtbl32.h"
+#include "wcommdlg.h"
+#include "wowcmdlg.h"
+#include <commdlg.h>
+#include "wres16.h"
+#include "wres32.h"
+#include "wowkrn.h"
+#include "wdde.h"
+#include <dde.h>
+#include "wuclip.h"
+#include "wgmeta.h"
+#include "wowgdi.h"
+#include "wgdi.h"
+#include "wgprnset.h"
+#include "wgfont.h"
+#include "wgdi31.h"
+#include "wgman.h"
+#include "wgpal.h"
+#include "wgtext.h"
+#include "wheap.h"
+#include "wowkbd.h"
+#include "wkbman.h"
+#include "wkernel.h"
+#include "wkfileio.h"
+#include <winbase.h>
+#include "oemuni.h"
+#include "vrnmpipe.h"
+#include "wkgthunk.h"
+#include "wklocal.h"
+#include "wowhooks.h"
+#include "wutmr.h"
+#include "wreldc.h"
+#include "vdmapi.h"
+#include "wowinfo.h"
+#include "dbgexp.h"
+#include "wucomm.h"
+#include "wowmmcb.h"
+#include "isz.h"
+#include "wkmem.h"
+#include <mmddk.h>
+#include "wowmmed.h"
+#include "wmmstruc.h"
+#include "wmmedia.h"
+#include "isvwow.h"
+#include <string.h>
+#include <digitalv.h>
+#include "wmsgcb.h"
+#include "wmsgem.h"
+#include "wmsglb.h"
+#include "wmsgsbm.h"
+#include "wumsg.h"
+#include "wuman.h"
+#include "..\..\inc\vdm.h"
+#include "wucaret.h"
+#include "wucursor.h"
+#include "wuhook.h"
+#include "wumenu.h"
+#include "wuser.h"
+#include "wutext.h"
+#include "wuwind.h"
+#include "wuser31.h"
+#include "wulang.h"
+#include "winsockp.h"
+#include "wowsnd.h"
+#include "wsman.h"
+#include "wowshell.h"
+#include "wshell.h"
+#include "wowth.h"
+#include "wthman.h"
+#include "wusercli.h"
+#include "wole2.h"
+#include "wparam.h"
+#include <limits.h>
+
diff --git a/private/mvdm/wow32/sources b/private/mvdm/wow32/sources
new file mode 100644
index 000000000..e07567288
--- /dev/null
+++ b/private/mvdm/wow32/sources
@@ -0,0 +1,153 @@
+INDENTED_DIRECTIVES=1
+
+DLLORDER=wow32.prf
+
+
+
+MAJORCOMP=mvdm
+MINORCOMP=wow32
+
+TARGETNAME=wow32
+TARGETTYPE=DYNLINK
+
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\gdi32p.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32p.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntvdm.lib \
+ $(BASEDIR)\public\sdk\lib\*\oemuni.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \
+ $(BASEDIR)\public\sdk\lib\*\version.lib
+
+DLLENTRY=W32DllInitialize
+DLLBASE=0x10000000
+DLLDEF=obj\*\wow32.def
+
+NTTARGETFILES=
+
+SYNCHRONIZE_DRAIN=1
+SYNCHRONIZE_BLOCK=1
+
+INCLUDES=..\inc;..\..\windows\inc;..\..\inc;..\vdd\h; \
+ $(BASEDIR)\private\ntos\w32\ntgdi\inc
+
+USE_LIBCNTPR = 1
+
+SOURCES= \
+ mapembed.c \
+ wow32.c \
+ wowtbl.c \
+ walias.c \
+ wstruc.c \
+ wcall16.c \
+ wcall32.c \
+ wcntl32.c \
+ wdde.c \
+ wres16.c \
+ wres32.c \
+ wmsg16.c \
+ wmdisp32.c \
+ wmsgbm.c \
+ wmsgcb.c \
+ wmsgem.c \
+ wmsglb.c \
+ wmsgsbm.c \
+ wmtbl32.c \
+ wgdi31.c \
+ wgman.c \
+ wgdi.c \
+ wgfont.c \
+ wgmeta.c \
+ wgpal.c \
+ wgprnset.c \
+ wgtext.c \
+ wkbman.c \
+ wkmem.c \
+ wkgthunk.c \
+ wkman.c \
+ wkfileio.c \
+ wkernel.c \
+ wow32fax.c \
+ wsman.c \
+ wshell.c \
+ wuser31.c \
+ wuman.c \
+ wucaret.c \
+ wuclass.c \
+ wuclip.c \
+ wucomm.c \
+ wucursor.c \
+ wudlg.c \
+ wuhook.c \
+ wulang.c \
+ wumenu.c \
+ wumsg.c \
+ wuser.c \
+ wutext.c \
+ wutmr.c \
+ wuwind.c \
+ wowhooks.c \
+ wdos.c \
+ wreldc.c \
+ wcuricon.c \
+ wsubcls.c \
+ wmmedia.c \
+ wmmedia1.c \
+ wmmedia2.c \
+ wmmstruc.c \
+ wmmstru1.c \
+ wmmstru2.c \
+ wmmalias.c \
+ walloc16.c \
+ waccel.c \
+ wsdata.c \
+ wsext.c \
+ wsraw.c \
+ wthman.c \
+ wcommdlg.c \
+ wheap.c \
+ wspool.c \
+ wusercli.c \
+ wdib.c \
+ wole2.c \
+ wparam.c \
+ wow32.rc
+
+
+!IF 0
+ wkbtbl.c \
+ wstbl.c \
+ wktbl.c \
+ wutbl.c \
+ wshltbl.c \
+ wsocktbl.c \
+ wthtbl.c \
+ wmmtbl.c \
+ wgtbl.c \
+!ENDIF
+
+!IFNDEF MSC_WARNING_LEVEL
+MSC_WARNING_LEVEL=/W3
+!ENDIF
+MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /WX
+
+!IF "$(WOWPROFILE)" == ""
+C_DEFINES=-DWIN_32
+ASM_DEFINES=-DWIN_32
+!ELSE
+C_DEFINES=-DWIN_32 -DWOWPROFILE
+ASM_DEFINES=-DWIN_32 -DWOWPROFILE
+!ENDIF
+
+
+UMTYPE=windows
+UMTEST=
+UMRES=obj\*\wow32.res
+UMLIBS=
+
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
diff --git a/private/mvdm/wow32/sz.src b/private/mvdm/wow32/sz.src
new file mode 100644
index 000000000..bc03ef4c4
--- /dev/null
+++ b/private/mvdm/wow32/sz.src
@@ -0,0 +1,45 @@
+//---------------------------------------------------------------------------
+// Sz.src : String table resources
+//
+// Copyright (c) Microsoft Corporation, 1990-1993
+//---------------------------------------------------------------------------
+
+iszNotResponding "The Win 16 Subsystem is not responding to your request to start an application. Choose RETRY to continue to wait or Cancel to Terminate the Win 16 Subsystem."
+iszApplicationError "Application Error"
+
+iszStartupFailed "The Win 16 Subsystem failed to start due to low memory. Close other applications or increase your pagefile and try again."
+
+iszWIN16InternalError "The Win 16 Subsystem had an internal error. Close all your Win 16 applications and save your data."
+iszSystemError "System Error"
+
+iszCantEndTask "The system cannot end the selected task because %s is not allowing it to run. Press OK to End Task %s or Cancel to leave it running."
+
+iszUnableToEndSelTask "The request to end the selected 16 bit task has timed out. The Win 16 Subsystem may be unstable. Press OK to terminate the Win 16 Subsystem or Cancel to leave it running."
+
+iszCausedException "%s caused an exception in %s at 0x%08x. The exception code was 0x%08x.\n"
+iszCausedAV "%s caused an access violation in %s at 0x%08x.\n"
+iszCausedStackOverflow "%s caused a stack overflow in %s at 0x%08x.\n"
+iszCausedAlignmentFault "%s caused a datatype misalignment fault in %s at 0x%08x.\nIf you choose Ignore, slower software emulation of misaligned accesses will be used.\n"
+iszCausedIllegalInstr "%s caused an illegal instruction fault in %s at 0x%08x.\n"
+iszCausedInPageError "%s caused an in-page error in %s at 0x%08x.\n"
+iszCausedIntDivideZero "%s caused an integer divide by zero in %s at 0x%08x.\n"
+iszCausedFloatException "%s caused a floating-point exception in %s at 0x%08x.\n"
+iszTheWin16Subsystem "the Win16 Subsystem"
+
+iszChooseClose "Click on CLOSE to terminate the application"
+iszChooseCancel "Click on CANCEL to debug the application"
+iszChooseIgnore "Click on IGNORE to continue, you should save your work in a new file."
+iszChooseIgnoreAlignment "Click on IGNORE to enable emulation of misaligned data access in software."
+
+iszEventHook "An application has attempted to access the keyboard or mouse hardware as a 16 bit Windows program, which cannot be supported. This may cause the application to function incorrectly."
+
+iszApplication "Application: "
+
+iszOLEMemAllocFailedFatal "The Win 16 Subsystem was unable to allocate memory for this DDE transaction, shutting down the conversation."
+iszOLEMemAllocFailed "The Win 16 Subsystem was unable to allocate memory for this DDE transaction."
+
+// Localizers, the following string must match IDS_LOCALMONITOR in
+// \nt\private\windows\spooler\monitors\local\localmon.rc
+
+iszWowFaxLocalPort "Local Port"
+
diff --git a/private/mvdm/wow32/thunkdll.txt b/private/mvdm/wow32/thunkdll.txt
new file mode 100644
index 000000000..18b6a2283
--- /dev/null
+++ b/private/mvdm/wow32/thunkdll.txt
@@ -0,0 +1,22 @@
+
+How to add a new thunk table for a new 16-bit thunk DLL:
+
+ - modify wow16\kernel31\kernel.def and add an export similar to __MOD_KERNEL
+ rebuild the 16-bit libraries (nmake in mvdm\wow16\lib)
+
+ - modify the Thunk macro in inc\wow.h and add another externA
+ update the MOD_ constants in wow.h, the profiling code still uses them.
+ regenerate wow.inc
+
+ - update kernel31\kdata.asm and add another MOD_ variable
+
+ - declare and make public a new __MOD_ value for exporting (ldboot.asm)
+
+ - create the table (.h file) for inclusion into wowtbl.c
+
+ - wowtbl.h - add a field to the tableoffsets structure
+
+ - wowtbl.c - #include the table into aw32WOW and update apszModNames,
+ InitThunkTableOffsets, ModFromCallID, and TableOffsetFromName
+
+ - update makefile.inc with the new dependency
diff --git a/private/mvdm/wow32/waccel.c b/private/mvdm/wow32/waccel.c
new file mode 100644
index 000000000..630a9b788
--- /dev/null
+++ b/private/mvdm/wow32/waccel.c
@@ -0,0 +1,412 @@
+//*****************************************************************************
+//
+// LoadAccelerator - compatibility support.
+// So much code for such a silly thing.
+//
+// 23-Jul-92 NanduriR Created.
+//*****************************************************************************
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(waccel.c);
+
+extern ULONG SetCursorIconFlag(HAND16 hAccel16, BOOL bFlag);
+
+LPACCELALIAS lpAccelAlias = NULL;
+
+
+//*****************************************************************************
+// WU32LoadAccelerators -
+// This gets called from WU32NotifyWow. I use the familiar name WU32...
+// because this gets called indirectly in response to LoadAccelerator
+//
+// returs TRUE for success.
+//*****************************************************************************
+
+
+ULONG FASTCALL WU32LoadAccelerators(VPVOID vpData)
+{
+ PLOADACCEL16 ploadaccel16;
+ HACCEL hAccel;
+ BOOL fReturn = (BOOL)FALSE;
+
+
+ GETVDMPTR(vpData, sizeof(LOADACCEL16), ploadaccel16);
+
+ if (FindAccelAlias((HANDLE)FETCHWORD(ploadaccel16->hAccel),
+ HANDLE_16BIT)) {
+ LOGDEBUG(0, ("AccelAlias already exists\n"));
+ return (ULONG)TRUE;
+ }
+
+ if (hAccel = CreateAccel32(ploadaccel16->pAccel, ploadaccel16->cbAccel)) {
+ fReturn = (BOOL)SetupAccelAlias(FETCHWORD(ploadaccel16->hInst),
+ FETCHWORD(ploadaccel16->hAccel),
+ hAccel, TRUE);
+ }
+
+
+ FREEVDMPTR(ploadaccel16);
+ return (ULONG)fReturn;
+}
+
+
+//*****************************************************************************
+// SetupAccelAlias -
+// sets up the alias. the alias list is doubly linked. nothing fancy.
+//
+// returns pointer to the alias.
+//*****************************************************************************
+
+LPACCELALIAS SetupAccelAlias(
+ HAND16 hInstance,
+ HAND16 hAccel16,
+ HAND32 hAccel32,
+ BOOL f16
+) {
+ LPACCELALIAS lpT;
+ WORD hTask16;
+
+ hTask16 = CURRENTPTD()->htask16;
+ lpT = FindAccelAlias((HANDLE)hAccel16, HANDLE_16BIT);
+ if (lpT == (LPACCELALIAS)NULL) {
+ lpT = malloc_w_small(sizeof(ACCELALIAS));
+ if (lpT) {
+ lpT->lpNext = lpAccelAlias;
+ lpT->lpPrev = (LPACCELALIAS)NULL;
+
+ if (lpAccelAlias)
+ lpAccelAlias->lpPrev = lpT;
+
+ lpAccelAlias = lpT;
+ }
+ }
+ else {
+ LOGDEBUG(0, ("SetupAccelAlias: Alias Already exists. how & why?\n"));
+ WOW32ASSERT(FALSE);
+ }
+
+ if (lpT) {
+ lpT->hInst = hInstance;
+ lpT->hTask16 = CURRENTPTD()->htask16;
+ lpT->h16 = hAccel16;
+ lpT->h32 = hAccel32;
+ lpT->f16 = f16;
+
+ // mark this so we can remove it from the alias list when
+ // FreeResource() (in user.exe) calls GlobalFree() (in krnl386)
+ SetCursorIconFlag(hAccel16, TRUE);
+ }
+ else {
+ WOW32ASSERT(FALSE);
+ }
+
+
+ return (LPACCELALIAS)lpT;
+}
+
+
+//*****************************************************************************
+// DestroyAccelAlias -
+// Deletes the 32bit table and Frees the memory
+//
+// returns TRUE for success
+//*****************************************************************************
+
+BOOL DestroyAccelAlias(WORD hTask16)
+{
+ WORD hCurTask16;
+ LPACCELALIAS lpT;
+ LPACCELALIAS lpTFree;
+
+ hCurTask16 = CURRENTPTD()->htask16;
+ lpT = lpAccelAlias;
+ while (lpT) {
+ if (lpT->hTask16 == hCurTask16) {
+ if (lpT->lpPrev)
+ lpT->lpPrev->lpNext = lpT->lpNext;
+
+ if (lpT->lpNext)
+ lpT->lpNext->lpPrev = lpT->lpPrev;
+
+ if ( lpT->f16 ) {
+ DestroyAcceleratorTable(lpT->h32);
+ } else {
+ // this function - DestroyAccelAlias- gets called during
+ // taskexit time and the 16bit task cleanup code has already
+ // freed this memory handle. so this callback is not needed.
+ // - nanduri
+ // WOWGlobalFree16( lpT->h16 );
+ }
+
+ lpTFree = lpT;
+ lpT = lpT->lpNext;
+ if (lpTFree == lpAccelAlias)
+ lpAccelAlias = lpT;
+
+ free_w_small(lpTFree);
+ }
+ else
+ lpT = lpT->lpNext;
+ }
+
+
+ return TRUE;
+}
+
+
+//*****************************************************************************
+// FindAccelAlias -
+// maps 16 bit handle to 32bit handle and vice versa
+//
+// returns TRUE for success
+//*****************************************************************************
+
+LPACCELALIAS FindAccelAlias(HANDLE hAccel, UINT fSize)
+{
+ WORD hCurTask16;
+ LPACCELALIAS lpT;
+
+ hCurTask16 = CURRENTPTD()->htask16;
+ lpT = lpAccelAlias;
+ while (lpT) {
+ if (lpT->hTask16 == hCurTask16) {
+ if (fSize & HANDLE_16BIT) {
+ if (lpT->h16 == (HAND16)hAccel)
+ return lpT;
+ }
+ else {
+ if (lpT->h32 == (HAND32)hAccel)
+ return lpT;
+ }
+ }
+
+ lpT = lpT->lpNext;
+ }
+
+ return NULL;
+}
+
+
+//*****************************************************************************
+// GetAccelHandle32 -
+// Returns h32, given h16.
+//
+//*****************************************************************************
+
+HAND32 GetAccelHandle32(HAND16 h16)
+{
+ LPACCELALIAS lpT;
+
+ if (!(lpT = FindAccelAlias((HANDLE)(h16), HANDLE_16BIT))) {
+ DWORD cbAccel16;
+ VPVOID vpAccel16;
+ HACCEL hAccel;
+
+ if (vpAccel16 = RealLockResource16(h16, &cbAccel16)) {
+ if (hAccel = CreateAccel32(vpAccel16, cbAccel16)) {
+ lpT = SetupAccelAlias(CURRENTPTD()->hInst16, h16, hAccel, TRUE);
+ }
+ GlobalUnlock16(h16);
+ }
+ }
+ return (lpT) ? lpT->h32 : (HAND32)NULL;
+
+}
+
+//*****************************************************************************
+// GetAccelHandle16 -
+// Returns h16, given h32.
+//
+//*****************************************************************************
+
+HAND16 GetAccelHandle16(HAND32 h32)
+{
+ LPACCELALIAS lpT;
+ HAND16 hAccel16;
+
+ if (!(lpT = FindAccelAlias((HANDLE)(h32), HANDLE_32BIT))) {
+ //
+ // There isn't a corresponding 16-bit accelerator table handle already
+ // so create one.
+ //
+ if ( (hAccel16 = CreateAccel16(h32)) != 0 ) {
+ lpT = SetupAccelAlias(CURRENTPTD()->hInst16, hAccel16, h32, FALSE );
+ }
+ }
+
+ return (lpT) ? lpT->h16 : (HAND16)NULL;
+}
+
+//*****************************************************************************
+// CreateAccel32 -
+// This gets called from WU32NotifyWow.
+//
+// returs TRUE for success.
+//*****************************************************************************
+
+
+HACCEL CreateAccel32(VPVOID vpAccel16, DWORD cbAccel16)
+{
+ PSZ pAccel16;
+ DWORD nElem16;
+
+ LPACCEL lpAccel;
+ HACCEL hAccel = (HACCEL)NULL;
+ UINT i;
+#if DBG
+ UINT LastKeyIndex = 0xffffffff;
+#endif
+
+ //
+ // pAccel16 is pointer to an array of records of length:
+ // (BYTE+WORD+WORD)
+ //
+
+ GETVDMPTR(vpAccel16 , cbAccel16, pAccel16);
+ if (pAccel16) {
+
+ //
+ // convert the 16bit accel table to 32bit format and create it.
+ //
+
+ nElem16 = cbAccel16 / (sizeof(BYTE) + 2 * sizeof(WORD));
+ lpAccel = (LPACCEL)malloc_w(nElem16 * sizeof(ACCEL));
+ if (lpAccel) {
+ for (i=0; i<nElem16; ++i) {
+ lpAccel[i].fVirt = *(LPBYTE)(pAccel16);
+#if DBG
+ if ((lpAccel[i].fVirt & 0x80) && i < LastKeyIndex) {
+ LastKeyIndex = i;
+ }
+#endif
+ ((LPBYTE)pAccel16)++;
+ lpAccel[i].key = FETCHWORD(*(LPWORD)pAccel16);
+ ((LPWORD)pAccel16)++;
+ lpAccel[i].cmd = FETCHWORD(*(LPWORD)pAccel16);
+ ((LPWORD)pAccel16)++;
+ }
+
+#if DBG
+ if (LastKeyIndex == 0xffffffff) {
+ LOGDEBUG(LOG_ALWAYS, ("WOW::CreateAccel32 : no LastKey found in 16-bit haccel\n"));
+ } else if (LastKeyIndex < nElem16-1) {
+ LOGDEBUG(LOG_ALWAYS, ("WOW::CreateAccel32 : bogus LastKey flags ignored in 16-bit haccel\n"));
+ }
+#endif
+ hAccel = CreateAcceleratorTable(lpAccel, i);
+ free_w(lpAccel);
+ }
+ FREEVDMPTR(pAccel16);
+ }
+
+ return hAccel;
+}
+
+//*****************************************************************************
+// CreateAccel16 -
+// This gets called from WU32NotifyWow.
+//
+// returns HACCEL16 for success.
+//*****************************************************************************
+
+HAND16 CreateAccel16(HACCEL hAccel32)
+{
+ UINT iEntries;
+ UINT cbSize;
+ LPACCEL lpAccel32;
+ HAND16 hAccel16;
+ VPVOID vpAccel16;
+ LPBYTE lpAccel16;
+ LPBYTE lpAccel16Original;
+ UINT i;
+
+ iEntries = CopyAcceleratorTable( hAccel32, NULL, 0 );
+
+ if ( iEntries == 0 ) { // Invalid hAccel32
+ return( 0 );
+ }
+
+ lpAccel32 = (LPACCEL)malloc_w(iEntries * sizeof(ACCEL));
+ if ( lpAccel32 == NULL ) {
+ LOGDEBUG(LOG_ERROR, ("WOW::CreateAccel16 : Failed to alloc memory for 32-bit accel\n"));
+ return( 0 );
+ }
+
+ iEntries = CopyAcceleratorTable( hAccel32, lpAccel32, iEntries );
+
+ cbSize = iEntries * (sizeof(BYTE) + 2 * sizeof(WORD));
+
+ vpAccel16 = GlobalAllocLock16( GMEM_MOVEABLE, cbSize, &hAccel16 );
+
+ if ( vpAccel16 == 0 ) { // Out of 16-bit memory
+ LOGDEBUG(LOG_ERROR, ("WOW::CreateAccel16 : Failed to alloc memory for 16-bit haccel\n"));
+ free_w( lpAccel32 );
+ return( 0 );
+ }
+
+ GETVDMPTR(vpAccel16, cbSize, lpAccel16 );
+
+ WOW32ASSERT( lpAccel16 != NULL );
+
+ lpAccel16Original = lpAccel16;
+
+ //
+ // Now iterate through the entries changing them and moving them into
+ // the 16-bit memory.
+ //
+
+ i = 0;
+
+ while ( i < iEntries ) {
+ if ( i == iEntries-1 ) {
+ // Last one, set the last bit
+ *lpAccel16++ = lpAccel32[i].fVirt | 0x80;
+ } else {
+ *lpAccel16++ = lpAccel32[i].fVirt;
+ }
+ *((PWORD16)lpAccel16) = lpAccel32[i].key;
+ lpAccel16 += sizeof(WORD);
+ *((PWORD16)lpAccel16) = lpAccel32[i].cmd;
+ lpAccel16 += sizeof(WORD);
+
+ i++;
+ }
+
+ FLUSHVDMPTR(vpAccel16, cbSize, lpAccel16Original);
+ FREEVDMPTR(lpAccel16Original);
+
+ GlobalUnlock16( hAccel16 );
+
+ return( hAccel16 );
+}
+
+
+
+// this gets called indirectly from GlobalFree() in krnl386.exe
+// via WK32WowCursorIconOp() in wcuricon.c
+void FreeAccelAliasEntry(LPACCELALIAS lpT) {
+
+ if (lpT == lpAccelAlias)
+ lpAccelAlias = lpT->lpNext;
+
+ if (lpT->lpPrev)
+ lpT->lpPrev->lpNext = lpT->lpNext;
+
+ if (lpT->lpNext)
+ lpT->lpNext->lpPrev = lpT->lpPrev;
+
+ if ( lpT->f16 ) {
+ DestroyAcceleratorTable(lpT->h32);
+ } else {
+ // this function - FreeAccelAliasEntry -- is being called
+ // indirectly from GlobalFree() in krnl386. GlobalFree()
+ // takes care of freeing h16 so this callback is not needed.
+ // - a-craigj
+ // WOWGlobalFree16( lpT->h16 );
+ }
+
+ free_w_small(lpT);
+}
+
diff --git a/private/mvdm/wow32/waccel.h b/private/mvdm/wow32/waccel.h
new file mode 100644
index 000000000..15083a148
--- /dev/null
+++ b/private/mvdm/wow32/waccel.h
@@ -0,0 +1,34 @@
+//*****************************************************************************
+//
+// LoadAccelerator - compatibility support.
+//
+//
+// 23-Jul-92 NanduriR Created.
+//*****************************************************************************
+
+
+typedef struct _ACCELALIAS {
+ struct _ACCELALIAS FAR *lpNext;
+ struct _ACCELALIAS FAR *lpPrev;
+ HAND16 hInst;
+ HTASK16 hTask16;
+ WORD f16; // WORD only for padding, could be BOOL,DWORD
+ HAND16 h16;
+ HAND32 h32;
+} ACCELALIAS, FAR *LPACCELALIAS;
+
+
+ULONG FASTCALL WU32LoadAccelerators(VPVOID vpData);
+LPACCELALIAS SetupAccelAlias(HAND16 hInstance, HAND16 hAccel16, HAND32 hAccel32, BOOL f16);
+BOOL DestroyAccelAlias(WORD hTask16);
+LPACCELALIAS FindAccelAlias(HANDLE hAccel, UINT fSize);
+HAND32 GetAccelHandle32(HAND16 h16);
+HAND16 GetAccelHandle16(HAND32 h32);
+HACCEL CreateAccel32(VPVOID vpAccel16, DWORD cbAccel16);
+HAND16 CreateAccel16(HACCEL hAccel32);
+
+
+#define HANDLE_16BIT 0x01
+#define HANDLE_32BIT 0x02
+#define HACCEL32(h16) GetAccelHandle32(h16)
+#define GETHACCEL16(h32) GetAccelHandle16(h32)
diff --git a/private/mvdm/wow32/walias.c b/private/mvdm/wow32/walias.c
new file mode 100644
index 000000000..27185aa37
--- /dev/null
+++ b/private/mvdm/wow32/walias.c
@@ -0,0 +1,686 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WALIAS.C
+ * WOW32 16-bit handle alias support
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * Modified 12-May-1992 by Mike Tricker (miketri) to add MultiMedia support
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(walias.c);
+
+//BUGBUG - this must be removed once MM_MCISYSTEM_STRING is defined in MMSYSTEM.H.
+#ifndef MM_MCISYSTEM_STRING
+ #define MM_MCISYSTEM_STRING 0x3CA
+#endif
+
+#ifdef DEBUG
+extern BOOL fSkipLog; // TRUE to temporarily skip certain logging
+#endif
+
+typedef struct _stdclass {
+ LPSTR lpszClassName;
+ ATOM aClassAtom;
+ WNDPROC lpfnWndProc;
+ INT iOrdinal;
+ DWORD vpfnWndProc;
+} STDCLASS;
+
+// Some cool defines stolen from USERSRV.H
+#define MENUCLASS MAKEINTATOM(0x8000)
+#define DESKTOPCLASS MAKEINTATOM(0x8001)
+#define DIALOGCLASS MAKEINTATOM(0x8002)
+#define SWITCHWNDCLASS MAKEINTATOM(0x8003)
+#define ICONTITLECLASS MAKEINTATOM(0x8004)
+
+// See WARNING below!
+STDCLASS stdClasses[] = {
+ NULL, 0, NULL, 0, 0, // WOWCLASS_UNKNOWN
+ NULL, 0, NULL, 0, 0, // WOWCLASS_WIN16
+ "BUTTON", 0, NULL, FUN_BUTTONWNDPROC, 0, // WOWCLASS_BUTTON,
+ "COMBOBOX", 0, NULL, FUN_COMBOBOXCTLWNDPROC, 0, // WOWCLASS_COMBOBOX,
+ "EDIT", 0, NULL, FUN_EDITWNDPROC, 0, // WOWCLASS_EDIT,
+ "LISTBOX", 0, NULL, FUN_LBOXCTLWNDPROC, 0, // WOWCLASS_LISTBOX,
+ "MDICLIENT", 0, NULL, FUN_MDICLIENTWNDPROC, 0, // WOWCLASS_MDICLIENT,
+ "SCROLLBAR", 0, NULL, FUN_SBWNDPROC, 0, // WOWCLASS_SCROLLBAR,
+ "STATIC", 0, NULL, FUN_STATICWNDPROC, 0, // WOWCLASS_STATIC,
+ "#32769", (WORD)DESKTOPCLASS, NULL, FUN_DESKTOPWNDPROC, 0, // WOWCLASS_DESKTOP,
+ "#32770", (WORD)DIALOGCLASS, NULL, FUN_DEFDLGPROCTHUNK, 0, // WOWCLASS_DIALOG,
+ "#32772", (WORD)ICONTITLECLASS, NULL, FUN_TITLEWNDPROC, 0, // WOWCLASS_ICONTITLE,
+ "#32768", (WORD)MENUCLASS, NULL, FUN_MENUWNDPROC, 0, // WOWCLASS_MENU,
+ "#32771", (WORD)SWITCHWNDCLASS, NULL, 0, 0, // WOWCLASS_SWITCHWND,
+ "COMBOLBOX", 0, NULL, FUN_LBOXCTLWNDPROC, 0, // WOWCLASS_COMBOLBOX
+};
+//
+// WARNING! The above sequence and values must be maintained otherwise the
+// table in WMSG16.C for message thunking must be changed. Same goes for
+// the #define's in WALIAS.H
+//
+// The above COMBOLBOX case is special because it is class that is
+// almost identical to a listbox. Therefore we lie about it.
+
+INT GetStdClassNumber(
+ PSZ pszClass
+) {
+ INT i;
+
+ if ( HIWORD(pszClass) ) {
+
+ // They passed us a string
+
+ for ( i = WOWCLASS_BUTTON; i < NUMEL(stdClasses); i++ ) {
+ if ( _stricmp(pszClass, stdClasses[i].lpszClassName) == 0 ) {
+ return( i );
+ }
+ }
+ } else {
+
+ // They passed us an atom
+
+ for ( i = WOWCLASS_BUTTON; i < NUMEL(stdClasses); i++ ) {
+ if ( stdClasses[i].aClassAtom == 0 ) {
+ // RegisterWindowMessage is an undocumented way of determining
+ // an atom value in the context of the server-side heap.
+ stdClasses[i].aClassAtom = RegisterWindowMessage(stdClasses[i].lpszClassName);
+ }
+ if ( (ATOM)LOWORD(pszClass) == stdClasses[i].aClassAtom ) {
+ return( i );
+ }
+ }
+ }
+ return( WOWCLASS_UNKNOWN );
+}
+
+// Returns a 32 window proc given a class index
+
+WNDPROC GetStdClassWndProc(
+ DWORD iClass
+) {
+ WNDPROC lpfn32;
+
+ if ( iClass < WOWCLASS_UNKNOWN || iClass > WOWCLASS_MAX ) {
+ WOW32ASSERT(FALSE);
+ return( NULL );
+ }
+
+ lpfn32 = stdClasses[iClass].lpfnWndProc;
+
+ if ( lpfn32 == NULL ) {
+ WNDCLASS wc;
+ BOOL f;
+
+ f = GetClassInfo( NULL, stdClasses[iClass].lpszClassName, &wc );
+
+ if ( f ) {
+ VPVOID vp;
+ DWORD UNALIGNED * lpdw;
+
+ lpfn32 = wc.lpfnWndProc;
+ stdClasses[iClass].lpfnWndProc = lpfn32;
+
+ vp = GetStdClassThunkProc(iClass);
+ vp = (VPVOID)((DWORD)vp - sizeof(DWORD)*3);
+
+ GETVDMPTR( vp, sizeof(DWORD)*3, lpdw );
+
+ WOW32ASSERT(*lpdw == SUBCLASS_MAGIC); // Are we editing the right stuff?
+
+ if (!lpdw)
+ *(lpdw+2) = (DWORD)lpfn32;
+
+ FLUSHVDMCODEPTR( vp, sizeof(DWORD)*3, lpdw );
+ FREEVDMPTR( lpdw );
+
+ }
+ }
+ return( lpfn32 );
+}
+
+// Returns a 16 window proc thunk given a class index
+
+DWORD GetStdClassThunkProc(
+ INT iClass
+) {
+ DWORD dwResult;
+ INT iOrdinal;
+ PARM16 Parm16;
+
+ if ( iClass < WOWCLASS_UNKNOWN || iClass > WOWCLASS_MAX ) {
+ WOW32ASSERT(FALSE);
+ return( 0 );
+ }
+
+ iOrdinal = stdClasses[iClass].iOrdinal;
+
+ if ( iOrdinal == 0 ) {
+ return( (DWORD)NULL );
+ }
+
+ // If we've already gotten this proc, then don't bother calling into 16-bit
+ dwResult = stdClasses[iClass].vpfnWndProc;
+
+ if ( dwResult == (DWORD)NULL ) {
+
+ // Callback into the 16-bit world asking for the 16:16 address
+
+ Parm16.SubClassProc.iOrdinal = iOrdinal;
+
+ if (!CallBack16(RET_SUBCLASSPROC, &Parm16, (VPPROC)NULL,
+ (PVPVOID)&dwResult)) {
+ WOW32ASSERT(FALSE);
+ return( 0 );
+ }
+ // Save it since it is a constant.
+ stdClasses[iClass].vpfnWndProc = dwResult;
+ }
+ return( dwResult );
+}
+
+PWW FindPWW(HANDLE h32, INT iClass)
+{
+
+ PWW pww;
+ CHAR szClassName[16];
+
+ if (!h32) {
+ return (PWW) NULL;
+ }
+ else {
+ try {
+ pww = (PWW) GetWindowLong(h32, GWL_WOWWORDS);
+ }
+ except (EXCEPTION_ACCESS_VIOLATION == GetExceptionCode()) {
+ pww = (PWW) NULL;
+ }
+
+ if (pww) {
+ if (WOWCLASS_UNKNOWN == pww->iClass &&
+ !(pww->flState & WWSTATE_ICLASSISSET)) {
+
+ if (WOWCLASS_UNKNOWN == iClass &&
+ GetClassName(h32, szClassName, sizeof(szClassName))) {
+
+ iClass = GetStdClassNumber(szClassName);
+
+ }
+
+ if (WOWCLASS_UNKNOWN != iClass) {
+ SETWL(h32, GWL_WOWiClassAndflState,
+ MAKECLASSANDSTATE(iClass, pww->flState | WWSTATE_ICLASSISSET));
+ } else {
+ SETWL(h32, GWL_WOWiClassAndflState,
+ MAKECLASSANDSTATE(pww->iClass, pww->flState | WWSTATE_ICLASSISSET));
+ }
+ }
+ }
+ else {
+ LOGDEBUG(2,("WOW::FindPWW(): *** Invalid hwnd32 %08x\n", h32));
+ }
+ }
+
+ return (pww);
+}
+
+PWC FindPWC(HANDLE h32)
+{
+ PWC pwc;
+
+ try {
+ pwc = (PWC) GetClassLong(h32, GCL_WOWWORDS);
+ WOW32ASSERT(pwc);
+ }
+ except (EXCEPTION_ACCESS_VIOLATION == GetExceptionCode()) {
+ pwc = (PWC) NULL;
+ LOGDEBUG(LOG_ALWAYS,("WOW::FindPWC(): *** Invalid hwnd32 %08x\n", h32));
+ WOW32ASSERT(FALSE);
+ }
+
+ return (pwc);
+}
+
+/*
+ * PWC GetClassWOWWords(hInst, pszClass)
+ * is a ***private*** API for WOW only. It returns a pointer to the
+ * WOW Class structure in the server's window class structure.
+ * This is similar to GetClassLong(hwnd32, GCL_WOWWORDS) (see FindPWC),
+ * but in this case we don't have a hwnd32, we have the class name
+ * and instance handle.
+ */
+
+PWC FindClass16(LPCSTR pszClass, HAND16 hInst)
+{
+ register PWC pwc;
+
+ pwc = (PWC)(pfnOut.pfnGetClassWOWWords)(HMODINST32(hInst), pszClass);
+ WOW32WARNMSGF(
+ pwc,
+ ("WOW32 warning: GetClassWOWWords('%s', %04x) returned NULL\n", pszClass, hInst)
+ );
+
+ return (pwc);
+}
+
+
+
+#ifdef DEBUG
+
+INT nAliases;
+INT iLargestListSlot;
+
+PSZ apszHandleClasses[] = {
+ "Unknown", // WOWCLASS_UNKNOWN
+ "Window", // WOWCLASS_WIN16
+ "Button", // WOWCLASS_BUTTON
+ "ComboBox", // WOWCLASS_COMBOBOX
+ "Edit", // WOWCLASS_EDIT
+ "ListBox", // WOWCLASS_LISTBOX
+ "MDIClient", // WOWCLASS_MDICLIENT
+ "Scrollbar", // WOWCLASS_SCROLLBAR
+ "Static", // WOWCLASS_STATIC
+ "Desktop", // WOWCLASS_DESKTOP
+ "Dialog", // WOWCLASS_DIALOG
+ "Menu", // WOWCLASS_MENU
+ "IconTitle", // WOWCLASS_ICONTITLE
+ "Accel", // WOWCLASS_ACCEL
+ "Cursor", // WOWCLASS_CURSOR
+ "Icon", // WOWCLASS_ICON
+ "DC", // WOWCLASS_DC
+ "Font", // WOWCLASS_FONT
+ "MetaFile", // WOWCLASS_METAFILE
+ "Region", // WOWCLASS_RGN
+ "Bitmap", // WOWCLASS_BITMAP
+ "Brush", // WOWCLASS_BRUSH
+ "Palette", // WOWCLASS_PALETTE
+ "Pen", // WOWCLASS_PEN
+ "Object" // WOWCLASS_OBJECT
+};
+
+
+BOOL MessageNeedsThunking(UINT uMsg)
+{
+ switch (uMsg) {
+ case WM_CREATE:
+ case WM_ACTIVATE:
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ case WM_SETTEXT:
+ case WM_GETTEXT:
+ case WM_ERASEBKGND:
+ case WM_WININICHANGE:
+ case WM_DEVMODECHANGE:
+ case WM_ACTIVATEAPP:
+ case WM_SETCURSOR:
+ case WM_MOUSEACTIVATE:
+ case WM_GETMINMAXINFO:
+ case WM_ICONERASEBKGND:
+ case WM_NEXTDLGCTL:
+ case WM_DRAWITEM:
+ case WM_MEASUREITEM:
+ case WM_DELETEITEM:
+ case WM_VKEYTOITEM:
+ case WM_CHARTOITEM:
+ case WM_SETFONT:
+ case WM_GETFONT:
+ case WM_QUERYDRAGICON:
+ case WM_COMPAREITEM:
+ case WM_OTHERWINDOWCREATED:
+ case WM_OTHERWINDOWDESTROYED:
+ case WM_COMMNOTIFY:
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED:
+ case WM_NCCREATE:
+ case WM_NCCALCSIZE:
+ case WM_COMMAND:
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ case WM_INITMENU:
+ case WM_INITMENUPOPUP:
+ case WM_MENUSELECT:
+ case WM_MENUCHAR:
+ case WM_ENTERIDLE:
+ case WM_CTLCOLORMSGBOX:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORSTATIC:
+ case WM_PARENTNOTIFY:
+ case WM_MDICREATE:
+ case WM_MDIDESTROY:
+ case WM_MDIACTIVATE:
+ case WM_MDIGETACTIVE:
+ case WM_MDISETMENU:
+ case WM_RENDERFORMAT:
+ case WM_PAINTCLIPBOARD:
+ case WM_VSCROLLCLIPBOARD:
+ case WM_SIZECLIPBOARD:
+ case WM_ASKCBFORMATNAME:
+ case WM_CHANGECBCHAIN:
+ case WM_HSCROLLCLIPBOARD:
+ case WM_PALETTEISCHANGING:
+ case WM_PALETTECHANGED:
+ case MM_JOY1MOVE:
+ case MM_JOY2MOVE:
+ case MM_JOY1ZMOVE:
+ case MM_JOY2ZMOVE:
+ case MM_JOY1BUTTONDOWN:
+ case MM_JOY2BUTTONDOWN:
+ case MM_JOY1BUTTONUP:
+ case MM_JOY2BUTTONUP:
+ case MM_MCINOTIFY:
+ case MM_MCISYSTEM_STRING:
+ case MM_WOM_OPEN:
+ case MM_WOM_CLOSE:
+ case MM_WOM_DONE:
+ case MM_WIM_OPEN:
+ case MM_WIM_CLOSE:
+ case MM_WIM_DATA:
+ case MM_MIM_OPEN:
+ case MM_MIM_CLOSE:
+ case MM_MIM_DATA:
+ case MM_MIM_LONGDATA:
+ case MM_MIM_ERROR:
+ case MM_MIM_LONGERROR:
+ case MM_MOM_OPEN:
+ case MM_MOM_CLOSE:
+ case MM_MOM_DONE:
+ LOGDEBUG(LOG_IMPORTANT,
+ ("MessageNeedsThunking: WM_msg %04x is not thunked\n", uMsg));
+ return TRUE;
+
+ default:
+ return FALSE;
+
+ }
+}
+
+#endif
+
+
+extern PTD gptdTaskHead;
+
+PTD ThreadProcID32toPTD(DWORD dwThreadID, DWORD dwProcessID)
+{
+ PTD ptd;
+ PWOAINST pWOA;
+
+ //
+ // If we have active child instances of WinOldAp,
+ // try to map the process ID of a child Win32 app
+ // to the corresponding WinOldAp PTD.
+ //
+
+ ptd = CURRENTPTD();
+
+ pWOA = ptd->pWOAList;
+
+ while (pWOA && pWOA->dwChildProcessID != dwProcessID) {
+ pWOA = pWOA->pNext;
+ }
+
+ if (pWOA) {
+
+ ptd = pWOA->ptdWOA;
+
+ } else {
+
+ //
+ // We didn't find a WinOldAp PTD to return, see
+ // if the thread ID matches one of our app threads.
+ //
+
+ ptd = gptdTaskHead;
+
+ while (ptd && ptd->dwThreadID != dwThreadID) {
+ ptd = ptd->ptdNext;
+ }
+
+ }
+
+ return ptd;
+
+}
+
+PTD Htask16toPTD(
+ HTASK16 htask16
+) {
+ PTD ptd;
+
+ ptd = gptdTaskHead;
+
+ while(ptd) {
+
+ if ( ptd->htask16 == htask16 ) {
+ return( ptd );
+ }
+ ptd = ptd->ptdNext;
+ }
+
+ return((PTD)NULL);
+}
+
+
+HTASK16 ThreadID32toHtask16(
+ DWORD ThreadID32
+) {
+ PTD ptd;
+ HTASK16 htask16;
+
+
+ if ( ThreadID32 == 0 ) {
+ WOW32ASSERTMSG(ThreadID32, "WOW::ThreadID32tohTask16: Thread ID is 0\n");
+ htask16 = 0;
+ } else {
+
+ ptd = ThreadProcID32toPTD( ThreadID32, (DWORD)-1 );
+ if ( ptd ) {
+ // Good, its one of our wow threads.
+ htask16 = ptd->htask16;
+ } else {
+ // Nope, its is some other 32-bit thread
+ htask16 = FindHtaskAlias( ThreadID32 );
+ if ( htask16 == 0 ) {
+ //
+ // See the comment in WOLE2.C for a nice description
+ //
+ htask16 = AddHtaskAlias( ThreadID32 );
+ }
+ }
+ }
+
+ return htask16;
+}
+
+DWORD Htask16toThreadID32(
+ HTASK16 htask16
+) {
+ if ( htask16 == 0 ) {
+ return( 0 );
+ }
+
+ if ( ISTASKALIAS(htask16) ) {
+ return( GetHtaskAlias(htask16,NULL) );
+ } else {
+ return( THREADID32(htask16) );
+ }
+}
+
+//***************************************************************************
+// GetGCL_HMODULE - returns the valid hmodule if the window corresponds to
+// a 16bit class else returns the hmodule of 16bit user.exe
+// if the window is of a standard class.
+//
+// These cases are required for compatibility sake.
+// apps like VirtualMonitor, hDC etc depend on such behaviour.
+// - Nanduri
+//***************************************************************************
+WORD gUser16hInstance = 0;
+
+ULONG GetGCL_HMODULE(HWND hwnd)
+{
+ ULONG ul;
+ PTD ptd;
+ PWOAINST pWOA;
+ DWORD dwProcessID;
+
+ ul = (ULONG)GetClassLong(hwnd, GCL_HMODULE);
+
+ //
+ // hMod32 = 0xZZZZ0000
+ //
+
+ if (ul != 0 && LOWORD(ul) == 0) {
+
+ //
+ // If we have active WinOldAp children, see if this window
+ // belongs to a Win32 process spawned by one of the
+ // active winoldap's. If it is, return the hmodule
+ // of the corresponding winoldap. Otherwise we
+ // return user.exe's hinstance (why not hmodule?)
+ //
+
+ dwProcessID = (DWORD)-1;
+ GetWindowThreadProcessId(hwnd, &dwProcessID);
+
+ ptd = CURRENTPTD();
+
+ pWOA = ptd->pWOAList;
+ while (pWOA && pWOA->dwChildProcessID != dwProcessID) {
+ pWOA = pWOA->pNext;
+ }
+
+ if (pWOA) {
+ ul = pWOA->ptdWOA->hMod16;
+ LOGDEBUG(LOG_ALWAYS, ("WOW32 GetClassLong(0x%x, GWW_HMODULE) returning 0x%04x\n",
+ hwnd, ul));
+ } else {
+ ul = (ULONG) gUser16hInstance;
+ WOW32ASSERT(ul);
+ }
+ }
+ else {
+ ul = (ULONG)GETHMOD16(ul); // 32-bit hmod is HMODINST32
+ }
+
+ return ul;
+}
+
+//
+// EXPORTED handle mapping functions. WOW32 code should use the
+// macros defined in walias.h -- these functions are for use by
+// third-party 32-bit code running in WOW, for example called
+// using generic thunks from WOW-specific 16-bit code.
+//
+
+HANDLE WOWHandle32 (WORD h16, WOW_HANDLE_TYPE htype)
+{
+ switch (htype) {
+ case WOW_TYPE_HWND:
+ return HWND32(h16);
+ case WOW_TYPE_HMENU:
+ return HMENU32(h16);
+ case WOW_TYPE_HDWP:
+ return HDWP32(h16);
+ case WOW_TYPE_HDROP:
+ return HDROP32(h16);
+ case WOW_TYPE_HDC:
+ return HDC32(h16);
+ case WOW_TYPE_HFONT:
+ return HFONT32(h16);
+ case WOW_TYPE_HMETAFILE:
+ return HMETA32(h16);
+ case WOW_TYPE_HRGN:
+ return HRGN32(h16);
+ case WOW_TYPE_HBITMAP:
+ return HBITMAP32(h16);
+ case WOW_TYPE_HBRUSH:
+ return HBRUSH32(h16);
+ case WOW_TYPE_HPALETTE:
+ return HPALETTE32(h16);
+ case WOW_TYPE_HPEN:
+ return HPEN32(h16);
+ case WOW_TYPE_HACCEL:
+ return HACCEL32(h16);
+ case WOW_TYPE_HTASK:
+ return (HANDLE)HTASK32(h16);
+ case WOW_TYPE_FULLHWND:
+ return (HANDLE)FULLHWND32(h16);
+ default:
+ return(INVALID_HANDLE_VALUE);
+ }
+}
+
+WORD WOWHandle16 (HANDLE h32, WOW_HANDLE_TYPE htype)
+{
+ switch (htype) {
+ case WOW_TYPE_HWND:
+ return GETHWND16(h32);
+ case WOW_TYPE_HMENU:
+ return GETHMENU16(h32);
+ case WOW_TYPE_HDWP:
+ return GETHDWP16(h32);
+ case WOW_TYPE_HDROP:
+ return GETHDROP16(h32);
+ case WOW_TYPE_HDC:
+ return GETHDC16(h32);
+ case WOW_TYPE_HFONT:
+ return GETHFONT16(h32);
+ case WOW_TYPE_HMETAFILE:
+ return GETHMETA16(h32);
+ case WOW_TYPE_HRGN:
+ return GETHRGN16(h32);
+ case WOW_TYPE_HBITMAP:
+ return GETHBITMAP16(h32);
+ case WOW_TYPE_HBRUSH:
+ return GETHBRUSH16(h32);
+ case WOW_TYPE_HPALETTE:
+ return GETHPALETTE16(h32);
+ case WOW_TYPE_HPEN:
+ return GETHPEN16(h32);
+ case WOW_TYPE_HACCEL:
+ return GETHACCEL16(h32);
+ case WOW_TYPE_HTASK:
+ return GETHTASK16(h32);
+ default:
+ return(0xffff);
+ }
+}
+
+PVOID gpGdiHandleInfo = (PVOID)-1;
+
+//WARNING: This structure must match ENTRY in ntgdi\inc\hmgshare.h
+
+typedef struct _ENTRYWOW
+{
+ LONG l1;
+ LONG l2;
+ USHORT FullUnique;
+ USHORT us1;
+ LONG l3;
+} ENTRYWOW, *PENTRYWOW;
+
+//
+// this routine converts a 16bit GDI handle to a 32bit handle. There
+// is no need to do any validation on the handle since the 14bit space
+// for handles ignoring the low two bits is completely contained in the
+// valid 32bit handle space.
+//
+
+HANDLE hConvert16to32(int h16)
+{
+ ULONG h32;
+ int i = h16 >> 2;
+
+ h32 = i | (ULONG)(((PENTRYWOW)gpGdiHandleInfo)[i].FullUnique) << 16;
+
+ return((HANDLE)h32);
+}
diff --git a/private/mvdm/wow32/walias.h b/private/mvdm/wow32/walias.h
new file mode 100644
index 000000000..76b676c76
--- /dev/null
+++ b/private/mvdm/wow32/walias.h
@@ -0,0 +1,416 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WALIAS.H
+ * WOW32 16-bit handle alias support
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * Modified 12-May-1992 by Mike Tricker (miketri) to add MultiMedia support
+--*/
+
+typedef HANDLE HAND32;
+
+#define _WALIAS_
+#include "wspool.h"
+#include "wowuserp.h"
+
+
+/* WOW class/handle type identifiers (see WARNING below)
+ */
+#define WOWCLASS_UNKNOWN 0 // here begin our "window handle" classes
+#define WOWCLASS_WIN16 1
+#define WOWCLASS_BUTTON 2
+#define WOWCLASS_COMBOBOX 3
+#define WOWCLASS_EDIT 4
+#define WOWCLASS_LISTBOX 5
+#define WOWCLASS_MDICLIENT 6
+#define WOWCLASS_SCROLLBAR 7
+#define WOWCLASS_STATIC 8
+#define WOWCLASS_DESKTOP 9
+#define WOWCLASS_DIALOG 10
+#define WOWCLASS_ICONTITLE 11
+#define WOWCLASS_MENU 12
+#define WOWCLASS_SWITCHWND 13
+#define WOWCLASS_COMBOLBOX 14
+#define WOWCLASS_MAX 14 // Always equal to the last value used.
+
+#define WOWCLASS_NOTHUNK 0xFF // not an actual class index
+//
+// WARNING! The above sequence and values must be maintained otherwise the
+// table in WMSG16.C for message thunking must be changed. Same goes for
+// table in WALIAS.C.
+//
+
+
+//
+//
+// The WC structure is present in every CLS structure in the system,
+// although USER32 defines it as an array of 2 DWORDs. FindPWC(hwnd)
+// returns a read-only pointer to the WC structure for a given window's
+// class. Note that only classes registered by Win16 applications will
+// have meaningful values in the structure. To change elements of the
+// structure, use SETWC (== SetClassLong) with the appropriate GCL_WOW*
+// offset defined below.
+//
+
+typedef struct _WC { /* wcd */
+ VPWNDPROC vpfnWndProc; // 16-bit window proc address
+ VPSZ vpszMenu; // pointer to original copy of menu name, if any
+} WC, *PWC, **PPWC;
+
+#define GCL_WOWvpfnWndProc GCL_WOWDWORD1
+#define GCL_WOWvpszMenu GCL_WOWDWORD2
+
+#define SETWC(hwnd, nIndex, l) SetClassLong(hwnd, nIndex, l)
+
+#define GWL_WOWiClassAndflState GWL_WOWDWORD1
+#define GWL_WOWvpfnWndProc GWL_WOWDWORD2
+#define GWL_WOWvpfnDlgProc GWL_WOWDWORD3
+
+#define SETWL(hwnd, nIndex, l) SetWindowLong(hwnd, nIndex, l)
+#define MAKECLASSANDSTATE(class,state) MAKELONG((class),(state))
+
+// defines for flState of WW struct.
+
+#define WWSTATE_ICLASSISSET 0x00000001
+#define WWSTATE_FAKEDIALOGCLASS 0x00000002
+
+
+typedef struct _HDW {
+ struct _HDW *Next; // pointer to next hDDE alias
+ HANDLE hdwp32; // handle of WOW allocated 32 bit object
+} HDW, *PHDW;
+
+
+/* Handle mapping macros
+ */
+
+//
+// The 32-bit hInstance for a 16-bit task will be hMod / hInst.
+// The hModule/hInstnace for a 32-bit entity will be xxxx / 0000.
+//
+// FritzS 8/13/92
+//
+
+#define HINSTRES32(h16) ((h16)?HMODINST32(h16):(HANDLE)NULL)
+
+//
+// The THREADID32 and HTASK32 macros are nearly equivalent, but the
+// WOWHandle mapping uses the one which will detect aliases (see WOLE2.C).
+// Most other functions don't need alias detection and it is too late
+// to test with the more general.
+//
+
+#ifdef DEBUG
+
+//
+// Check for task aliases that will cause us to fault if we dereference the NULL
+// pointer returned by SEGPTR(htask16,0).
+//
+
+#define THREADID32(htask16) \
+ ((htask16) \
+ ? (ISTASKALIAS(htask16) \
+ ? (WOW32ASSERTMSGF(FALSE, \
+ ("WOW32 ERROR %s line %d Task alias " \
+ "to THREADID32, use HTASK32 instead.\n", \
+ szModule, __LINE__)), 0) \
+ : ((PTDB)SEGPTR((htask16),0))->TDB_ThreadID) \
+ : 0)
+#else
+#define THREADID32(htask16) ((htask16) \
+ ? ((PTDB)SEGPTR((htask16),0))->TDB_ThreadID \
+ : 0)
+#endif
+
+#define HTASK32(htask16) (Htask16toThreadID32(htask16))
+#define GETHTASK16(htask32) (ThreadID32toHtask16((DWORD)htask32))
+
+#define ISINST16(h32) (((INT)(h32) & 0x0000ffff) != 0)
+#define HMODINST32(h16) ((HANDLE) MAKELONG(h16, GetExePtr16(h16)))
+#define GETHINST16(h32) ((HAND16)(INT)(h32))
+#define GETHMOD16(h32) ((HAND16)(INT)(HIWORD(h32)))
+
+#define ISMEM16(h32) (((INT)(h32) & 0xFFFF0000) == 0)
+#define HMEM32(h16) ((HANDLE)(INT)(h16))
+#define GETHMEM16(h32) ((HMEM16)(INT)(h32))
+
+#define ISRES16(h32) ((INT)(h32)&1)
+#define HRES32(p) ((p)?(HANDLE)((INT)(p)|1):(HANDLE)NULL)
+#define GETHRES16(h32) ((PRES)((INT)(h32)&~1))
+
+//
+// USER handle mapping WARNING:
+//
+// When using any of the following macros, beware:
+//
+// Macro Safe function call equivalent
+// --------------------- -----------------------------
+// USER32 GetUser32
+// HWND32 GetHwnd32
+// HMENU32 GetHmenu32
+//
+// The macro versions of the USER handle mapping functions evaluate their
+// argument twice, so be extra careful to avoid the following type of
+// error:
+//
+// h32 = HWND32(callback16(...)); // WRONG!!
+//
+// The above statement calls CreateWindows twice! Instead use the equivalent
+// function call from the table above, which is safe for arguments that must
+// only be evaluated once:
+//
+// h32 = GetHwnd32(callback16(...)); // Correct
+//
+// Use the macro form only when it's safe to evaluate the argument twice:
+//
+// h32 = HWND32(h16); // Correct
+//
+
+#define USER32(h16) ((HAND32)(INT)(SHORT)(h16))
+#define USER16(h32) ((HAND16)h32)
+
+#define HWND32(h16) USER32(h16)
+#define FULLHWND32(h16) (pfnOut.pfnGetFullUserHandle)(h16)
+#define GETHWND16(h32) USER16(h32)
+#define GETHWNDIA16(h32) GETHWND16(h32)
+#define HWNDIA32(h16) HWND32(h16)
+
+#define HMENU32(h16) USER32(h16)
+#define GETHMENU16(h32) USER16(h32)
+
+
+#define SERVERHANDLE(h) (HIWORD(h))
+
+#define GDI32(h16) (HANDLE) hConvert16to32(h16)
+#define GDI16(h32) (HAND16) (((DWORD) (h32)) << 2)
+
+#define HGDI16(hobj32) GDI16((HAND32)(hobj32))
+
+#define HDC32(hdc16) GDI32((HAND16)(hdc16))
+#define GETHDC16(hdc32) GDI16((HAND32)(hdc32))
+#define FREEHDC16(hdc16)
+
+#define HFONT32(hobj16) GDI32((HAND16)(hobj16))
+#define GETHFONT16(hobj32) GDI16((HAND32)(hobj32))
+#define FREEHFONT16(hobj16)
+
+#define HMETA32(hobj16) ((HANDLE)HMFFromWinMetaFile((HAND16)(hobj16),FALSE))
+#define GETHMETA16(hobj32) ((HAND16)WinMetaFileFromHMF((HMETAFILE)(hobj32),FALSE))
+#define FREEHMETA16(hobj16)
+
+#define HRGN32(hobj16) GDI32((HAND16)(hobj16))
+#define GETHRGN16(hobj32) GDI16((HAND32)(hobj32))
+#define FREEHRGN16(hobj16)
+
+#define HBITMAP32(hobj16) GDI32((HAND16)(hobj16))
+#define GETHBITMAP16(hobj32) GDI16((HAND32)(hobj32))
+#define FREEHBITMAP16(hobj16)
+
+#define HBRUSH32(hobj16) GDI32((HAND16)(hobj16))
+#define GETHBRUSH16(hobj32) GDI16((HAND32)(hobj32))
+#define FREEHBRUSH16(hobj16)
+
+#define HPALETTE32(hobj16) GDI32((HAND16)(hobj16))
+#define GETHPALETTE16(hobj32) GDI16((HAND32)(hobj32))
+#define FREEHPALETTE16(hobj16)
+
+#define HPEN32(hobj16) GDI32((HAND16)(hobj16))
+#define GETHPEN16(hobj32) GDI16((HAND32)(hobj32))
+#define FREEHPEN16(hobj16)
+
+#define HOBJ32(hobj16) GDI32((HAND16)(hobj16))
+#define GETHOBJ16(hobj32) GDI16((HAND32)(hobj32))
+#define FREEHOBJ16(hobj16)
+
+#define HDROP32(hobj16) (HDROP)DropFilesHandler((HAND16)(hobj16), 0, HDROP_H16 | HDROP_ALLOCALIAS)
+#define GETHDROP16(hobj32) (HAND16)DropFilesHandler(0, (HAND32)(hobj32), HDROP_H32 | HDROP_ALLOCALIAS)
+#define FREEHDROP16(hobj16) (HDROP)DropFilesHandler((HAND16)(hobj16), 0, HDROP_H16 | HDROP_FREEALIAS)
+
+#define HMODULE32(h16) ((HANDLE)(h16)) // bogus
+#define GETHMODULE16(h32) ((HAND16)(h32)) // bogus
+
+#define HLOCAL32(h16) ((HANDLE)(h16)) // bogus
+#define GETHLOCAL16(h32) ((HAND16)(h32)) // bogus
+
+#define HANDLE32(h16) ((HANDLE)(h16)) // bogus (used in wucomm.c)
+#define GETHANDLE16(h32) ((HAND16)(h32)) // bogus (used in wucomm.c)
+
+#define BOGUSHANDLE32(h16) ((DWORD)(h16)) // bogus
+
+#define HDWP32(hdwp16) Prn32((HAND16)(hdwp16))
+#define GETHDWP16(hdwp32) GetPrn16((HAND32)(hdwp32))
+#define FREEHDWP16(h16) FreePrn((HAND16)(h16))
+
+
+/*
+ * MultiMedia handle mappings - MikeTri 12-May-1992
+ *
+ * change WOWCLASS_UNKNOWN to WOWCLASS_WIN16 MikeTri 210292
+ */
+
+#define HDRVR32(hdrvr16) GetMMedia32((HAND16)(hdrvr16))
+#define GETHDRVR16(hdrvr32) GetMMedia16((HAND32)(hdrvr32), WOWCLASS_WIN16)
+#define FREEHDRVR16(hdrvr16) FreeMMedia16((HAND16)(hdrvr16))
+
+#define HMMIO32(hmmio16) GetMMedia32((HAND16)(hmmio16))
+#define GETHMMIO16(hmmio32) GetMMedia16((HAND32)(hmmio32), WOWCLASS_WIN16)
+#define FREEHMMIO16(hmmio16) FreeMMedia16((HAND16)(hmmio16))
+
+#define HMIDIIN32(hmidiin16) GetMMedia32((HAND16)(hmidiin16))
+#define GETHMIDIIN16(hmidiin32) GetMMedia16((HAND32)(hmidiin32), WOWCLASS_WIN16)
+#define FREEHMIDIIN16(hmidiin16) FreeMMedia16((HAND16)(hmidiin16))
+
+#define HMIDIOUT32(hmidiout16) GetMMedia32((HAND16)(hmidiout16))
+#define GETHMIDIOUT16(hmidiout32) GetMMedia16((HAND32)(hmidiout32), WOWCLASS_WIN16)
+#define FREEHMIDIOUT16(hmidiout16) FreeMMedia16((HAND16)(hmidiout16))
+
+#define HWAVEIN32(hwavein16) GetMMedia32((HAND16)(hwavein16))
+#define GETHWAVEIN16(hwavein32) GetMMedia16((HAND32)(hwavein32), WOWCLASS_WIN16)
+#define FREEHWAVEIN16(hwavein16) FreeMMedia16((HAND16)(hwavein16))
+
+#define HWAVEOUT32(hwaveout16) GetMMedia32((HAND16)(hwaveout16))
+#define GETHWAVEOUT16(hwaveout32) GetMMedia16((HAND32)(hwaveout32), WOWCLASS_WIN16)
+#define FREEHWAVEOUT16(hwaveout16) FreeMMedia16((HAND16)(hwaveout16))
+
+/* Function prototypes
+ */
+
+INT GetStdClassNumber(PSZ pszClass);
+WNDPROC GetStdClassWndProc(DWORD iClass);
+DWORD GetStdClassThunkProc(INT iClass);
+
+PWC FindPWC (HANDLE h32);
+PWC FindClass16 (LPCSTR pszClass, HINST16 hInst16);
+PWW FindPWW (HAND32 h32, INT iClass);
+
+HAND16 GetMMedia16 (HANDLE h32, INT iClass); //MultiMedia additions - MikeTri 12-May-1992
+HANDLE GetMMedia32 (HAND16 h16);
+VOID FreeMMedia16 (HAND16 h16);
+
+HAND16 GetWinsock16 (INT h32, INT iClass); //Winsock additions - DavidTr 4-Oct-1992
+DWORD GetWinsock32 (HAND16 h16);
+VOID FreeWinsock16 (HAND16 h16);
+
+BOOL MessageNeedsThunking (UINT uMsg);
+
+DWORD Htask16toThreadID32(HTASK16 htask16);
+
+/* Dialog function data
+ */
+
+typedef struct _DLGDATA { /* dlgdata */
+ VPPROC vpfnDlgProc; // 16-bit dialog function
+ DWORD dwUserInitParam; // user init param, if any
+} DLGDATA, *PDLGDATA;
+
+
+/* Data structure used in thunking LB_GETTEXT special case
+ */
+
+typedef struct _THUNKTEXTDWORD {
+ BOOL fDWORD; // dword used or text
+ DWORD dwDataItem; // dword
+} THUNKTEXTDWORD, *PTHUNKTEXTDWORD;
+
+typedef union _MSGTHUNKBUFFER {
+ MSG msg;
+ DRAWITEMSTRUCT ditem;
+ MEASUREITEMSTRUCT mitem;
+ DELETEITEMSTRUCT delitem;
+ COMPAREITEMSTRUCT cmpitem;
+ RECT rect;
+ DLGDATA dlgdata;
+ CREATESTRUCT cstruct;
+ WINDOWPOS winpos;
+ CLIENTCREATESTRUCT clcstruct;
+ MDINEXTMENU mnm;
+ MDICREATESTRUCT mdis;
+ DROPSTRUCT dps;
+ POINT pt[5]; // WM_GETMINMAXINFO
+ UINT uinteger[2]; // SBM_GETRANGE
+ BYTE cmdichild[sizeof(CREATESTRUCT) +
+ sizeof(MDICREATESTRUCT)]; // FinishThunking...
+ BYTE cmdiclient[sizeof(CREATESTRUCT) +
+ sizeof(CLIENTCREATESTRUCT)]; // FinishThunking...
+ BYTE calcsz[sizeof(NCCALCSIZE_PARAMS) +
+ sizeof(WINDOWPOS)];
+ THUNKTEXTDWORD thkdword; // LB_GETTEXT w/no HASSTRINGS
+} MSGTHUNKBUFFER, *LPMSGTHUNKBUFFER;
+
+typedef struct _MSGPARAMEX *LPMSGPARAMEX;
+typedef BOOL (FASTCALL *LPFNTHUNKMSG16)(LPMSGPARAMEX lpmpex);
+typedef VOID (FASTCALL *LPFNUNTHUNKMSG16)(LPMSGPARAMEX lpmpex);
+
+typedef struct _MSGPARAMEX {
+ PARM16 Parm16;
+ HWND hwnd;
+ UINT uMsg;
+ UINT uParam;
+ LONG lParam;
+ LONG lReturn;
+ LPFNUNTHUNKMSG16 lpfnUnThunk16;
+ PWW pww;
+ INT iMsgThunkClass; // thunking aid
+ INT iClass;
+ MSGTHUNKBUFFER MsgBuffer[1];
+} MSGPARAMEX;
+
+#define MSG16NEEDSTHUNKING(lpmpex) ((lpmpex)->iClass != WOWCLASS_NOTHUNK)
+
+// Used for compatibility sake. If app gets The hInstance of a 32bit window
+// (the loword of 32bit hinstance is zero) then return a bogus gdt.
+//
+// Subsequently, if the app does a getmodulefilename on it we will return a
+// a fake 32bit modulename.
+//
+// This is required for a couple of HDC apps and 16bit recorder.
+//
+// - Nanduri
+//
+
+#define BOGUSGDT 0xfff0
+#define VALIDHMOD(h32) (((h32) && !(WORD)(h32)) ? BOGUSGDT : (WORD)(h32))
+
+
+
+// For DEVMODE struct handling
+// We add a little extra to devmode sizes that we return to 16-bit apps
+// including a signature "DM31" at the end of the driver extra stuff
+// See notes in wstruc.c
+
+typedef struct _WOWDM31 {
+ DWORD dwWOWSig;
+ WORD dmSpecVersion;
+ WORD dmSize;
+ WORD dmDriverExtra;
+ WORD reserved; // pad to even DWORD (required for ptr arithmetic)
+} WOWDM31;
+typedef WOWDM31 UNALIGNED *PWOWDM31;
+
+// WOW DEVMODE magic signature
+#define WOW_DEVMODE31SIG 0x444d3331 // "DM31"
+
+// Win3.1 DEVMODE spec
+#define WOW_DEVMODE31SPEC 0x30A
+
+// Constant we add to Win3.1 DevMode->DriverExtra to account for the NT Devmode
+// fields not in the Win3.1 devmode & the WOW thunk info we add to the end
+#define WOW_DEVMODEEXTRA ((sizeof(DEVMODE)-sizeof(DEVMODE31))+sizeof(WOWDM31))
+
+
+
+extern WORD gUser16hInstance;
+ULONG GetGCL_HMODULE(HWND hwnd);
+
+#define ISFUNCID(dwcallid) (!((DWORD)(dwcallid) & 0xffff0000))
+#define POSTMSG(dwLocal) (ISFUNCID(dwLocal = \
+ FRAMEPTR(CURRENTPTD()->vpStack)->wCallID) ? \
+ (aw32WOW[dwLocal].lpfnW32 == WU32PostMessage) : \
+ (dwLocal == (DWORD) WU32PostMessage))
+
+ULONG WOW32FaxHandler(UINT iFun, LPSTR lpIn);
diff --git a/private/mvdm/wow32/walloc16.c b/private/mvdm/wow32/walloc16.c
new file mode 100644
index 000000000..f210661ee
--- /dev/null
+++ b/private/mvdm/wow32/walloc16.c
@@ -0,0 +1,271 @@
+//*****************************************************************************
+//
+// MESSAGE HEAP 16 -
+//
+// Heap allocation functions for 32-16 message thunks.
+//
+// NOTE: these are NOT general purpose heap managment routines.
+//
+//
+// 07-17-92 NanduriR Created.
+//
+//*****************************************************************************
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(walloc16.c);
+
+//*****************************************************************************
+// General Notes:
+//
+// This heap maanger is for specific 'performance gains' and is thus not
+// intended for general purpose use and therfore much of the overhead has
+// been eliminated.
+//
+// This heap manager is intended mainly for thunks - where we are sure that
+// an alloced block will definitely be freed. Thus it is meant for our use.
+//
+// The heap is conceptually an array of constant-size blocks. The size of the
+// block is predefined. The code is optimized for allocation requests of one
+// blocksize or less. It is slower if the allocation request needs more than
+// one block.
+//
+// The heap header is a static array. The header has two flags. One to note
+// that a particular heapblock is in use and the other to note whether the
+// block forms a part of a linked/chained set of contiguous blocks. The blocks
+// are linked when the allocation request is for more than the predefined
+// block size.
+//
+//*****************************************************************************
+
+
+#define HEAP16_TOTALSIZE 0x2000
+#define HEAP16_BLOCKSIZE 0x100 // We should set it to an optimum value
+#define HEAP16_BLOCKCOUNT (HEAP16_TOTALSIZE/HEAP16_BLOCKSIZE)
+
+#define HHDR16_FINUSE 0x01
+#define HHDR16_FLINKED 0x02
+
+#define ISBLOCKINUSE(block) ((block) & HHDR16_FINUSE)
+#define ISBLOCKLINKED(block) ((block) & HHDR16_FLINKED)
+
+
+//*****************************************************************************
+//
+// Globals -
+//
+// vahdr - is the heap header. This header is 32bit memory and not part of the
+// 16bit heap - this is so that the 16bit heap is put to maximum use.
+//
+// vpHeap16 - far pointer to the start of 16bit heap
+//
+// viFreeIndex - the index from which we start searching for a freeblock.
+// Normally this is set to the memoryblock that was most
+// recently freed, thus increasing the chances of finding
+// a freeblock instantly.
+//*****************************************************************************
+
+BYTE vahdr[HEAP16_BLOCKCOUNT];
+LPBYTE vpHeap16 = (LPBYTE)NULL;
+UINT viFreeIndex = 0; // First look for Free block here.
+
+
+
+//*****************************************************************************
+//
+// malloc16 -
+//
+// Allocs memory from 16bit block.
+// If heap is full, does normal GlobalAlloc
+//
+// Returns farpointer to memoryblock;
+//
+//*****************************************************************************
+
+VPVOID FASTCALL malloc16(UINT cb)
+{
+ INT i, j;
+ INT cBlocksRequired;
+ INT fContiguousFreeBlocks;
+ INT vpT;
+
+ if (vpHeap16 == (LPBYTE)NULL) {
+ vpHeap16 = (LPBYTE)GlobalAllocLock16(GMEM_MOVEABLE | GMEM_SHARE, HEAP16_TOTALSIZE,
+ NULL);
+ if (vpHeap16 != NULL) {
+
+ //
+ // Initialize heap header.
+ // LATER: is this necessary?. Heaphdr is a static array so
+ // is it already intialized to ZERO?
+ //
+
+ for(i = 0; i < HEAP16_BLOCKCOUNT ; i++) {
+ vahdr[i] = 0;
+ }
+
+ }
+
+ }
+
+ if (vpHeap16 != (LPBYTE)NULL) {
+ if (cb <= HEAP16_BLOCKSIZE && !ISBLOCKINUSE(vahdr[viFreeIndex])) {
+
+ //
+ // If 'single' block and the 'current' index is free.
+ //
+
+ vahdr[viFreeIndex] = HHDR16_FINUSE;
+ i = viFreeIndex++;
+ if (viFreeIndex == HEAP16_BLOCKCOUNT)
+ viFreeIndex = 0;
+ return (VPVOID)((LPBYTE)vpHeap16 + i * HEAP16_BLOCKSIZE);
+ }
+ else {
+
+ //
+ // if the 'current' index is not free or if 'multiple' blocks
+ //
+
+ cBlocksRequired = (cb / HEAP16_BLOCKSIZE) + 1;
+ for (i = 0; i < HEAP16_BLOCKCOUNT ; i++ ) {
+ if ((viFreeIndex + i + cBlocksRequired) <=
+ HEAP16_BLOCKCOUNT) {
+ fContiguousFreeBlocks = TRUE;
+ for (j = 0; j < cBlocksRequired; j++) {
+ if (ISBLOCKINUSE(vahdr[viFreeIndex + i + j])) {
+ fContiguousFreeBlocks = FALSE;
+ i += j;
+ break;
+ }
+ }
+
+ if (fContiguousFreeBlocks) {
+ for (j = 0; j < (cBlocksRequired - 1); j++) {
+ vahdr[viFreeIndex + i + j] =
+ (HHDR16_FINUSE | HHDR16_FLINKED);
+ }
+ vahdr[viFreeIndex + i + j] = HHDR16_FINUSE;
+
+ i += viFreeIndex;
+ viFreeIndex = i + cBlocksRequired;
+ if (viFreeIndex == HEAP16_BLOCKCOUNT)
+ viFreeIndex = 0;
+ return (VPVOID)((LPBYTE)vpHeap16 + i * HEAP16_BLOCKSIZE);
+ }
+ }
+ else {
+
+ //
+ // Outside the heaphdr range. Reset viFreeIndex, so that
+ // we search from the start of heaphdr.
+ //
+
+ viFreeIndex = -(i+1);
+ }
+ }
+ viFreeIndex = 0;
+ }
+
+ }
+
+ //
+ // Here - if allocation from heap failed
+ //
+
+ vpT = (VPVOID)GlobalAllocLock16(GMEM_MOVEABLE, cb, NULL);
+ if (vpT) {
+ return vpT;
+ }
+ else {
+ LOGDEBUG(0,("malloc16: failed\n"));
+ return (VPVOID)NULL;
+ }
+}
+
+
+
+//*****************************************************************************
+//
+// free16 -
+//
+// frees 16bit memory block.
+// If the block is not part of the 16bit heap, does GlobalFree.
+//
+// Returns TRUE;
+//
+//*****************************************************************************
+
+BOOL FASTCALL free16(VPVOID vp)
+{
+ INT iStartIndex;
+ BOOL fLinked;
+
+ iStartIndex = ((LPBYTE)vp - (LPBYTE)vpHeap16) / HEAP16_BLOCKSIZE;
+
+ //
+ // Invalid iStartIndex implies that the block was GlobalAlloced
+ //
+
+ if (iStartIndex >= 0 && iStartIndex < HEAP16_BLOCKCOUNT) {
+
+ //
+ // If 'single' block: get out fast
+ // else 'multiple' block: loop for all the blocks
+ //
+
+ viFreeIndex = iStartIndex;
+ if (!ISBLOCKLINKED(vahdr[iStartIndex])) {
+ WOW32ASSERT(ISBLOCKINUSE(vahdr[iStartIndex]));
+ vahdr[iStartIndex] = 0;
+ }
+ else {
+ while (ISBLOCKINUSE(vahdr[iStartIndex])) {
+ fLinked = ISBLOCKLINKED(vahdr[iStartIndex]);
+ vahdr[iStartIndex] = 0;
+ if (fLinked)
+ iStartIndex++;
+ else
+ break;
+ }
+ }
+ }
+ else {
+ WOW32ASSERT(LOWORD(vp)==0); // GlobalAlloced pointers have offset = 0
+ GlobalUnlockFree16(vp);
+ }
+ return (BOOL)TRUE;
+}
+
+
+//*****************************************************************************
+//
+// stackalloc16 -
+//
+// Allocs memory from current task's 16bit stack.
+// Returns farpointer to memoryblock;
+//
+//*****************************************************************************
+
+VPVOID FASTCALL stackalloc16(UINT cb)
+{
+ register PTD ptd;
+
+ // get current task's 16bit stack
+
+ ptd = CURRENTPTD();
+
+ // grow ss:sp and return this imaginary pointer.
+
+ if (ptd->dwFlags & TDF_INITCALLBACKSTACK) {
+ ptd->vpCBStack = ptd->vpStack - cb;
+ ptd->dwFlags &= ~TDF_INITCALLBACKSTACK;
+ }
+ else {
+ ptd->vpCBStack -= cb;
+ }
+
+ return (VPVOID)ptd->vpCBStack;
+}
+
diff --git a/private/mvdm/wow32/wcall16.c b/private/mvdm/wow32/wcall16.c
new file mode 100644
index 000000000..c90570007
--- /dev/null
+++ b/private/mvdm/wow32/wcall16.c
@@ -0,0 +1,819 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WCALL16.C
+ * WOW32 16-bit message/callback support
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+ * Changed 18-Aug-1992 by Mike Tricker (MikeTri) Added DOS PDB and SFT functions
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+MODNAME(wcall16.c);
+
+#define WOWFASTEDIT
+
+#ifdef WOWFASTEDIT
+
+typedef struct _LOCALHANDLEENTRY {
+ WORD lhe_address; // actual address of object
+ BYTE lhe_flags; // flags and priority level
+ BYTE lhe_count; // lock count
+} LOCALHANDLEENTRY, *PLOCALHANDLEENTRY;
+
+#define LA_MOVEABLE 0x0002 // moveable or fixed?
+
+#define LHE_DISCARDED 0x0040 // Marks objects that have been discarded.
+
+#endif
+
+/* Common callback functions
+ */
+HANDLE LocalAlloc16(WORD wFlags, INT cb, HANDLE hInstance)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+
+ if (LOWORD(hInstance) == 0 ) { /* if lo word == 0, then this is a 32-bit
+ hInstance, which makes no sense */
+ WOW32ASSERT(LOWORD(hInstance));
+ return (HANDLE)0;
+ }
+
+ if (cb < 0 || cb > 0xFFFF) {
+ WOW32ASSERT(cb > 0 && cb <= 0xFFFF);
+ return (HANDLE)0;
+ }
+
+ Parm16.WndProc.wMsg = LOWORD(hInstance) | 1;
+
+ Parm16.WndProc.wParam = wFlags;
+ Parm16.WndProc.lParam = cb;
+ CallBack16(RET_LOCALALLOC, &Parm16, 0, &vp);
+
+ if (LOWORD(vp) == 0)
+ vp = 0;
+
+ return (HANDLE)vp;
+}
+
+
+HANDLE LocalReAlloc16(HANDLE hMem, INT cb, WORD wFlags)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+
+ if (HIWORD(hMem) == 0 || cb < 0 || cb > 0xFFFF) {
+ WOW32ASSERT(HIWORD(hMem) && cb >= 0 && cb <= 0xFFFF);
+ return (HANDLE)0;
+ }
+
+ LOGDEBUG(4,("LocalRealloc DS = %x, hMem = %x, bytes = %x, flags = %x\n",HIWORD(hMem),LOWORD(hMem),cb,wFlags));
+ Parm16.WndProc.lParam = (LONG)hMem;
+ Parm16.WndProc.wParam = wFlags;
+ Parm16.WndProc.wMsg = (WORD)cb;
+ CallBack16(RET_LOCALREALLOC, &Parm16, 0, &vp);
+
+ if (LOWORD(vp) == 0)
+ vp = 0;
+
+ return (HANDLE)vp;
+}
+
+#ifndef WOWFASTEDIT
+
+VPVOID LocalLock16(HANDLE hMem)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+
+ if (HIWORD(hMem) == 0) {
+ WOW32ASSERT(HIWORD(hMem) != 0);
+ return (VPVOID)0;
+ }
+
+ Parm16.WndProc.lParam = (LONG)hMem;
+ CallBack16(RET_LOCALLOCK, &Parm16, 0, &vp);
+
+ return vp;
+}
+
+BOOL LocalUnlock16(HANDLE hMem)
+{
+ PARM16 Parm16;
+ VPVOID vp = FALSE;
+
+ if (HIWORD(hMem) == 0) {
+ WOW32ASSERT(HIWORD(hMem));
+ return FALSE;
+ }
+
+ Parm16.WndProc.lParam = (LONG)hMem;
+ CallBack16(RET_LOCALUNLOCK, &Parm16, 0, &vp);
+
+ return (BOOL)vp;
+}
+
+#else
+
+VPVOID LocalLock16(HANDLE hMem)
+{
+ WORD h16;
+ LONG retval;
+
+ if (HIWORD(hMem) == 0) {
+ WOW32ASSERT(HIWORD(hMem) != 0);
+ return (VPVOID)0;
+ }
+
+ h16 = LOWORD(hMem);
+ retval = (VPVOID)hMem;
+
+ if (h16 & LA_MOVEABLE) {
+ PLOCALHANDLEENTRY plhe;
+
+ GETVDMPTR(hMem, sizeof(*plhe), plhe);
+
+ if (plhe->lhe_flags & LHE_DISCARDED) {
+ goto LOCK1;
+ }
+
+ plhe->lhe_count++;
+ if (!plhe->lhe_count)
+ plhe->lhe_count--;
+
+LOCK1:
+ LOW(retval) = plhe->lhe_address;
+ FLUSHVDMPTR((ULONG)hMem, sizeof(*plhe), plhe);
+ FREEVDMPTR(plhe);
+ }
+
+ if (LOWORD(retval) == 0)
+ retval = 0;
+
+ return retval;
+}
+
+BOOL LocalUnlock16(HANDLE hMem)
+{
+ WORD h16;
+ BOOL rc;
+ PLOCALHANDLEENTRY plhe;
+ BYTE count;
+
+ if (HIWORD(hMem) == 0) {
+ WOW32ASSERT(HIWORD(hMem));
+ return FALSE;
+ }
+
+ rc = FALSE;
+ h16 = LOWORD(hMem);
+
+ if (!(h16 & LA_MOVEABLE)) {
+ goto UNLOCK2;
+ }
+
+ GETVDMPTR(hMem, sizeof(*plhe), plhe);
+
+ if (plhe->lhe_flags & LHE_DISCARDED)
+ goto UNLOCK1;
+
+ count = plhe->lhe_count;
+ count--;
+
+ if (count >= (BYTE)(0xff-1))
+ goto UNLOCK1;
+
+ plhe->lhe_count = count;
+ rc = (BOOL)((SHORT)count);
+
+ FLUSHVDMPTR((ULONG)hMem, sizeof(*plhe), plhe);
+
+UNLOCK1:
+ FREEVDMPTR(plhe);
+
+UNLOCK2:
+ return rc;
+}
+
+#endif // WOWFASTEDIT
+
+
+WORD LocalSize16(HANDLE hMem)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+
+ if (HIWORD(hMem) == 0) {
+ WOW32ASSERT(HIWORD(hMem));
+ return FALSE;
+ }
+
+ Parm16.WndProc.lParam = (LONG)hMem;
+ CallBack16(RET_LOCALSIZE, &Parm16, 0, &vp);
+
+ return (WORD)vp;
+}
+
+
+HANDLE LocalFree16(HANDLE hMem)
+{
+ PARM16 Parm16;
+ VPVOID vp = FALSE;
+
+ if (HIWORD(hMem) == 0) {
+ WOW32ASSERT(HIWORD(hMem));
+ return (HANDLE)0;
+ }
+
+ Parm16.WndProc.lParam = (LONG)hMem;
+ CallBack16(RET_LOCALFREE, &Parm16, 0, &vp);
+
+ if (LOWORD(vp) == 0) {
+ vp = 0;
+ } else {
+ WOW32ASSERT(LOWORD(vp) == LOWORD(hMem));
+ vp = (VPVOID)hMem;
+ }
+
+ return (HANDLE)vp;
+}
+
+
+BOOL LockSegment16(WORD wSeg)
+{
+ PARM16 Parm16;
+ VPVOID vp = FALSE;
+
+ Parm16.WndProc.wParam = wSeg;
+ CallBack16(RET_LOCKSEGMENT, &Parm16, 0, &vp);
+
+ return (BOOL)vp;
+}
+
+
+BOOL UnlockSegment16(WORD wSeg)
+{
+ PARM16 Parm16;
+ VPVOID vp = FALSE;
+
+ Parm16.WndProc.wParam = wSeg;
+ CallBack16(RET_UNLOCKSEGMENT, &Parm16, 0, &vp);
+
+ return (BOOL)vp;
+}
+
+
+VPVOID WOWGlobalAllocLock16(WORD wFlags, DWORD cb, HMEM16 *phMem)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+
+ Parm16.WndProc.wParam = wFlags;
+ Parm16.WndProc.lParam = cb;
+ CallBack16(RET_GLOBALALLOCLOCK, &Parm16, 0, &vp);
+
+ if (vp) {
+
+ // Get handle of 16-bit object
+ if (phMem) {
+ PCBVDMFRAME pCBFrame;
+
+ pCBFrame = CBFRAMEPTR(CURRENTPTD()->vpCBStack);
+ *phMem = pCBFrame->wGenUse1;
+ FREEVDMPTR(pCBFrame);
+ }
+ }
+ return vp;
+}
+
+
+HMEM16 WOWGlobalAlloc16(WORD wFlags, DWORD cb)
+{
+ HMEM16 hMem;
+ VPVOID vp;
+
+ if (vp = WOWGlobalAllocLock16(wFlags, cb, &hMem)) {
+ WOWGlobalUnlock16(hMem);
+ } else {
+ hMem = 0;
+ }
+
+ return hMem;
+}
+
+
+VPVOID WOWGlobalLockSize16(HMEM16 hMem, PDWORD pcb)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+ PCBVDMFRAME pCBFrame;
+
+ Parm16.WndProc.wParam = hMem;
+ CallBack16(RET_GLOBALLOCK, &Parm16, 0, &vp);
+
+ // Get size of 16-bit object (will be 0 if lock failed)
+ if (pcb) {
+ pCBFrame = CBFRAMEPTR(CURRENTPTD()->vpCBStack);
+ *pcb = pCBFrame->wGenUse2 | (LONG)pCBFrame->wGenUse1 << 16;
+ FREEVDMPTR(pCBFrame);
+ }
+
+ return vp;
+}
+
+
+VPVOID WOWGlobalLock16(HMEM16 hMem)
+{
+ return WOWGlobalLockSize16(hMem, NULL);
+}
+
+
+BOOL WOWGlobalUnlock16(HMEM16 hMem)
+{
+ PARM16 Parm16;
+ VPVOID vp = FALSE;
+
+ Parm16.WndProc.wParam = hMem;
+ CallBack16(RET_GLOBALUNLOCK, &Parm16, 0, &vp);
+
+ return (BOOL)vp;
+}
+
+
+HMEM16 WOWGlobalUnlockFree16(VPVOID vpMem)
+{
+ PARM16 Parm16;
+ VPVOID vp = FALSE;
+
+ Parm16.WndProc.lParam = vpMem;
+ CallBack16(RET_GLOBALUNLOCKFREE, &Parm16, 0, &vp);
+
+ return (HMEM16)vp;
+}
+
+
+HMEM16 WOWGlobalFree16(HMEM16 hMem)
+{
+ VPVOID vp;
+
+ if (vp = WOWGlobalLock16(hMem)) {
+ hMem = WOWGlobalUnlockFree16(vp);
+ } else {
+ // On failure we return the passed-in handle,
+ // so there's nothing to do.
+ }
+
+ return hMem;
+}
+
+
+HAND16 GetExePtr16( HAND16 hInst )
+{
+ PARM16 Parm16;
+ ULONG ul;
+ PTD ptd;
+ INT i;
+
+ if (hInst == 0) return (HAND16)0;
+
+ //
+ // see if this is the hInst for the current task
+ //
+
+ ptd = CURRENTPTD();
+
+ if (hInst == ptd->hInst16) {
+ return ptd->hMod16;
+ }
+
+ //
+ // check the cache
+ //
+
+ for (i = 0; i < CHMODCACHE; i++) {
+ if (ghModCache[i].hInst16 == hInst)
+ return ghModCache[i].hMod16;
+ }
+
+ /*
+ ** Function returns a hModule, given an hInstance
+ */
+ Parm16.WndProc.wParam = hInst;
+ CallBack16(RET_GETEXEPTR, &Parm16, 0, &ul);
+
+
+ //
+ // update the cache
+ // slide everybody down 1 entry, put this new guy at the top
+ //
+
+ RtlMoveMemory(ghModCache+1, ghModCache, sizeof(HMODCACHE)*(CHMODCACHE-1));
+ ghModCache[0].hInst16 = hInst;
+ ghModCache[0].hMod16 = (HAND16)LOWORD(ul);
+
+ return (HAND16)LOWORD(ul);
+}
+
+
+WORD GetModuleFileName16( HAND16 hInst, VPVOID lpszModuleName, WORD cchModuleName )
+{
+ PARM16 Parm16;
+ ULONG ul;
+
+
+ if (hInst == 0) return 0;
+
+ Parm16.WndProc.wParam = hInst;
+ Parm16.WndProc.lParam = lpszModuleName;
+ Parm16.WndProc.wMsg = cchModuleName;
+ CallBack16(RET_GETMODULEFILENAME, &Parm16, 0, &ul );
+
+ return( LOWORD(ul) );
+}
+
+
+ULONG GetDosPDB16(VOID)
+{
+ PARM16 Parm16;
+ DWORD dwReturn = 0;
+
+ CallBack16(RET_GETDOSPDB, &Parm16, 0, &dwReturn);
+
+ return (ULONG)dwReturn;
+}
+
+
+ULONG GetDosSFT16(VOID)
+{
+ PARM16 Parm16;
+ DWORD dwReturn = 0;
+
+ CallBack16(RET_GETDOSSFT, &Parm16, 0, &dwReturn);
+
+ return (ULONG)dwReturn;
+}
+
+// Given a data selector change it into a code selector
+
+WORD ChangeSelector16(WORD wSeg)
+{
+ PARM16 Parm16;
+ VPVOID vp = FALSE;
+
+ Parm16.WndProc.wParam = wSeg;
+ CallBack16(RET_CHANGESELECTOR, &Parm16, 0, &vp);
+
+ return LOWORD(vp);
+}
+
+VPVOID RealLockResource16(HMEM16 hMem, PINT pcb)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+ PCBVDMFRAME pCBFrame;
+
+ Parm16.WndProc.wParam = hMem;
+ CallBack16(RET_LOCKRESOURCE, &Parm16, 0, &vp);
+
+ // Get size of 16-bit object (will be 0 if lock failed)
+ if (pcb) {
+ pCBFrame = CBFRAMEPTR(CURRENTPTD()->vpCBStack);
+ *pcb = pCBFrame->wGenUse2 | (LONG)pCBFrame->wGenUse1 << 16;
+ FREEVDMPTR(pCBFrame);
+ }
+
+ return vp;
+}
+
+
+DWORD WOWCallback16(DWORD vpFn, DWORD dwParam)
+{
+ PARM16 Parm16;
+ VPVOID vp;
+
+ //
+ // Copy DWORD parameter to PARM16 structure.
+ //
+
+ RtlCopyMemory(&Parm16.WOWCallback16.wArgs, &dwParam, sizeof(dwParam));
+
+ //
+ // Use semi-slimy method to pass argument size to CallBack16.
+ //
+
+ vp = (VPVOID) sizeof(dwParam);
+
+ CallBack16(RET_WOWCALLBACK16, &Parm16, (VPPROC)vpFn, &vp);
+
+ return (DWORD)vp;
+}
+
+
+BOOL WOWCallback16Ex(
+ DWORD vpFn,
+ DWORD dwFlags,
+ DWORD cbArgs,
+ PVOID pArgs,
+ PDWORD pdwRetCode
+ )
+{
+#ifdef DEBUG
+ static BOOL fFirstTime = TRUE;
+
+ if (fFirstTime) {
+
+ //
+ // Ensure that wownt32.h's definition of WCB16_MAX_CBARGS
+ // matches wow.h's definition of PARMWCB16.
+ //
+
+ WOW32ASSERT( WCB16_MAX_CBARGS == sizeof(PARMWCB16) );
+
+ //
+ // If the PARMWCB16 structure is smaller than the PARM16
+ // union, we should increase the size of PARMWCB16 and
+ // WCB16_MAX_CBARG to allow the use of the extra bytes.
+ //
+
+ WOW32ASSERT( sizeof(PARMWCB16) == sizeof(PARM16) );
+
+ fFirstTime = FALSE;
+ }
+#endif // DEBUG
+
+ if (cbArgs > sizeof(PARM16)) {
+ LOGDEBUG(LOG_ALWAYS, ("WOWCallback16V: cbArgs = %u, must be <= %u",
+ cbArgs, (unsigned) sizeof(PARM16)));
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ //
+ // For cdecl functions we don't want to "sub SP, cbArgs" after calling
+ // the function, so we pass 0 as cbArgs to the 16-bit side.
+ //
+
+ if (dwFlags & WCB16_CDECL) {
+ cbArgs = 0;
+ }
+
+ //
+ // Use semi-slimy method to pass argument size to CallBack16.
+ //
+
+ *pdwRetCode = cbArgs;
+
+ CallBack16(RET_WOWCALLBACK16, (PPARM16)pArgs, (VPPROC)vpFn, (PVPVOID)pdwRetCode);
+
+ return TRUE;
+}
+
+
+BOOL CallBack16(INT iRetID, PPARM16 pParm16, VPPROC vpfnProc, PVPVOID pvpReturn)
+{
+#ifdef DEBUG
+ static PSZ apszCallBacks[] = {
+ "ERROR:RETURN", // RET_RETURN (not a callback!)
+ "ERROR:DEBUGRETURN", // RET_DEBUGRETURN (not a callback!)
+ "DEBUG", // RET_DEBUG
+ "WNDPROC", // RET_WNDPROC
+ "ENUMFONTPROC", // RET_ENUMFONTPROC
+ "ENUMWINDOWPROC", // RET_ENUMWINDOWPROC
+ "LOCALALLOC", // RET_LOCALALLOC
+ "LOCALREALLOC", // RET_LOCALREALLOC
+ "LOCALLOCK", // RET_LOCALLOCK
+ "LOCALUNLOCK", // RET_LOCALUNLOCK
+ "LOCALSIZE", // RET_LOCALSIZE
+ "LOCALFREE", // RET_LOCALFREE
+ "GLOBALALLOCLOCK", // RET_GLOBALALLOCLOCK
+ "GLOBALLOCK", // RET_GLOBALLOCK
+ "GLOBALUNLOCK", // RET_GLOBALUNLOCK
+ "GLOBALUNLOCKFREE", // RET_GLOBALUNLOCKFREE
+ "FINDRESOURCE", // RET_FINDRESOURCE
+ "LOADRESOURCE", // RET_LOADRESOURCE
+ "FREERESOURCE", // RET_FREERESOURCE
+ "LOCKRESOURCE", // RET_LOCKRESOURCE
+ "UNLOCKRESOURCE", // RET_UNLOCKRESOURCE
+ "SIZEOFRESOURCE", // RET_SIZEOFRESOURCE
+ "LOCKSEGMENT", // RET_LOCKSEGMENT
+ "UNLOCKSEGMENT", // RET_UNLOCKSEGMENT
+ "ENUMMETAFILEPROC", // RET_ENUMMETAFILEPROC
+ "TASKSTARTED ", // RET_TASKSTARTED
+ "HOOKPROC", // RET_HOOKPROC
+ "SUBCLASSPROC", // RET_SUBCLASSPROC
+ "LINEDDAPROC", // RET_LINEDDAPROC
+ "GRAYSTRINGPROC", // RET_GRAYSTRINGPROC
+ "FORCETASKEXIT", // RET_FORCETASKEXIT
+ "SETCURDIR", // RET_SETCURDIR
+ "ENUMOBJPROC", // RET_ENUMOBJPROC
+ "SETCURSORICONFLAG", // RET_SETCURSORICONFLAG
+ "SETABORTPROC", // RET_SETABORTPROC
+ "ENUMPROPSPROC", // RET_ENUMPROPSPROC
+ "FORCESEGMENTFAULT", // RET_FORCESEGMENTFAULT
+ "UNUSEDFUNC", //
+ "UNUSEDFUNC", //
+ "UNUSEDFUNC", //
+ "UNUSEDFUNC", //
+ "UNUSEDFUNC", //
+ "GETEXEPTR", // RET_GETEXEPTR
+ "UNUSEDFUNC", //
+ "FORCETASKFAULT", // RET_FORCETASKFAULT
+ "GETEXPWINVER", // RET_GETEXPWINVER
+ "GETCURDIR", // RET_GETCURDIR
+ "GETDOSPDB", // RET_GETDOSPDB
+ "GETDOSSFT", // RET_GETDOSSFT
+ "FOREGROUNDIDLE", // RET_FOREGROUNDIDLE
+ "WINSOCKBLOCKHOOK", // RET_WINSOCKBLOCKHOOK
+ "WOWDDEFREEHANDLE", // RET_WOWDDEFREEHANDLE
+ "CHANGESELECTOR", // RET_CHANGESELECTOR
+ "GETMODULEFILENAME", // RET_GETMODULEFILENAME
+ "WORDBREAKPROC", // RET_WORDBREAKPROC
+ "WINEXEC", // RET_WINEXEC
+ "WOWCALLBACK16", // RET_WOWCALLBACK16
+ "GETDIBSIZE", // RET_GETDIBSIZE
+ "GETDIBFLAGS", // RET_GETDIBFLAGS
+ "SETDIBSEL", // RET_SETDIBSEL
+ "FREEDIBSEL" // RET_FREEDIBSEL
+ };
+#endif
+ register PTD ptd;
+ register PVDMFRAME pFrame;
+ register PCBVDMFRAME pCBFrame;
+ WORD wAX;
+#if FASTBOPPING
+#else
+ USHORT SaveIp;
+#endif
+#ifdef DEBUG
+ VPVOID vpStackT, vpCBStackT;
+#endif
+
+
+ WOW32ASSERT(iRetID != RET_RETURN && iRetID != RET_DEBUGRETURN);
+
+ ptd = CURRENTPTD();
+
+ GETFRAMEPTR(ptd->vpStack, pFrame);
+
+ // Just making sure that this thread matches the current 16-bit task
+
+ WOW32ASSERT((pFrame->wTDB == ptd->htask16) ||
+ (ptd->dwFlags & TDF_IGNOREINPUT) ||
+ (ptd->htask16 == 0));
+
+ // Prep the frame for the callback
+ // make it word aligned.
+
+ if (ptd->dwFlags & TDF_INITCALLBACKSTACK) {
+ ptd->vpCBStack = (ptd->vpStack - sizeof(CBVDMFRAME)) & (~0x1);
+ }
+ else {
+ ptd->dwFlags |= TDF_INITCALLBACKSTACK;
+ ptd->vpCBStack = (ptd->vpCBStack - sizeof(CBVDMFRAME)) & (~0x1);
+ }
+ GETFRAMEPTR(ptd->vpCBStack, (PVDMFRAME)pCBFrame);
+ pCBFrame->vpStack = ptd->vpStack;
+ pCBFrame->wRetID = (WORD)iRetID;
+ pCBFrame->wTDB = pFrame->wTDB;
+ pCBFrame->wLocalBP = pFrame->wLocalBP;
+
+#ifdef DEBUG
+ // Save
+
+ vpStackT = ptd->vpStack;
+ vpCBStackT = ptd->vpCBStack;
+#endif
+
+ if (pParm16)
+ RtlCopyMemory(&pCBFrame->Parm16, pParm16, sizeof(PARM16));
+
+ //if (vpfnProc) // cheaper to just do it
+ STOREDWORD(pCBFrame->vpfnProc, vpfnProc);
+
+ wAX = HIWORD(ptd->vpStack); // Put SS in AX register for callback
+
+ if ( iRetID == RET_WNDPROC ) {
+ if ( pParm16->WndProc.hInst )
+ wAX = pParm16->WndProc.hInst | 1;
+ }
+
+ pCBFrame->wAX = wAX; // Use this AX for the callback
+
+ //
+ // Semi-slimy way we pass byte count of arguments into this function
+ // for generic callbacks (WOWCallback16).
+ //
+
+ if (RET_WOWCALLBACK16 == iRetID) {
+ pCBFrame->wGenUse1 = (WORD)(DWORD)*pvpReturn;
+ }
+
+#ifdef DEBUG
+ if (iRetID == RET_WNDPROC) {
+ LOGDEBUG(9,("%04X Calling WIN16 WNDPROC(%08lx:%04x,%04x,%04x,%04x,%04x)\n",
+ pFrame->wTDB,
+ vpfnProc,
+ pParm16->WndProc.hwnd,
+ pParm16->WndProc.wMsg,
+ pParm16->WndProc.wParam,
+ HIWORD(pParm16->WndProc.lParam),
+ LOWORD(pParm16->WndProc.lParam)
+ )
+ );
+
+ } else if (iRetID == RET_HOOKPROC) {
+ LOGDEBUG(9,("%04X Calling WIN16 HOOKPROC(%08lx: %04x,%04x,%04x,%04x)\n",
+ pFrame->wTDB,
+ vpfnProc,
+ pParm16->HookProc.nCode,
+ pParm16->HookProc.wParam,
+ HIWORD(pParm16->HookProc.lParam),
+ LOWORD(pParm16->HookProc.lParam)
+ )
+ );
+
+
+ } else {
+ LOGDEBUG(9,("%04X Calling WIN16 %s(%04x,%04x,%04x)\n",
+ pFrame->wTDB,
+ apszCallBacks[iRetID],
+ pParm16->WndProc.wParam,
+ HIWORD(pParm16->WndProc.lParam),
+ LOWORD(pParm16->WndProc.lParam)
+ )
+ );
+ }
+#endif
+
+ FREEVDMPTR(pFrame);
+ FLUSHVDMPTR(ptd->vpCBStack, sizeof(CBVDMFRAME), pCBFrame);
+ FREEVDMPTR(pCBFrame);
+
+ // Set up to use the right 16-bit stack for this thread
+
+#if FASTBOPPING
+ SETFASTVDMSTACK(ptd->vpCBStack);
+#else
+ SETVDMSTACK(ptd->vpCBStack);
+#endif
+
+ //
+ // do the callback!
+ //
+
+#if FASTBOPPING
+ CurrentMonitorTeb = NtCurrentTeb();
+ FastWOWCallbackCall();
+ // fastbop code refreshes ptd->vpStack
+#else
+ // Time to get the IEU running task-time code again
+ SaveIp = getIP();
+ host_simulate();
+ setIP(SaveIp);
+ ptd->vpStack = VDMSTACK();
+#endif
+
+ // after return from callback ptd->vpStack will point to PCBVDMFRAME
+
+ // consistency check
+ WOW32ASSERT(ptd->vpStack == vpCBStackT);
+
+ ptd->vpCBStack = ptd->vpStack;
+ GETFRAMEPTR(ptd->vpCBStack, (PVDMFRAME)pCBFrame);
+
+ // Just making sure that this thread matches the current 16-bit task
+
+ WOW32ASSERT((pCBFrame->wTDB == ptd->htask16) ||
+ (ptd->htask16 == 0));
+
+ if (pvpReturn) {
+ LOW(*pvpReturn) = pCBFrame->wAX;
+ HIW(*pvpReturn) = pCBFrame->wDX;
+ }
+
+ LOGDEBUG(9,("%04X WIN16 %s returning: %lx\n",
+ pCBFrame->wTDB, apszCallBacks[iRetID], (pvpReturn) ? *pvpReturn : 0));
+
+ // restore the stack to its original value.
+ // ie. fake the 'pop' of callback stack by resetting the vpStack
+ // to its original value. The ss:sp will actually be updated when
+ // the 'api thunk' returns.
+
+ // consistency check
+ WOW32ASSERT(pCBFrame->vpStack == vpStackT);
+
+ ptd->vpStack = pCBFrame->vpStack;
+
+ FREEVDMPTR(pCBFrame);
+
+ return TRUE;
+}
diff --git a/private/mvdm/wow32/wcall16.h b/private/mvdm/wow32/wcall16.h
new file mode 100644
index 000000000..dc49ab183
--- /dev/null
+++ b/private/mvdm/wow32/wcall16.h
@@ -0,0 +1,50 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WCALL16.H
+ * WOW32 16-bit message/callback support
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+ * Changed 18-Aug-1992 by Mike Tricker (MikeTri) Added DOS PDB and SFT prototypes
+--*/
+
+
+/* Function prototypes
+ */
+HANDLE LocalAlloc16(WORD wFlags, INT cb, HANDLE hInstance);
+HANDLE LocalReAlloc16(HANDLE hMem, INT cb, WORD wFlags);
+VPVOID LocalLock16(HANDLE hMem);
+BOOL LocalUnlock16(HANDLE hMem);
+WORD LocalSize16(HANDLE hMem);
+HANDLE LocalFree16(HANDLE hMem);
+BOOL LockSegment16(WORD wSeg);
+BOOL UnlockSegment16(WORD wSeg);
+HAND16 GetExePtr16( HAND16 hInstance );
+WORD ChangeSelector16( WORD wSeg );
+VPVOID RealLockResource16( HMEM16 hMem, PINT pcb );
+WORD GetModuleFileName16( HAND16 hInst, VPVOID lpszModuleName, WORD cchModuleName );
+
+BOOL CallBack16(INT iRetID, PPARM16 pParms, VPPROC vpfnProc, PVPVOID pvpReturn);
+
+
+VPVOID FASTCALL malloc16(UINT cb);
+BOOL FASTCALL free16(VPVOID vp);
+VPVOID FASTCALL stackalloc16(UINT cb);
+#define stackfree16(vp)
+
+ULONG GetDosPDB16(VOID);
+ULONG GetDosSFT16(VOID);
+
+/* Function prototypes for 16-bit Global memory functions are now in
+ * \nt\public\sdk\inc\winntwow.h with slightly different names. The
+ * old names are supported by the following defines:
+ */
+
+#define GlobalAllocLock16 WOWGlobalAllocLock16
+#define GlobalLock16 WOWGlobalLockSize16
+#define GlobalUnlock16 WOWGlobalUnlock16
+#define GlobalUnlockFree16 WOWGlobalUnlockFree16
diff --git a/private/mvdm/wow32/wcall32.c b/private/mvdm/wow32/wcall32.c
new file mode 100644
index 000000000..4f9799a52
--- /dev/null
+++ b/private/mvdm/wow32/wcall32.c
@@ -0,0 +1,352 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WCALL32.C
+ * WOW32 16-bit resource support
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wcall32.c);
+
+//
+// the 16-bit local handles are treated as 32-bit quantities.
+// the low word contains the 16-bit handle and the high word
+// contains the data segment for the block.
+// when we do a callback to WOW16LocalAlloc it will
+// return the DS in the high word (which is normally unused).
+// on subsequent callbacks to realloc/lock/unlock/size/free
+// the 16-bit code sets the DS to this value.
+//
+
+
+HANDLE APIENTRY W32LocalAlloc(UINT dwFlags, UINT dwBytes, HANDLE hInstance)
+{
+
+ //
+ // If hInstance is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if (LOWORD (hInstance) == 0) {
+ return (LocalAlloc(dwFlags, dwBytes));
+ }
+
+
+#if !defined(i386)
+ if (dwBytes != 0)
+ dwBytes += 4;
+#endif
+
+ return LocalAlloc16((WORD)dwFlags, (INT)dwBytes, hInstance);
+}
+
+// This api takes an extra pointer which is optional
+// In case of an edit control reallocating the memory inside apps memory
+// space it is used to update the thunk data (see wparam.c)
+
+HANDLE APIENTRY W32LocalReAlloc(
+ HANDLE hMem, // memory to be reallocated
+ UINT dwBytes, // size to reallocate to
+ UINT dwFlags, // reallocation flags
+ HANDLE hInstance, // Instance to identify ptr
+ PVOID* ppv) // Pointer to the pointer that needs an update
+{
+ //
+ // If hInstance is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if (LOWORD (hInstance) == 0) {
+ return (LocalReAlloc(hMem, dwBytes, dwFlags));
+ }
+
+
+
+#if !defined(i386)
+ if (dwBytes != 0)
+ dwBytes += 4;
+#endif
+
+ hMem = LocalReAlloc16(hMem, (INT)dwBytes, (WORD)dwFlags);
+
+ // this code is used in User/Client (edit control) to realloc
+ // memory for text storage
+ // update what ppv points to using wparam.c
+
+ if (NULL != ppv && NULL != *ppv) {
+ *ppv = ParamMapUpdateNode((DWORD)*ppv, PARAM_32, NULL);
+ }
+
+ return hMem;
+}
+
+LPSTR APIENTRY W32LocalLock(HANDLE hMem, HANDLE hInstance)
+{
+ VPVOID vp;
+
+ //
+ // If hInstance is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if (LOWORD (hInstance) == 0) {
+ return (LocalLock(hMem));
+ }
+
+ if (vp = LocalLock16(hMem)) {
+ return (LPSTR)VDMPTR(vp, 0);
+ }
+ else
+ return NULL;
+}
+
+
+
+
+BOOL APIENTRY W32LocalUnlock(HANDLE hMem, HANDLE hInstance)
+{
+
+ //
+ // If hInstance is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if (LOWORD (hInstance) == 0) {
+ return (LocalUnlock(hMem));
+ }
+
+
+ return LocalUnlock16(hMem);
+}
+
+
+DWORD APIENTRY W32LocalSize(HANDLE hMem, HANDLE hInstance)
+{
+ DWORD dwSize;
+
+
+
+ //
+ // If hInstance is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if (LOWORD (hInstance) == 0) {
+ return (LocalSize(hMem));
+ }
+
+
+
+ dwSize = LocalSize16(hMem);
+
+#if !defined(i386)
+ if (dwSize >= 4)
+ dwSize -= 4;
+#endif
+
+ return dwSize;
+}
+
+
+HANDLE APIENTRY W32LocalFree(HANDLE hMem, HANDLE hInstance)
+{
+
+ //
+ // If hInstance is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if (LOWORD (hInstance) == 0) {
+ return (LocalFree(hMem));
+ }
+
+ return LocalFree16(hMem);
+}
+
+ULONG APIENTRY W32GetExpWinVer(HANDLE hInst)
+{
+ PARM16 Parm16;
+ ULONG ul;
+
+ // makes a direct call to krnl286:GetExpWinVer
+ //
+
+ if (LOWORD((DWORD)hInst) == (WORD) NULL) {
+
+ //
+ // Window is created by a 32 bit DLL, which is
+ // linked to NTVDM process. So, we should not
+ // passs it to the 16 bit kernel.
+ //
+
+ return (WOWRtlGetExpWinVer(hInst));
+ }
+ else {
+ LPBYTE lpNewExeHdr;
+ VPVOID vp = (DWORD)hInst & 0xffff0000;
+
+ GETMISCPTR(vp, lpNewExeHdr);
+ if (lpNewExeHdr) {
+ ul = MAKELONG(*(PWORD16)&lpNewExeHdr[NE_LOWINVER_OFFSET],
+ (*(PWORD16)&lpNewExeHdr[NE_HIWINVER_OFFSET] &
+ FLAG_NE_PROPFONT));
+ }
+ else {
+ Parm16.WndProc.wParam = LOWORD(hInst);
+ CallBack16(RET_GETEXPWINVER, &Parm16, 0, &ul );
+ }
+ return ul;
+ }
+
+
+}
+
+
+/*
+ * VOID W32InitDlg(HWND hDlg, LONG lParam);
+ *
+ * this function is called by USER during dialog creation
+ * before any messages are sent.
+ */
+
+DWORD APIENTRY W32InitDlg(HWND hDlg, LONG lParam)
+{
+ register PWW pww;
+
+ if (!lParam) {
+ LOGDEBUG(2,(" Warning: W32InitDlg called with null lParam\n"));
+ return (DWORD)0;
+ }
+
+ // FindPWW was here
+
+ if (!(pww = (PWW) GetWindowLong(hDlg, GWL_WOWWORDS))) {
+ LOGDEBUG(0,(" W32InitDlg ERROR: cannot create alias for window %08lx\n", hDlg));
+ WOW32ASSERT(pww);
+ return (DWORD)0;
+ }
+
+ // the reason we need the hmap.vpfnDlgProc field is because some
+ // dialogs have both a window proc and a dialog proc. this happens
+ // when the dialog template has a class in it and the app also
+ // passes a dialog proc to CreateDialogxxx()
+ //
+
+ SETWL(hDlg, GWL_WOWiClassAndflState,
+ MAKECLASSANDSTATE(WOWCLASS_DIALOG, WWSTATE_ICLASSISSET));
+ SETWL(hDlg, GWL_WOWvpfnDlgProc, ((PDLGDATA)lParam)->vpfnDlgProc);
+
+ return ((PDLGDATA)lParam)->dwUserInitParam;
+}
+
+
+WORD APIENTRY W32GlobalAlloc16(UINT uFlags, DWORD dwBytes)
+{
+ return HIWORD(GlobalAllocLock16((WORD)uFlags, dwBytes, NULL));
+}
+
+
+VOID APIENTRY W32GlobalFree16(WORD selector)
+{
+ GlobalUnlockFree16(MAKELONG(0, selector));
+ return;
+}
+
+
+
+int APIENTRY W32EditNextWord (LPSZ lpszEditText, int ichCurrentWord,
+ int cbEditText, int action, DWORD dwProc16)
+{
+ PARM16 Parm16;
+ ULONG lReturn = 0;
+ PBYTE lpstr16;
+ VPVOID vpstr16;
+ VPVOID vpfn;
+
+ if (vpstr16 = malloc16 (cbEditText)) {
+ GETMISCPTR (vpstr16, lpstr16);
+ if (lpstr16) {
+ lstrcpy (lpstr16, lpszEditText);
+
+ vpfn = dwProc16 & WNDPROC_MASK;
+
+ //
+ // if the actual selector had the high bit on then we turned off
+ // bit 2 of the selector (the LDT bit, which will always be on)
+ //
+
+ if (!(vpfn & WOWCLASS_VIRTUAL_NOT_BIT31)) {
+ vpfn |= (WNDPROC_WOW | WOWCLASS_VIRTUAL_NOT_BIT31);
+ }
+
+ Parm16.WordBreakProc.action = GETINT16(action);
+ Parm16.WordBreakProc.cbEditText = GETINT16(cbEditText);
+ Parm16.WordBreakProc.ichCurrentWord = GETINT16(ichCurrentWord);
+ Parm16.WordBreakProc.lpszEditText = vpstr16;
+
+ CallBack16(RET_SETWORDBREAKPROC, &Parm16, vpfn, (PVPVOID)&lReturn);
+
+ FREEMISCPTR (lpstr16);
+ }
+
+ free16(vpstr16);
+ }
+
+ return (INT32(LOWORD(lReturn)));
+}
+
+
+/***************************************************************************\
+* WOWRtlGetExpWinVer
+*
+* Returns the expected windows version, in the same format as Win3.1's
+* GetExpWinVer(). This takes it out of the module header.
+*
+* 09-9-92 ChandanC Created.
+\***************************************************************************/
+
+DWORD WOWRtlGetExpWinVer(
+ HANDLE hmod)
+{
+ PIMAGE_NT_HEADERS pnthdr;
+ DWORD dwMajor = 3;
+ DWORD dwMinor = 0xA;
+
+ if (hmod != NULL) {
+ try {
+ pnthdr = (PIMAGE_NT_HEADERS)RtlImageNtHeader((PVOID)hmod);
+ dwMajor = pnthdr->OptionalHeader.MajorSubsystemVersion;
+ dwMinor = pnthdr->OptionalHeader.MinorSubsystemVersion;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ dwMajor = 3; // just to be safe
+ dwMinor = 0xA;
+ }
+ }
+
+// !!! HACK until linker is fixed!!! 05-Aug-1992 Bug #3211
+if (((dwMajor == 3) && (dwMinor == 1)) || (dwMajor == 1)) {
+ dwMajor = 0x3;
+ dwMinor = 0xA;
+}
+
+
+ /*
+ * Return this is a win3.1 compatible format:
+ *
+ * 0x030A == win3.1
+ * 0x0300 == win3.0
+ * 0x0200 == win2.0, etc.
+ *
+ */
+
+ return (DWORD)MAKELONG(MAKEWORD((BYTE)dwMinor, (BYTE)dwMajor), 0);
+}
diff --git a/private/mvdm/wow32/wcall32.h b/private/mvdm/wow32/wcall32.h
new file mode 100644
index 000000000..9efa02d71
--- /dev/null
+++ b/private/mvdm/wow32/wcall32.h
@@ -0,0 +1,29 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WCALL32.H
+ * WOW32 16-bit resource support
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+/* Function prototypes
+ */
+HANDLE APIENTRY W32LocalAlloc(UINT dwFlags, UINT dwBytes, HANDLE hInstance);
+HANDLE APIENTRY W32LocalReAlloc(HANDLE hMem, UINT dwBytes, UINT dwFlags, HANDLE hInstance, PVOID* ppv);
+LPSTR APIENTRY W32LocalLock(HANDLE hMem, HANDLE hInstance);
+BOOL APIENTRY W32LocalUnlock(HANDLE hMem, HANDLE hInstance);
+DWORD APIENTRY W32LocalSize(HANDLE hMem, HANDLE hInstance);
+HANDLE APIENTRY W32LocalFree(HANDLE hMem, HANDLE hInstance);
+ULONG APIENTRY W32GetExpWinVer(HANDLE Inst);
+DWORD APIENTRY W32InitDlg(HWND hDlg, LONG lParam);
+WORD APIENTRY W32GlobalAlloc16(UINT uFlags, DWORD dwBytes);
+VOID APIENTRY W32GlobalFree16(WORD selector);
+DWORD WOWRtlGetExpWinVer(HANDLE hmod);
+int APIENTRY W32EditNextWord (LPSZ lpszEditText, int ichCurrentWord,
+ int cbEditText, int action, DWORD dwProc16);
diff --git a/private/mvdm/wow32/wcmdgtbl.h b/private/mvdm/wow32/wcmdgtbl.h
new file mode 100644
index 000000000..857d694e8
--- /dev/null
+++ b/private/mvdm/wow32/wcmdgtbl.h
@@ -0,0 +1,48 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1993, Microsoft Corporation
+ *
+ * WCMDGTBL.h
+ * WOW32 16-bit Commdlg tables
+ *
+ * History:
+ * John Vert (jvert) 31-Dec-1992 - created
+ *
+ * This file is included into the master thunk table.
+ *
+--*/
+
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_COMMDLG, 0)},
+ {W32FUN(WCD32GetOpenFileName, "GETOPENFILENAME", MOD_COMMDLG, sizeof(GETOPENFILENAME16))},
+ {W32FUN(WCD32GetSaveFileName, "GETSAVEFILENAME", MOD_COMMDLG, sizeof(GETSAVEFILENAME16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(WCD32ChooseColor, "CHOOSECOLOR", MOD_COMMDLG, sizeof(CHOOSECOLOR16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+
+ /*** 0010 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(WCD32FindText, "FINDTEXT", MOD_COMMDLG, sizeof(FINDREPLACE16))},
+ {W32FUN(WCD32ReplaceText, "REPLACETEXT", MOD_COMMDLG, sizeof(FINDREPLACE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(WCD32ChooseFont, "CHOOSEFONT", MOD_COMMDLG, sizeof(CHOOSEFONT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+
+ /*** 0020 ***/
+ {W32FUN(WCD32PrintDlg, "PRINTDLG", MOD_COMMDLG, sizeof(PRINTDLG16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_COMMDLG, 0)},
+ {W32FUN(WCD32ExtendedError, "COMMDLGEXTENDEDERROR", MOD_COMMDLG, 0)},
+
diff --git a/private/mvdm/wow32/wcntl32.c b/private/mvdm/wow32/wcntl32.c
new file mode 100644
index 000000000..94951f5b9
--- /dev/null
+++ b/private/mvdm/wow32/wcntl32.c
@@ -0,0 +1,1116 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSG32.C
+ * WOW32 32-bit message thunks
+ *
+ * History:
+ * Created 19-Feb-1992 by Chandan Chauhan (ChandanC)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wcntl32.c);
+
+// This function thunks the button control messages,
+//
+// BM_GETCHECK
+// BM_SETCHECK
+// BM_GETSTATE
+// BM_SETSTATE
+// BM_SETSTYLE
+//
+
+BOOL FASTCALL WM32BMControl(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - BM_GETCHECK));
+ }
+
+ return (TRUE);
+}
+
+
+BOOL FASTCALL WM32BMClick (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WIN31_BM_CLICK);
+ }
+
+ return (TRUE);
+}
+
+
+
+// This function thunks the following edit control messages,
+//
+// EM_GETSEL
+// EM_GETMODIFY
+// EM_SETMODIFY
+// EM_GETLINECOUNT
+// EM_GETLINEINDEX
+// EM_LINELENGTH
+// EM_LIMITTEX
+// EM_CANUNDO
+// EM_UNDO
+// EM_FMTLINES
+// EM_LINEFROMCHAR
+// EM_SETPASSWORDCHAR
+// EM_EMPTYUNDOBUFFER
+
+BOOL FASTCALL WM32EMControl(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the button control messages,
+//
+// EM_SETSEL
+//
+
+BOOL FASTCALL WM32EMSetSel (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) lpwm32mpex->uParam;
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) =
+ (lpwm32mpex->lParam != -1) ? lpwm32mpex->lParam : 32767;
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the edit control messages,
+//
+// EM_GETRECT
+//
+
+BOOL FASTCALL WM32EMGetRect (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ if ( lpwm32mpex->fThunk ) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(sizeof(RECT16));
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ } else {
+ GETRECT16( lpwm32mpex->Parm16.WndProc.lParam, (LPRECT)lpwm32mpex->lParam );
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the edit control messages,
+//
+// EM_SETRECT
+// EM_SETRECTNP
+//
+
+BOOL FASTCALL WM32EMSetRect (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if ( lpwm32mpex->fThunk ) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(sizeof(RECT16));
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ PUTRECT16( lpwm32mpex->Parm16.WndProc.lParam, (LPRECT)lpwm32mpex->lParam );
+ } else {
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the edit control messages,
+//
+// EM_LINESCROLL
+//
+
+BOOL FASTCALL WM32EMLineScroll (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) lpwm32mpex->lParam;
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) lpwm32mpex->uParam;
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the edit control messages,
+//
+// EM_REPLACESEL
+//
+
+BOOL FASTCALL WM32EMReplaceSel (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if ( lpwm32mpex->fThunk ) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+ if (lpwm32mpex->lParam) {
+ INT cb;
+
+ cb = strlen((LPSZ)lpwm32mpex->lParam)+1;
+
+ // winworks2.0a requires DS based string pointers for this message
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_DSBASEDSTRINGPOINTERS) {
+ lpwm32mpex->Parm16.WndProc.lParam = stackalloc16(cb);
+ } else {
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(cb);
+ }
+
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ putstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, cb);
+ }
+ } else {
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_DSBASEDSTRINGPOINTERS) {
+ stackfree16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ } else {
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+
+BOOL FASTCALL WM32EMSetFont (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+ }
+
+ LOGDEBUG(0,(" Window %08lX is receiving Control Message %s(%08x)\n", lpwm32mpex->hwnd, (LPSZ)GetWMMsgName(lpwm32mpex->uMsg), lpwm32mpex->uMsg));
+ return (TRUE);
+}
+
+
+// This function thunks the edit control messages,
+//
+// EM_GETLINE
+//
+
+BOOL FASTCALL WM32EMGetLine (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if ( lpwm32mpex->fThunk ) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+ if (lpwm32mpex->lParam) {
+ INT cb;
+ PBYTE lp;
+
+ // the first WORD is what USER uses.
+
+ cb = *(UNALIGNED WORD *)(lpwm32mpex->lParam);
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(cb);
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ ALLOCVDMPTR(lpwm32mpex->Parm16.WndProc.lParam,2,lp);
+ *((UNALIGNED WORD *)lp) = cb;
+ FLUSHVDMPTR(lpwm32mpex->Parm16.WndProc.lParam,2,lp); /* first 2 bytes modified */
+ }
+ } else {
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ PBYTE lp;
+
+ GETMISCPTR(lpwm32mpex->Parm16.WndProc.lParam,lp);
+ RtlCopyMemory((PBYTE)lpwm32mpex->lParam,lp,lpwm32mpex->lReturn);
+ FREEVDMPTR(lp);
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+
+ LOGDEBUG(3,(" Window %08lX is receiving Control Message %s(%08x)\n", lpwm32mpex->hwnd, (LPSZ)GetWMMsgName(lpwm32mpex->uMsg), lpwm32mpex->uMsg));
+
+ return (TRUE);
+}
+
+
+BOOL FASTCALL WM32EMSetWordBreakProc (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+
+ lpwm32mpex->Parm16.WndProc.lParam = lpwm32mpex->lParam & WNDPROC_MASK;
+
+ //
+ // if the actual selector had the high bit on then we turned off
+ // bit 2 of the selector (the LDT bit, which will always be on)
+ //
+
+ if (!(lpwm32mpex->Parm16.WndProc.lParam & WOWCLASS_VIRTUAL_NOT_BIT31)) {
+ lpwm32mpex->Parm16.WndProc.lParam |= (WNDPROC_WOW | WOWCLASS_VIRTUAL_NOT_BIT31);
+ }
+
+ LOGDEBUG(3,(" Window %08lX is receiving Control Message %s(%08x)\n", lpwm32mpex->hwnd, (LPSZ)GetWMMsgName(lpwm32mpex->uMsg), lpwm32mpex->uMsg));
+ }
+
+ return (TRUE);
+}
+
+
+BOOL FASTCALL WM32EMGetWordBreakProc (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+ LOGDEBUG(3,(" Window %08lX is receiving Control Message %s(%08x)\n", lpwm32mpex->hwnd, (LPSZ)GetWMMsgName(lpwm32mpex->uMsg), lpwm32mpex->uMsg));
+ }
+ else {
+ //
+ // FEATURE-O-RAMA
+ //
+ // if the selector already has the high bit on then turn off bit 2
+ // of the selector (the LDT bit, which should always be on). we
+ // need a way to not blindly strip off the high bit in our wndproc.
+ //
+
+ if (lpwm32mpex->lReturn & WNDPROC_WOW) {
+ WOW32ASSERT(lpwm32mpex->lReturn & WOWCLASS_VIRTUAL_NOT_BIT31);
+ lpwm32mpex->lReturn &= ~WOWCLASS_VIRTUAL_NOT_BIT31;
+ }
+
+ lpwm32mpex->lReturn = lpwm32mpex->lReturn | WNDPROC_WOW;
+ }
+
+
+ return (TRUE);
+}
+
+
+// This function thunks the edit control messages,
+//
+// EM_SETTABSTOPS
+//
+
+BOOL FASTCALL WM32EMSetTabStops (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if ( lpwm32mpex->fThunk ) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - EM_GETSEL));
+ if (lpwm32mpex->uParam != 0) {
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(lpwm32mpex->uParam * sizeof(WORD));
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ putintarray16((VPINT16)lpwm32mpex->Parm16.WndProc.lParam, (INT)lpwm32mpex->uParam, (LPINT)lpwm32mpex->lParam);
+ }
+ } else {
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the following combo box control messages,
+//
+// CB_GETEDITSEL
+// CB_LIMITTEXT
+// CB_SETEDITSEL
+// CB_DELETESTRING
+// CB_GETCOUNT
+// CB_GETCURSEL
+// CB_GETLBTEXTLEN
+// CB_SETCURSEL
+// CB_SHOWDROPDOWN
+// CB_GETITEMDATA
+// CB_SETITEMDATA
+
+
+BOOL FASTCALL WM32CBControl (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - CB_GETEDITSEL));
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the following combo box control messages,
+//
+// CB_ADDSTRING
+// CB_INSERTSTRING
+// CB_FINDSTRING
+// CB_SELECTSTRING
+
+BOOL FASTCALL WM32CBAddString (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ PWW pww;
+
+
+
+
+ if ( lpwm32mpex->fThunk ) {
+ if (!(pww = lpwm32mpex->pww)) {
+ if (pww = FindPWW (lpwm32mpex->hwnd, WOWCLASS_UNKNOWN))
+ lpwm32mpex->pww = pww;
+ else
+ return FALSE;
+ }
+
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - CB_GETEDITSEL));
+
+ //
+ // Determine if this combobox has string pointers or handles passed
+ // in with CB_ADDSTRING messages. Normal comboboxes have string
+ // pointers passed. Owner-draw comboboxes that don't have the
+ // CBS_HASSTRINGS style bit set have handles passed in. These handles
+ // are simply passed back to the owner at paint time. If the
+ // CBS_HASSTRINGS style bit is set, strings are used instead of
+ // handles as the "cookie" which is passed back to the application
+ // at paint time.
+ //
+ // We treat lpwm32mpex->dwParam as a BOOL indicating this combobox
+ // takes handles instead of strings.
+ //
+
+ lpwm32mpex->dwParam =
+ (pww->dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
+ !(pww->dwStyle & CBS_HASSTRINGS);
+
+ if ( !lpwm32mpex->dwParam ) { // if strings are used
+ if (lpwm32mpex->lParam) {
+ INT cb;
+
+ cb = strlen((LPSZ)lpwm32mpex->lParam)+1;
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(cb);
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ putstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, cb);
+ }
+ }
+ } else {
+ if ( !lpwm32mpex->dwParam ) { // if strings are used
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ getstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, -1);
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+ }
+
+ LOGDEBUG(3,(" Window %08lX is receiving Control Message %s(%08x)\n", lpwm32mpex->hwnd, (LPSZ)GetWMMsgName(lpwm32mpex->uMsg), lpwm32mpex->uMsg));
+
+ return(TRUE);
+
+}
+
+
+// This function thunks the following combo box control messages,
+//
+// CB_DIR
+//
+// Code in this routine references code in wparam.c in order to circumvent
+// copying memory to 16-bit memory space.
+// GetParam16 verifies that the parameter we get (lparam) had not originated
+// in 16-bit code. If it did come from 16-bit code, then we send an original
+// 16:16 pointer to the application.
+// This fixes PagePlus 3.0 application and (if implemented on a broader scale)
+// will positively affect performance of applications which send a lot of
+// standard messages and use subclassing a lot.
+// -- VadimB
+
+BOOL FASTCALL WM32CBDir (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - CB_GETEDITSEL));
+ if (lpwm32mpex->lParam) {
+ INT cb;
+
+ if (W32CheckThunkParamFlag()) {
+ LONG lParam = (LONG)GetParam16(lpwm32mpex->lParam);
+ if (lParam) {
+ lpwm32mpex->Parm16.WndProc.lParam = lParam;
+ return (TRUE);
+ }
+ }
+
+ cb = strlen((LPSZ)lpwm32mpex->lParam)+1;
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(cb);
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ putstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, cb);
+ }
+ } else {
+ if (W32CheckThunkParamFlag()) {
+ if (DeleteParamMap(lpwm32mpex->Parm16.WndProc.lParam, PARAM_16, NULL)) {
+ return TRUE;
+ }
+ }
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return(TRUE);
+}
+
+
+// This function thunks the following combo box control messages,
+//
+// CB_GETLBTEXT
+
+BOOL FASTCALL WM32CBGetLBText (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ PWW pww;
+
+
+
+ if ( lpwm32mpex->fThunk ) {
+ INT cb;
+
+ if (!(pww = lpwm32mpex->pww)) {
+ if (pww = FindPWW (lpwm32mpex->hwnd, WOWCLASS_UNKNOWN))
+ lpwm32mpex->pww = pww;
+ else
+ return FALSE;
+ }
+
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - CB_GETEDITSEL));
+
+ //
+ // Determine if this combobox has string pointers or handles passed
+ // in with CB_ADDSTRING messages. Normal comboboxes have string
+ // pointers passed. Owner-draw comboboxes that don't have the
+ // CBS_HASSTRINGS style bit set have handles passed in. These handles
+ // are simply passed back to the owner at paint time. If the
+ // CBS_HASSTRINGS style bit is set, strings are used instead of
+ // handles as the "cookie" which is passed back to the application
+ // at paint time.
+ //
+ // We treat lpwm32mpex->dwParam as a BOOL indicating this combobox
+ // takes handles instead of strings.
+ //
+
+ lpwm32mpex->dwParam =
+ (pww->dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
+ !(pww->dwStyle & CBS_HASSTRINGS);
+
+ //
+ // Determine the size of the buffer to allocate on the 16-bit side
+ // to receive the text.
+ //
+
+ if (lpwm32mpex->dwParam) { // if handles are used
+ cb = 4;
+ } else {
+ cb = SendMessage(lpwm32mpex->hwnd, CB_GETLBTEXTLEN, lpwm32mpex->uParam, 0);
+ if (cb == CB_ERR) {
+ //
+ // lpwm32mpex->dwTmp[0] is initialized to 0 so that nothing
+ // gets copied to the buffer by getstr16() while unthunking
+ // this message.
+ //
+ // bug # 24415, ChandanC
+ //
+
+ cb = SIZE_BOGUS;
+ lpwm32mpex->dwTmp[0] = 0;
+ }
+ else {
+ //
+ // Add one for NULL character.
+ //
+ cb = cb + 1;
+ (INT) lpwm32mpex->dwTmp[0] = (INT) -1;
+ }
+ }
+ if (lpwm32mpex->lParam) {
+ BYTE *lpT;
+
+ // See comment on similar code below
+
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(cb);
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ GETVDMPTR((lpwm32mpex->Parm16.WndProc.lParam), sizeof(BYTE), lpT);
+ *lpT = 0;
+ FREEVDMPTR(lpT);
+ }
+ }
+ else {
+ if (lpwm32mpex->lParam && lpwm32mpex->Parm16.WndProc.lParam) {
+ if (lpwm32mpex->dwParam) { // if handles are used
+ UNALIGNED DWORD *lpT;
+ GETVDMPTR((lpwm32mpex->Parm16.WndProc.lParam), sizeof(DWORD), lpT);
+ *(UNALIGNED DWORD *)lpwm32mpex->lParam = *lpT;
+ FREEVDMPTR(lpT);
+ }
+ else {
+ getstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam,
+ (INT) lpwm32mpex->dwTmp[0]);
+ }
+
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+
+ }
+ }
+
+ return(TRUE);
+}
+
+
+// This function thunks the following combo box control messages,
+//
+// CB_GETDROPPEDCONTROLRECT
+
+BOOL FASTCALL WM32CBGetDropDownControlRect (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if ( lpwm32mpex->fThunk ) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - CB_GETEDITSEL));
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(sizeof(RECT16));
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ } else {
+ GETRECT16( lpwm32mpex->Parm16.WndProc.lParam, (LPRECT)lpwm32mpex->lParam );
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return(TRUE);
+}
+
+
+// This function thunks the following combo box control messages,
+//
+// CBEC_SETCOMBOFOCUS (WM_USER+CB_MSGMAX+1)
+// CBEC_KILLCOMBOFOCUS (WM_USER+CB_MSGMAX+2)
+// These undocumented messages are used by Excel 5.0
+//
+
+BOOL FASTCALL WM32CBComboFocus (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg =
+ (WORD)((lpwm32mpex->uMsg-CBEC_SETCOMBOFOCUS) + OLDCBEC_SETCOMBOFOCUS);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the list box control messages
+//
+// LB_RESETCONTENT
+// LB_SETCURSEL
+// LB_GETSEL
+// LB_GETCURSEL
+// LB_GETTEXTLEN
+// LB_GETCOUNT
+// LB_GETCARETINDEX
+// LB_GETTOPINDEX
+// LB_GETSELCOUNT
+// LB_GETHORIZONTALEXTENT
+// LB_SETHORIZONTALEXTENT
+// LB_SETCOLUMNWIDTH
+// LB_SETTOPINDEX
+// LB_SETCARETINDEX
+// LB_SETITEMDATA
+// LB_SELITEMRANGE
+// LB_SETITEMHEIGHT
+// LB_GETITEMHEIGHT
+// LB_DELETESTRING
+//
+
+BOOL FASTCALL WM32LBControl (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - LB_ADDSTRING + 1));
+ }
+
+ return (TRUE);
+}
+
+// This function thunks the list box control messages
+//
+// LB_GETTEXT
+
+BOOL FASTCALL WM32LBGetText (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ PWW pww;
+
+
+
+ if ( lpwm32mpex->fThunk ) {
+ INT cb;
+
+ if (!(pww = lpwm32mpex->pww)) {
+ if (pww = FindPWW (lpwm32mpex->hwnd, WOWCLASS_UNKNOWN))
+ lpwm32mpex->pww = pww;
+ else
+ return FALSE;
+ }
+
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - LB_ADDSTRING + 1));
+
+ //
+ // Determine if this listbox has string pointers or handles passed
+ // in with LB_ADDSTRING messages. Owner-draw listboxes that don't
+ // have the LBS_HASSTRINGS style bit set have handles passed in.
+ // These handles are simply passed back to the owner at paint time.
+ // If the LBS_HASSTRINGS style bit is set, strings are used instead of
+ // handles as the "cookie" which is passed back to the application
+ // at paint time.
+ //
+ // We treat lpwm32mpex->dwParam as a BOOL indicating this listbox
+ // takes handles instead of strings.
+ //
+
+ lpwm32mpex->dwParam =
+ (pww->dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
+ !(pww->dwStyle & LBS_HASSTRINGS);
+
+ if (lpwm32mpex->dwParam) { // if this listbox takes handles
+ cb = 4;
+ }
+ else {
+ cb = SendMessage(lpwm32mpex->hwnd, LB_GETTEXTLEN, lpwm32mpex->uParam, 0);
+
+ // Check for LB_ERR (which is -1) on the above SendMessage().
+ // When cb is equal to LB_ERR make the size as SIZE_BOGUS (256 bytes),
+ // and allocate a buffer just in case if the app diddles the lParam.
+ // We will free the buffer while unthunking the message (LB_GETTEXT).
+ // This fix makes the app MCAD happy.
+ // ChandanC 4-21-93.
+
+ if (cb == LB_ERR) {
+ cb = SIZE_BOGUS;
+ }
+ else {
+ //
+ // Add one for NULL character.
+ //
+ cb = cb + 1;
+ }
+
+ }
+
+ if (lpwm32mpex->lParam) {
+ BYTE *lpT;
+
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(cb);
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+
+ // The reason for this code to be here is that sometimes thunks
+ // are executed on a buffer that has not been initialized, e.g.
+ // if the hooks are installed by a wow app. That means we will
+ // alloc 16-bit buffer while thunking (boils down to uninitialized
+ // data buffer and will try to copy the buffer back while unthunking
+ // overwriting the stack sometimes (as user allocates temp bufs from
+ // the stack). This code initializes data so problem is avoided
+ // App: Grammatik/Windows v6.0 -- VadimB
+
+ GETVDMPTR((lpwm32mpex->Parm16.WndProc.lParam), sizeof(BYTE), lpT);
+ *lpT = 0;
+ FREEVDMPTR(lpT);
+ }
+ }
+ else {
+
+ if ((lpwm32mpex->lReturn != LB_ERR) && lpwm32mpex->lParam && lpwm32mpex->Parm16.WndProc.lParam) {
+ if (lpwm32mpex->dwParam) { // if this listbox takes handles
+ UNALIGNED DWORD *lpT;
+ GETVDMPTR((lpwm32mpex->Parm16.WndProc.lParam), sizeof(DWORD), lpT);
+ *(UNALIGNED DWORD *)lpwm32mpex->lParam = *lpT;
+ FREEVDMPTR(lpT);
+ }
+ else {
+ getstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, -1);
+ }
+ }
+
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+
+ return(TRUE);
+}
+
+// This function thunks the list box control messages
+//
+// LB_GETTEXTLEN
+
+BOOL FASTCALL WM32LBGetTextLen (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - LB_ADDSTRING + 1));
+
+ // USER32 and so do we send the LB_GETTEXTLEN message whenever an
+ // LB_GETTEXT message is sent. This LB_GETTEXTLEN message is an
+ // additional message that an app normally wouldn't see in WIN31.
+ // lParam by definition is NULL.
+ //
+ // Super Project dies (at times) when it receives the LB_GETTEXTLEN
+ // message. It doesn't expect to see this message and as a result does
+ // strlen(lParam) and dies.
+ // - nanduri
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_LB_NONNULLLPARAM) {
+ LPBYTE lpT = (LPBYTE)stackalloc16(0x2); // just an even number
+ lpwm32mpex->Parm16.WndProc.lParam = (LONG)lpT;
+ GETVDMPTR(lpT, 0x2, lpT);
+ *lpT = '\0';
+ }
+ }
+
+ return (TRUE);
+}
+
+
+
+// This function thunks the list box control messages
+//
+// LB_DIR
+
+BOOL FASTCALL WM32LBDir (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ INT cb;
+ VPVOID vp;
+
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - LB_ADDSTRING + 1));
+ if (lpwm32mpex->lParam) {
+ cb = strlen((LPSTR)lpwm32mpex->lParam)+1;
+ if (!(vp = malloc16(cb))) {
+ LOGDEBUG(0,(" WOW32.DLL : WM32LBDir() :: Could not allocate memory for string, ChandanC\n"));
+ WOW32ASSERT(vp);
+ return FALSE;
+ }
+ putstr16(vp, (LPSTR) lpwm32mpex->lParam, cb);
+ lpwm32mpex->Parm16.WndProc.lParam = vp;
+ }
+ }
+ else {
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+
+ return(TRUE);
+}
+
+// This function thunks the list box control messages
+//
+// LB_GETSELITEMS
+
+BOOL FASTCALL WM32LBGetSelItems (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if ( lpwm32mpex->fThunk ) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - LB_ADDSTRING + 1));
+ if (lpwm32mpex->lParam) {
+ INT cb;
+
+ cb = lpwm32mpex->uParam * sizeof(WORD);
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(cb);
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+
+ }
+ } else {
+ getintarray16((VPRECT16)lpwm32mpex->Parm16.WndProc.lParam, (INT)lpwm32mpex->uParam, (LPINT)lpwm32mpex->lParam);
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return(TRUE);
+}
+
+
+// This function thunks the list box control messages
+//
+// LB_SETTABSTOPS
+
+BOOL FASTCALL WM32LBSetTabStops (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if ( lpwm32mpex->fThunk ) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - LB_ADDSTRING + 1));
+ if (lpwm32mpex->uParam != 0) {
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(lpwm32mpex->uParam * sizeof(WORD));
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ putintarray16((VPRECT16)lpwm32mpex->Parm16.WndProc.lParam, (INT)lpwm32mpex->uParam, (LPINT)lpwm32mpex->lParam);
+ }
+ } else {
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return(TRUE);
+}
+
+// This function thunks the list box control messages
+//
+// LB_GETITEMRECT
+
+BOOL FASTCALL WM32LBGetItemRect (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if ( lpwm32mpex->fThunk ) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - LB_ADDSTRING + 1));
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(sizeof(RECT16));
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ } else {
+ GETRECT16( lpwm32mpex->Parm16.WndProc.lParam, (LPRECT)lpwm32mpex->lParam );
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ LOGDEBUG(3,(" Window %08lX is receiving Control Message %s(%08x)\n", lpwm32mpex->hwnd, (LPSZ)GetWMMsgName(lpwm32mpex->uMsg), lpwm32mpex->uMsg));
+
+ return(TRUE);
+
+}
+
+
+// This function thunks the list box control messages
+//
+// LB_ADDSTRING
+// LB_INSERTSTRING
+// LB_FINDSTRING
+// LB_SELECTSTRING
+
+BOOL FASTCALL WM32LBAddString (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ PWW pww;
+
+
+ if ( lpwm32mpex->fThunk ) {
+ if (!(pww = lpwm32mpex->pww)) {
+ if (pww = FindPWW (lpwm32mpex->hwnd, WOWCLASS_UNKNOWN))
+ lpwm32mpex->pww = pww;
+ else
+ return FALSE;
+ }
+
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - LB_ADDSTRING + 1));
+
+ //
+ // Determine if this listbox has string pointers or handles passed
+ // in with LB_ADDSTRING messages. Owner-draw listboxes that don't
+ // have the LBS_HASSTRINGS style bit set have handles passed in.
+ // These handles are simply passed back to the owner at paint time.
+ // If the LBS_HASSTRINGS style bit is set, strings are used instead of
+ // handles as the "cookie" which is passed back to the application
+ // at paint time.
+ //
+ // We treat lpwm32mpex->dwParam as a BOOL indicating this listbox
+ // takes handles instead of strings.
+ //
+
+ lpwm32mpex->dwParam =
+ (pww->dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
+ !(pww->dwStyle & LBS_HASSTRINGS);
+
+ if ( !lpwm32mpex->dwParam ) { // if this listbox takes strings
+ if (lpwm32mpex->lParam) {
+ INT cb;
+
+ cb = strlen((LPSZ)lpwm32mpex->lParam)+1;
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(cb);
+ if (!(lpwm32mpex->Parm16.WndProc.lParam))
+ return FALSE;
+ putstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, cb);
+ }
+ }
+ } else {
+ if ( !lpwm32mpex->dwParam ) { // if this listbox takes strings
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ getstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, -1);
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+ }
+
+ return(TRUE);
+}
+
+// This function thunks the scrollbar control messages,
+//
+// SBM_SETPOS
+// SBM_GETPOS
+// SBM_ENABLE_ARROWS
+//
+
+BOOL FASTCALL WM32SBMControl (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = WM_USER + (lpwm32mpex->uMsg - SBM_SETPOS);
+ }
+
+ return (TRUE);
+}
+
+
+// SBM_GETRANGE
+
+BOOL FASTCALL WM32SBMGetRange (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ //
+ // Changed semantics for this message to support 32-bit
+ // scroll bar ranges (vs. 16-bit).
+ //
+ // Win16:
+ // posMin = LOWORD(SendMessage(hwnd, SBM_GETRANGE, 0, 0));
+ // posMax = HIWORD(SendMessage(hwnd, SBM_GETRANGE, 0, 0));
+ //
+ // Win32:
+ // SendMessage(hwnd, SBM_GETRANGE,
+ // (WPARAM) &posMin, (LPARAM) &posMax);
+ //
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = OLDSBM_GETRANGE;
+ } else {
+ *(DWORD *)lpwm32mpex->uParam = INT32(LOWORD(lpwm32mpex->lReturn));
+ *(DWORD *)lpwm32mpex->lParam = INT32(HIWORD(lpwm32mpex->lReturn));
+ lpwm32mpex->lReturn = 0;
+ }
+
+ return (TRUE);
+}
+
+
+// SBM_SETRANGE
+// SBM_SETRANGEREDRAW (new for Win32)
+
+BOOL FASTCALL WM32SBMSetRange (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ //
+ // Changed semantics to support 32-bit scroll bar range:
+ //
+ // Win16:
+ // SendMessage(hwnd, SBM_SETRANGE, fRedraw, MAKELONG(posMin, posMax);
+ //
+ // Win32:
+ // SendMessage(hwnd, fRedraw ? SBM_SETRANGE : SBM_SETRANGEREDRAW,
+ // posMin, posMax);
+ //
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = OLDSBM_SETRANGE;
+ lpwm32mpex->Parm16.WndProc.wParam = (SBM_SETRANGEREDRAW == lpwm32mpex->uMsg);
+ lpwm32mpex->Parm16.WndProc.lParam = MAKELONG( (WORD)lpwm32mpex->uParam, (WORD)lpwm32mpex->lParam);
+ }
+
+ return (TRUE);
+}
+
+
+// LB_SETSEL
+
+BOOL FASTCALL WM32LBSetSel (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) (WM_USER + (lpwm32mpex->uMsg - LB_ADDSTRING + 1));
+ lpwm32mpex->Parm16.WndProc.wParam = (WORD) lpwm32mpex->uParam;
+ lpwm32mpex->Parm16.WndProc.lParam = (WORD)lpwm32mpex->lParam; // loword = index, hiword = 0
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the static control messages,
+//
+// STM_SETICON
+// STM_GETICON
+//
+
+BOOL FASTCALL WM32STMControl (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ switch (lpwm32mpex->uMsg) {
+ case STM_SETICON:
+ lpwm32mpex->Parm16.WndProc.wParam = (WORD)GETHICON16(lpwm32mpex->uParam);
+ break;
+
+ case STM_GETICON:
+ break;
+
+ }
+ lpwm32mpex->Parm16.WndProc.wMsg = WM_USER + (lpwm32mpex->uMsg - STM_SETICON);
+ }
+ else {
+ lpwm32mpex->lReturn = (LONG)HICON32(lpwm32mpex->lReturn);
+ }
+
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// MN_FINDMENUWINDOWFROMPOINT
+//
+
+// NT - wparam = (PUINT)pitem lParam = MAKELONG(pt.x, pt.y)
+// returns flags or hwnd *pitem = index or -1
+//
+// win31 wParam = 0 lParam = same
+// returns 0 or MAKELONG(-1, item) or MAKELONG(-2, item) or MAKELONG(hwnd, item)
+
+
+BOOL FASTCALL WM32MNFindMenuWindow (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = WIN30_MN_FINDMENUWINDOWFROMPOINT;
+ lpwm32mpex->Parm16.WndProc.wParam = 0;
+
+ } else {
+ USHORT n = LOWORD(lpwm32mpex->lReturn);
+
+ *(PLONG)lpwm32mpex->uParam = (SHORT)HIWORD(lpwm32mpex->lReturn);
+ lpwm32mpex->lReturn = (LONG)HWND32(n); // this sign-extends -1, -2 and leaves 0 as 0
+ }
+ return TRUE;
+}
diff --git a/private/mvdm/wow32/wcntl32.h b/private/mvdm/wow32/wcntl32.h
new file mode 100644
index 000000000..785f23617
--- /dev/null
+++ b/private/mvdm/wow32/wcntl32.h
@@ -0,0 +1,53 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WCNTL32.H
+ * WOW32 32-bit message thunks
+ *
+ * History:
+ * Created 19-Feb-1992 by ChandanC (ChandanC)
+--*/
+
+
+LPFNM32PROTO WM32BMControl;
+LPFNM32PROTO WM32BMClick;
+LPFNM32PROTO WM32EMControl;
+LPFNM32PROTO WM32EMSetSel;
+LPFNM32PROTO WM32EMGetRect;
+LPFNM32PROTO WM32EMSetRect;
+LPFNM32PROTO WM32EMSetRectNP;
+LPFNM32PROTO WM32EMScroll;
+LPFNM32PROTO WM32EMLineScroll;
+LPFNM32PROTO WM32EMSetHandle;
+LPFNM32PROTO WM32EMGetHandle;
+LPFNM32PROTO WM32EMGetThumb;
+LPFNM32PROTO WM32EMReplaceSel;
+LPFNM32PROTO WM32EMSetFont;
+LPFNM32PROTO WM32EMGetLine;
+LPFNM32PROTO WM32EMSetWordBreak;
+LPFNM32PROTO WM32EMSetWordBreakProc;
+LPFNM32PROTO WM32EMGetWordBreakProc;
+LPFNM32PROTO WM32EMSetTabStops;
+LPFNM32PROTO WM32CBControl;
+LPFNM32PROTO WM32CBAddString;
+LPFNM32PROTO WM32CBDir;
+LPFNM32PROTO WM32CBGetLBText;
+LPFNM32PROTO WM32CBResetContent;
+LPFNM32PROTO WM32CBGetDropDownControlRect;
+LPFNM32PROTO WM32CBComboFocus;
+LPFNM32PROTO WM32LBControl;
+LPFNM32PROTO WM32LBGetText;
+LPFNM32PROTO WM32LBGetTextLen;
+LPFNM32PROTO WM32LBDir;
+LPFNM32PROTO WM32LBGetSelItems;
+LPFNM32PROTO WM32LBSetTabStops;
+LPFNM32PROTO WM32LBGetItemRect;
+LPFNM32PROTO WM32LBAddString;
+LPFNM32PROTO WM32SBMControl;
+LPFNM32PROTO WM32SBMGetRange;
+LPFNM32PROTO WM32SBMSetRange;
+LPFNM32PROTO WM32LBSetSel;
+LPFNM32PROTO WM32STMControl;
diff --git a/private/mvdm/wow32/wcommdlg.c b/private/mvdm/wow32/wcommdlg.c
new file mode 100644
index 000000000..bc309fd98
--- /dev/null
+++ b/private/mvdm/wow32/wcommdlg.c
@@ -0,0 +1,2489 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ wcomdlg.c
+
+Abstract:
+
+ 32-bit support for thunking COMMDLG in WOW
+
+Author:
+
+ John Vert (jvert) 31-Dec-1992
+
+Revision History:
+
+ John Vert (jvert) 31-Dec-1992
+ created
+
+--*/
+#include "precomp.h"
+#pragma hdrstop
+#include <cderr.h>
+#include <dlgs.h>
+#include <wowcmndg.h>
+
+MODNAME(wcommdlg.c);
+
+//
+// Debugging macros
+//
+#if DBG
+
+#define WCDDUMPFINDREPLACE16(p16) \
+ if (fLogFilter & FILTER_COMMDLG) { \
+ LOGDEBUG(0, ("FINDREPLACE16:\n")); \
+ LOGDEBUG(0, ("\tlStructSize = %lx\n",(p16)->lStructSize)); \
+ LOGDEBUG(0, ("\thwndOwner = %x\n",(p16)->hwndOwner)); \
+ LOGDEBUG(0, ("\thInstance = %x\n",(p16)->hInstance)); \
+ LOGDEBUG(0, ("\tFlags = %x\n",(p16)->Flags)); \
+ LOGDEBUG(0, ("\tlpstrFindWhat = %lx\n",(p16)->lpstrFindWhat)); \
+ LOGDEBUG(0, ("\tlpstrReplaceWith = %lx\n",(p16)->lpstrReplaceWith)); \
+ LOGDEBUG(0, ("\twFindWhatLen = %x\n",(p16)->wFindWhatLen)); \
+ LOGDEBUG(0, ("\twReplaceWithLen = %x\n",(p16)->wReplaceWithLen)); \
+ LOGDEBUG(0, ("\tlCustData = %lx\n",(p16)->lCustData)); \
+ LOGDEBUG(0, ("\tlpfnHook = %lx\n",(p16)->lpfnHook)); \
+ LOGDEBUG(0, ("\tlpTemplateName= %lx\n",(p16)->lpTemplateName)); \
+ }
+
+#define WCDDUMPFINDREPLACE32(p32) \
+ if (fLogFilter & FILTER_COMMDLG) { \
+ LOGDEBUG(0, ("FINDREPLACE32:\n")); \
+ LOGDEBUG(0, ("\tlStructSize = %lx\n",(p32)->lStructSize)); \
+ LOGDEBUG(0, ("\thwndOwner = %x\n",(p32)->hwndOwner)); \
+ LOGDEBUG(0, ("\thInstance = %x\n",(p32)->hInstance)); \
+ LOGDEBUG(0, ("\tFlags = %x\n",(p32)->Flags)); \
+ LOGDEBUG(0, ("\tlpstrFindWhat = %s\n",(p32)->lpstrFindWhat)); \
+ LOGDEBUG(0, ("\tlpstrReplaceWith = %s\n",(p32)->lpstrReplaceWith)); \
+ LOGDEBUG(0, ("\twFindWhatLen = %x\n",(p32)->wFindWhatLen)); \
+ LOGDEBUG(0, ("\twReplaceWithLen = %x\n",(p32)->wReplaceWithLen)); \
+ LOGDEBUG(0, ("\tlCustData = %lx\n",(p32)->lCustData)); \
+ LOGDEBUG(0, ("\tlpfnHook = %lx\n",(p32)->lpfnHook)); \
+ LOGDEBUG(0, ("\tlpTemplateName= %lx\n",(p32)->lpTemplateName)); \
+ }
+
+#define WCDDUMPCHOOSEFONTDATA16(p16) \
+ if (fLogFilter & FILTER_COMMDLG) { \
+ LOGDEBUG(10, ("CHOOSEFONT16:\n")); \
+ LOGDEBUG(10, ("\tlStructSize = %lx\n",(p16)->lStructSize)); \
+ LOGDEBUG(10, ("\thwndOwner = %lx\n",(p16)->hwndOwner)); \
+ LOGDEBUG(10, ("\thDC = %lx\n",(p16)->hDC)); \
+ LOGDEBUG(10, ("\tlpLogFont = %lx\n",(p16)->lpLogFont)); \
+ LOGDEBUG(10, ("\tiPointSize = %x\n",(p16)->iPointSize)); \
+ LOGDEBUG(10, ("\tiFlags = %lx\n",(p16)->Flags)); \
+ LOGDEBUG(10, ("\trbgColors = %lx\n",(p16)->rgbColors)); \
+ LOGDEBUG(10, ("\tlCustData = %lx\n",(p16)->lCustData)); \
+ LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p16)->lpfnHook)); \
+ LOGDEBUG(10, ("\tlpTemplateName= %lx\n",(p16)->lpTemplateName)); \
+ LOGDEBUG(10, ("\thInstance = %lx\n",(p16)->hInstance)); \
+ LOGDEBUG(10, ("\tlpszStyle = %lx\n",(p16)->lpszStyle)); \
+ LOGDEBUG(10, ("\tnFontType = %x\n",(p16)->nFontType)); \
+ LOGDEBUG(10, ("\tnSizeMin = %x\n",(p16)->nSizeMin)); \
+ LOGDEBUG(10, ("\tnSizeMax = %x\n",(p16)->nSizeMax)); \
+ }
+
+#define WCDDUMPCHOOSEFONTDATA32(p32) \
+ if (fLogFilter & FILTER_COMMDLG) { \
+ LOGDEBUG(10, ("CHOOSEFONT32:\n")); \
+ LOGDEBUG(10, ("\tlStructSize = %lx\n",(p32)->lStructSize)); \
+ LOGDEBUG(10, ("\thwndOwner = %lx\n",(p32)->hwndOwner)); \
+ LOGDEBUG(10, ("\thDC = %lx\n",(p32)->hDC)); \
+ LOGDEBUG(10, ("\tlpLogFont = %lx\n",(p32)->lpLogFont)); \
+ LOGDEBUG(10, ("\tiPointSize = %lx\n",(p32)->iPointSize)); \
+ LOGDEBUG(10, ("\tiFlags = %lx\n",(p32)->Flags)); \
+ LOGDEBUG(10, ("\trbgColors = %lx\n",(p32)->rgbColors)); \
+ LOGDEBUG(10, ("\tlCustData = %lx\n",(p32)->lCustData)); \
+ LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p32)->lpfnHook)); \
+ LOGDEBUG(10, ("\tlpTemplateName= %lx\n",(p32)->lpTemplateName)); \
+ LOGDEBUG(10, ("\thInstance = %lx\n",(p32)->hInstance)); \
+ LOGDEBUG(10, ("\tlpszStyle = %lx\n",(p32)->lpszStyle)); \
+ LOGDEBUG(10, ("\tnFontType = %x\n",(p32)->nFontType)); \
+ LOGDEBUG(10, ("\tnSizeMin = %lx\n",(p32)->nSizeMin)); \
+ LOGDEBUG(10, ("\tnSizeMax = %lx\n",(p32)->nSizeMax)); \
+ }
+
+#define WCDDUMPOPENFILENAME16(p16) \
+ if (fLogFilter & FILTER_COMMDLG) { \
+ LOGDEBUG(10, ("OPENFILENAME16:\n")); \
+ LOGDEBUG(10, ("\tlStructSize = %x\n",(p16)->lStructSize)); \
+ LOGDEBUG(10, ("\thwndOwner = %lx\n",(p16)->hwndOwner)); \
+ LOGDEBUG(10, ("\thInstance = %lx\n",(p16)->hInstance)); \
+ LOGDEBUG(10, ("\tlpstrFilter = %lx\n",(p16)->lpstrFilter)); \
+ LOGDEBUG(10, ("\tlpstrCustomFilter= %lx\n",(p16)->lpstrCustomFilter)); \
+ LOGDEBUG(10, ("\tnMaxCustFilter = %lx\n",(p16)->nMaxCustFilter)); \
+ LOGDEBUG(10, ("\tnFilterIndex = %lx\n",(p16)->nFilterIndex)); \
+ LOGDEBUG(10, ("\tlpstrFile = %lx\n",(p16)->lpstrFile)); \
+ LOGDEBUG(10, ("\tnMaxFile = %lx\n",(p16)->nMaxFile)); \
+ LOGDEBUG(10, ("\tlpstrFileTitle = %lx\n",(p16)->lpstrFileTitle)); \
+ LOGDEBUG(10, ("\tnMaxFileTitle = %lx\n",(p16)->nMaxFileTitle)); \
+ LOGDEBUG(10, ("\tlpstrInitialDir = %lx\n",(p16)->lpstrInitialDir)); \
+ LOGDEBUG(10, ("\tlpstrTitle = %lx\n",(p16)->lpstrTitle)); \
+ LOGDEBUG(10, ("\tFlags = %lx\n",(p16)->Flags)); \
+ LOGDEBUG(10, ("\tnFileOffset = %lx\n",(p16)->nFileOffset)); \
+ LOGDEBUG(10, ("\tnFileExtension = %lx\n",(p16)->nFileExtension)); \
+ LOGDEBUG(10, ("\tlpstrDefExt = %lx\n",(p16)->lpstrDefExt)); \
+ LOGDEBUG(10, ("\tlCustData = %lx\n",(p16)->lCustData)); \
+ LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p16)->lpfnHook)); \
+ LOGDEBUG(10, ("\tlpTemplateName = %lx\n",(p16)->lpTemplateName)); \
+ }
+
+#define WCDDUMPOPENFILENAME32(p32) \
+ if (fLogFilter & FILTER_COMMDLG) { \
+ LOGDEBUG(10, ("OPENFILENAME32:\n")); \
+ LOGDEBUG(10, ("\tlStructSize = %x\n",(p32)->lStructSize)); \
+ LOGDEBUG(10, ("\thwndOwner = %lx\n",(p32)->hwndOwner)); \
+ LOGDEBUG(10, ("\thInstance = %lx\n",(p32)->hInstance)); \
+ LOGDEBUG(10, ("\tlpstrFilter = %s\n",(p32)->lpstrFilter)); \
+ LOGDEBUG(10, ("\tlpstrCustomFilter= %s\n",(p32)->lpstrCustomFilter)); \
+ LOGDEBUG(10, ("\tnMaxCustFilter = %lx\n",(p32)->nMaxCustFilter)); \
+ LOGDEBUG(10, ("\tnFilterIndex = %lx\n",(p32)->nFilterIndex)); \
+ LOGDEBUG(10, ("\tlpstrFile = %s\n",(p32)->lpstrFile)); \
+ LOGDEBUG(10, ("\tnMaxFile = %lx\n",(p32)->nMaxFile)); \
+ LOGDEBUG(10, ("\tlpstrFileTitle = %s\n",(p32)->lpstrFileTitle)); \
+ LOGDEBUG(10, ("\tnMaxFileTitle = %lx\n",(p32)->nMaxFileTitle)); \
+ LOGDEBUG(10, ("\tlpstrInitialDir = %s\n",(p32)->lpstrInitialDir)); \
+ LOGDEBUG(10, ("\tlpstrTitle = %s\n",(p32)->lpstrTitle)); \
+ LOGDEBUG(10, ("\tFlags = %lx\n",(p32)->Flags)); \
+ LOGDEBUG(10, ("\tnFileOffset = %lx\n",(p32)->nFileOffset)); \
+ LOGDEBUG(10, ("\tnFileExtension = %lx\n",(p32)->nFileExtension)); \
+ LOGDEBUG(10, ("\tlpstrDefExt = %s\n",(p32)->lpstrDefExt)); \
+ LOGDEBUG(10, ("\tlCustData = %lx\n",(p32)->lCustData)); \
+ LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p32)->lpfnHook)); \
+ LOGDEBUG(10, ("\tlpTemplateName = %lx\n",(p32)->lpTemplateName)); \
+ }
+
+#define WCDDUMPPRINTDLGDATA16(p16) \
+ if (fLogFilter & FILTER_COMMDLG) { \
+ LOGDEBUG(10, ("PRINTDLGDATA16:\n")); \
+ LOGDEBUG(10, ("\tlStructSize = %x\n",(p16)->lStructSize)); \
+ LOGDEBUG(10, ("\thwndOwner = %lx\n",(p16)->hwndOwner)); \
+ LOGDEBUG(10, ("\thDevMode = %lx\n",(p16)->hDevMode)); \
+ LOGDEBUG(10, ("\thDevNames = %lx\n",(p16)->hDevNames)); \
+ LOGDEBUG(10, ("\thDC = %lx\n",(p16)->hDC)); \
+ LOGDEBUG(10, ("\tFlags = %lx\n",(p16)->Flags)); \
+ LOGDEBUG(10, ("\tnFromPage = %d\n",(p16)->nFromPage)); \
+ LOGDEBUG(10, ("\tnToPage = %d\n",(p16)->nToPage)); \
+ LOGDEBUG(10, ("\tnMinPage = %d\n",(p16)->nMinPage)); \
+ LOGDEBUG(10, ("\tnMaxPage = %d\n",(p16)->nMaxPage)); \
+ LOGDEBUG(10, ("\tnCopies = %d\n",(p16)->nCopies)); \
+ LOGDEBUG(10, ("\thInstance = %lx\n",(p16)->hInstance)); \
+ LOGDEBUG(10, ("\tlCustData = %lx\n",(p16)->lCustData)); \
+ LOGDEBUG(10, ("\tlpfnPrintHook = %lx\n",(p16)->lpfnPrintHook)); \
+ LOGDEBUG(10, ("\tlpfnSetupHook = %lx\n",(p16)->lpfnSetupHook)); \
+ LOGDEBUG(10, ("\tlpPrintTemplateName = %lx\n",(p16)->lpPrintTemplateName)); \
+ LOGDEBUG(10, ("\tlpSetupTemplateName = %lx\n",(p16)->lpSetupTemplateName)); \
+ LOGDEBUG(10, ("\thPrintTemplate = %lx\n",(p16)->hPrintTemplate)); \
+ LOGDEBUG(10, ("\thSetupTemplate = %lx\n",(p16)->hSetupTemplate)); \
+ }
+
+#define WCDDUMPPRINTDLGDATA32(p32) \
+ if (fLogFilter & FILTER_COMMDLG) { \
+ LOGDEBUG(10, ("PRINTDLGDATA32:\n")); \
+ LOGDEBUG(10, ("\tlStructSize = %x\n",(p32)->lStructSize)); \
+ LOGDEBUG(10, ("\thwndOwner = %lx\n",(p32)->hwndOwner)); \
+ LOGDEBUG(10, ("\thDevMode = %lx\n",(p32)->hDevMode)); \
+ LOGDEBUG(10, ("\thDevNames = %lx\n",(p32)->hDevNames)); \
+ LOGDEBUG(10, ("\thDC = %lx\n",(p32)->hDC)); \
+ LOGDEBUG(10, ("\tFlags = %lx\n",(p32)->Flags)); \
+ LOGDEBUG(10, ("\tnFromPage = %d\n",(p32)->nFromPage)); \
+ LOGDEBUG(10, ("\tnToPage = %d\n",(p32)->nToPage)); \
+ LOGDEBUG(10, ("\tnMinPage = %d\n",(p32)->nMinPage)); \
+ LOGDEBUG(10, ("\tnMaxPage = %d\n",(p32)->nMaxPage)); \
+ LOGDEBUG(10, ("\tnCopies = %d\n",(p32)->nCopies)); \
+ LOGDEBUG(10, ("\thInstance = %lx\n",(p32)->hInstance)); \
+ LOGDEBUG(10, ("\tlCustData = %lx\n",(p32)->lCustData)); \
+ LOGDEBUG(10, ("\tlpfnPrintHook = %lx\n",(p32)->lpfnPrintHook)); \
+ LOGDEBUG(10, ("\tlpfnSetupHook = %lx\n",(p32)->lpfnSetupHook)); \
+ LOGDEBUG(10, ("\tlpPrintTemplateName = %lx\n",(p32)->lpPrintTemplateName)); \
+ LOGDEBUG(10, ("\tlpSetupTemplateName = %lx\n",(p32)->lpSetupTemplateName)); \
+ LOGDEBUG(10, ("\thPrintTemplate = %lx\n",(p32)->hPrintTemplate)); \
+ LOGDEBUG(10, ("\thSetupTemplate = %lx\n",(p32)->hSetupTemplate)); \
+ }
+
+#define WCDDUMPCHOOSECOLORDATA16(p16) \
+ if (fLogFilter & FILTER_COMMDLG) { \
+ LOGDEBUG(10, ("CHOOSECOLORDATA16:\n")); \
+ LOGDEBUG(10, ("\tlStructSize = %x\n",(p16)->lStructSize)); \
+ LOGDEBUG(10, ("\thwndOwner = %lx\n",(p16)->hwndOwner)); \
+ LOGDEBUG(10, ("\thInstance = %lx\n",(p16)->hInstance)); \
+ LOGDEBUG(10, ("\trgbResult = %lx\n",(p16)->rgbResult)); \
+ LOGDEBUG(10, ("\tlpCustColors = %lx\n",(p16)->lpCustColors)); \
+ LOGDEBUG(10, ("\tFlags = %lx\n",(p16)->Flags)); \
+ LOGDEBUG(10, ("\tlCustData = %lx\n",(p16)->lCustData)); \
+ LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p16)->lpfnHook)); \
+ LOGDEBUG(10, ("\tlpTemplateName = %lx\n",(p16)->lpTemplateName)); \
+ }
+#define WCDDUMPCHOOSECOLORDATA32(p32) \
+ if (fLogFilter & FILTER_COMMDLG) { \
+ LOGDEBUG(10, ("CHOOSECOLORDATA32:\n")); \
+ LOGDEBUG(10, ("\tlStructSize = %x\n",(p32)->lStructSize)); \
+ LOGDEBUG(10, ("\thwndOwner = %lx\n",(p32)->hwndOwner)); \
+ LOGDEBUG(10, ("\thInstance = %lx\n",(p32)->hInstance)); \
+ LOGDEBUG(10, ("\trgbResult = %lx\n",(p32)->rgbResult)); \
+ LOGDEBUG(10, ("\tlpCustColors = %lx\n",(p32)->lpCustColors)); \
+ LOGDEBUG(10, ("\tFlags = %lx\n",(p32)->Flags)); \
+ LOGDEBUG(10, ("\tlCustData = %lx\n",(p32)->lCustData)); \
+ LOGDEBUG(10, ("\tlpfnHook = %lx\n",(p32)->lpfnHook)); \
+ LOGDEBUG(10, ("\tlpTemplateName = %lx\n",(p32)->lpTemplateName)); \
+ }
+
+#else
+
+#define WCDDUMPCHOOSECOLORDATA16(p16)
+#define WCDDUMPCHOOSECOLORDATA32(p32)
+#define WCDDUMPCHOOSEFONTDATA16(p16)
+#define WCDDUMPCHOOSEFONTDATA32(p32)
+#define WCDDUMPOPENFILENAME16(p16)
+#define WCDDUMPOPENFILENAME32(p32)
+#define WCDDUMPPRINTDLGDATA16(p16)
+#define WCDDUMPPRINTDLGDATA32(p32)
+#define WCDDUMPFINDREPLACE16(p16)
+#define WCDDUMPFINDREPLACE32(p32)
+
+#endif
+
+#define FR_OUTPUTFLAGS (FR_DOWN | FR_WHOLEWORD | FR_MATCHCASE | \
+ FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL | \
+ FR_DIALOGTERM | FR_SHOWHELP | FR_NOUPDOWN | \
+ FR_NOMATCHCASE | FR_NOWHOLEWORD | FR_HIDEUPDOWN | \
+ FR_HIDEMATCHCASE | FR_HIDEWHOLEWORD)
+
+#define SETEXTENDEDERROR(Code) (dwExtError=Code)
+#define PD_OUTPUTFLAGS (PD_ALLPAGES | PD_COLLATE | PD_PAGENUMS | \
+ PD_PRINTTOFILE | PD_SELECTION)
+
+#define FO_OUTPUTFLAGS (OFN_READONLY | OFN_EXTENSIONDIFFERENT)
+
+#define CF_OUTPUTFLAGS (CF_NOFACESEL | CF_NOSIZESEL | CF_NOSTYLESEL)
+
+//
+// private typedefs and structs
+//
+
+typedef BOOL (APIENTRY* FILENAMEPROC)(LPOPENFILENAME);
+typedef HWND (APIENTRY* FINDREPLACEPROC)(LPFINDREPLACE);
+
+//
+// private function prototypes
+//
+
+PCOMMDLGTD
+GetCommdlgTd(
+ IN HWND Hwnd32
+ );
+
+PRES
+GetTemplate16(
+ IN HAND16 hInstance,
+ IN VPCSTR TemplateName,
+ IN BOOLEAN UseHandle
+ );
+
+VOID
+ThunkhDevMode32to16(
+ IN HANDLE hDevMode32,
+ IN OUT HAND16 *phDevMode16
+ );
+
+HGLOBAL
+ThunkhDevMode16to32(
+ IN HAND16 hDevMode16
+ );
+
+VOID
+ThunkDevNames32to16(
+ IN HANDLE hDevNames,
+ IN OUT HAND16 *phDevNames16
+ );
+
+VOID
+ThunkOpenFileName16to32(
+ IN POPENFILENAME16 FileName16,
+ OUT OPENFILENAME *FileName
+ );
+
+VOID
+ThunkOpenFileName32to16(
+ IN OPENFILENAME *FileName,
+ OUT POPENFILENAME16 FileName16,
+ IN BOOLEAN bUpperStrings
+ );
+
+VOID
+ThunkFindReplace16to32(
+ IN PFINDREPLACE16 FindReplace16,
+ OUT FINDREPLACE *FindReplace
+ );
+
+UINT APIENTRY
+WCD32CommonDialogProc(
+ HWND hdlg,
+ UINT uMsg,
+ WPARAM uParam,
+ LPARAM lParam,
+ PCOMMDLGTD pCTD,
+ VPVOID vpfnHook
+ );
+
+UINT APIENTRY
+WCD32PrintSetupDialogProc(
+ HWND hdlg,
+ UINT uMsg,
+ WPARAM uParam,
+ LPARAM lParam
+ );
+
+UINT APIENTRY
+WCD32DialogProc(
+ HWND hdlg,
+ UINT uMsg,
+ WPARAM uParam,
+ LPARAM lParam
+ );
+
+ULONG
+WCD32GetFileName(
+ IN PVDMFRAME pFrame,
+ IN FILENAMEPROC Function
+ );
+
+ULONG
+WCD32FindReplaceText(
+ IN PVDMFRAME pFrame,
+ IN FINDREPLACEPROC Function
+ );
+
+UINT APIENTRY
+WCD32FindReplaceDialogProc(
+ HWND hdlg,
+ UINT uMsg,
+ WPARAM uParam,
+ LPARAM lParam
+ );
+
+//
+// global data
+//
+ULONG dwExtError = 0;
+
+WORD msgFILEOK=0;
+WORD msgWOWLFCHANGE=0;
+WORD msgWOWDIRCHANGE=0;
+WORD msgWOWCHOOSEFONT=0;
+WORD msgSHAREVIOLATION=0;
+WORD msgFINDREPLACE=0;
+
+//
+// unique message thunks
+//
+
+//
+// This function thunks the private messages
+//
+// msgFILEOK
+//
+
+BOOL FASTCALL WM32msgFILEOK(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ VPOPENFILENAME lpof;
+ POPENFILENAME16 FileName16;
+ OPENFILENAME *FileName;
+
+
+ lpof = (VPOPENFILENAME)(GetCommdlgTd(lpwm32mpex->hwnd)->vpData);
+ FileName = (OPENFILENAME *)lpwm32mpex->lParam;
+ //
+ // Approach sends its own fileok message when you click on its
+ // secret listbox that it displays over lst1 sometimes. It
+ // sends NULL for the LPARAM instead of the address of the
+ // openfilename structure.
+ //
+ if (FileName == NULL) {
+ lpwm32mpex->Parm16.WndProc.lParam = (LPARAM)NULL;
+ return(TRUE);
+ }
+
+ GETVDMPTR(lpof, sizeof(*FileName16), FileName16);
+
+ if (lpwm32mpex->fThunk) {
+ UpdateDosCurrentDirectory(DIR_NT_TO_DOS);
+ lpwm32mpex->Parm16.WndProc.lParam = (LPARAM)lpof;
+
+ // sudeepb 12-Mar-1996
+ //
+ // The selected file name needs to be uppercased for brain dead
+ // apps like symanatec QA 4.0. So changed the following parameter
+ // in ThunkOpenFileName from FALSE to TRUE.
+ //
+
+
+ ThunkOpenFileName32to16(FileName, FileName16, TRUE);
+ } else {
+ FileName->Flags = DWORD32(FileName16->Flags) | OFN_NOLONGNAMES | CD_WOWAPP;
+ FileName->nFileOffset = FileName16->nFileOffset;
+ FileName->nFileExtension = FileName16->nFileExtension;
+ GETPSZPTR(FileName16->lpstrFilter, FileName->lpstrFilter);
+ GETPSZPTR(FileName16->lpstrCustomFilter, FileName->lpstrCustomFilter);
+ GETPSZPTR(FileName16->lpstrFile, FileName->lpstrFile);
+ GETPSZPTR(FileName16->lpstrFileTitle, FileName->lpstrFileTitle);
+ }
+
+ FREEVDMPTR( FileName16 );
+
+ return (TRUE);
+}
+
+//
+// This function thunks the private messages
+//
+// msgWOWDIRCHANGE
+//
+
+BOOL FASTCALL WM32msgWOWDIRCHANGE(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ UpdateDosCurrentDirectory(DIR_NT_TO_DOS);
+ }
+
+ return (TRUE);
+}
+
+//
+// This function thunks the private message
+//
+// msgWOWLFCHANGE
+//
+
+BOOL FASTCALL WM32msgWOWLFCHANGE(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ VPCHOOSEFONTDATA lpcf;
+ PCHOOSEFONTDATA16 ChooseFontData16;
+
+
+ lpcf = (VPCHOOSEFONTDATA)(GetCommdlgTd(lpwm32mpex->hwnd)->vpData);
+ GETVDMPTR(lpcf, sizeof(*ChooseFontData16), ChooseFontData16);
+
+ if (lpwm32mpex->fThunk) {
+ PUTLOGFONT16(ChooseFontData16->lpLogFont,
+ sizeof(LOGFONT),
+ (LPLOGFONT)lpwm32mpex->lParam);
+ }
+
+ return (TRUE);
+}
+
+//
+// This function thunks the private message
+//
+// msgSHAREVIOLATION
+//
+
+BOOL FASTCALL WM32msgSHAREVIOLATION(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ INT cb;
+ PLONG plParamNew = &lpwm32mpex->Parm16.WndProc.lParam;
+
+
+ if (lpwm32mpex->fThunk) {
+ if (lpwm32mpex->lParam) {
+ cb = strlen((LPSZ)lpwm32mpex->lParam)+1;
+ if (!(*plParamNew = malloc16(cb))) {
+ return(FALSE);
+ }
+ putstr16((VPSZ)*plParamNew, (LPSZ)lpwm32mpex->lParam, cb);
+ }
+ } else {
+ if (*plParamNew) {
+ free16((VPVOID) *plParamNew);
+ }
+ }
+
+ return (TRUE);
+}
+
+//
+// This function thunks the private messages
+//
+// WM_CHOOSEFONT_GETLOGFONT
+//
+
+BOOL FASTCALL WM32msgCHOOSEFONTGETLOGFONT(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ LOGFONT LogFont32;
+
+ // The mere fact that we access the buffer after allowing the 16-bit
+ // hook proc to step in breaks Serif PagePlus app which wants it's
+ // hook proc to always have a shot and commdlg to check the return value.
+
+ // If hook proc returns TRUE, no further action is taken
+ //
+ // This is the message an app sends the dialog if it wants to find
+ // out what font is currently selected.
+ //
+ // We thunk this by sending yet another hackorama message to comdlg32,
+ // who will then fill in the 32-bit structure we pass in so we can
+ // thunk it back to the 16-bit structure. Then we return TRUE so
+ // comdlg32 doesn't reference the 16-bit logfont.
+ //
+ if (!lpwm32mpex->fThunk && !lpwm32mpex->lReturn) {
+ SendMessage(lpwm32mpex->hwnd, msgWOWCHOOSEFONT, 0, (LPARAM)&LogFont32);
+
+ PUTLOGFONT16(lpwm32mpex->lParam, sizeof(LOGFONT), &LogFont32);
+
+ lpwm32mpex->lReturn = TRUE;
+ }
+
+ return (TRUE);
+}
+
+//
+// Dialog callback hook thunks
+//
+
+UINT APIENTRY
+WCD32DialogProc(
+ HWND hdlg,
+ UINT uMsg,
+ WPARAM uParam,
+ LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ This is the hook proc used by ChooseFont, GetOpenFileName,
+ GetSaveFileName, and PrintDlg. It pulls the 16-bit callback
+ out of the thread data and calls the common dialog proc to do
+ the rest of the work.
+
+--*/
+
+{
+ PCOMMDLGTD Td;
+
+ Td=GetCommdlgTd(hdlg);
+ return(WCD32CommonDialogProc(hdlg,
+ uMsg,
+ uParam,
+ lParam,
+ Td,
+ Td->vpfnHook));
+}
+
+
+UINT APIENTRY
+WCD32PrintSetupDialogProc(
+ HWND hdlg,
+ UINT uMsg,
+ WPARAM uParam,
+ LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ This is the hook proc used by PrintSetup. It is only used when
+ the Setup button on the Print dialog directly creates the PrintSetup
+ dialog. We find the correct TD by looking for the TD of our owner
+ window (which is the print dialog)
+
+ It calls the common dialog proc to do the rest of the work.
+
+--*/
+
+{
+ PCOMMDLGTD Td;
+
+ Td=CURRENTPTD()->CommDlgTd;
+ while (Td->SetupHwnd != GETHWND16(hdlg)) {
+ Td=Td->Previous;
+ if (Td==NULL) {
+ //
+ // Our hwnd has not been put in the list. Find our owner's
+ // hwnd. We share the same Td as our owner, find it and
+ // mark it with our hwnd.
+ //
+ Td = GetCommdlgTd(GetWindow(hdlg, GW_OWNER));
+ Td->SetupHwnd = GETHWND16(hdlg);
+ break;
+ }
+ }
+
+ return(WCD32CommonDialogProc(hdlg,
+ uMsg,
+ uParam,
+ lParam,
+ Td,
+ Td->vpfnSetupHook));
+}
+
+
+UINT APIENTRY
+WCD32CommonDialogProc(
+ HWND hdlg,
+ UINT uMsg,
+ WPARAM uParam,
+ LPARAM lParam,
+ PCOMMDLGTD pCTD,
+ VPVOID vpfnHook
+ )
+
+/*++
+
+Routine Description:
+
+ This thunks the 32-bit dialog callback into a 16-bit callback
+ This is the common code used by all the dialog callback thunks that
+ actually calls the 16-bit callback.
+
+--*/
+
+{
+ BOOL fSuccess;
+ LPFNM32 pfnThunkMsg;
+ WM32MSGPARAMEX wm32mpex;
+ BOOL fMessageNeedsThunking;
+ POPENFILENAME16 pStruct16;
+
+ // If the app has GP Faulted we don't want to pass it any more input
+ // This should be removed when USER32 does clean up on task death so
+ // it doesn't call us - mattfe june 24 92
+
+
+ // Uncomment to receive messages on entrance
+ // LOGDEBUG(10, ("CommonDialogProc In: %lX %X %X %lX (%lX)\n", (DWORD)hdlg, uMsg, uParam, lParam
+
+ if (CURRENTPTD()->dwFlags & TDF_IGNOREINPUT) {
+ LOGDEBUG(6,(" WCD32OpenFileDialog Ignoring Input Messsage %04X\n",uMsg));
+ WOW32ASSERTMSG(!gfIgnoreInputAssertGiven,
+ "WCD32CommonDialogProc: TDF_IGNOREINPUT hack was used, shouldn't be, "
+ "please email DaveHart with repro instructions. Hit 'g' to ignore this "
+ "and suppress this assertion from now on.\n");
+ gfIgnoreInputAssertGiven = TRUE;
+ goto SilentError;
+ }
+
+#if DBG
+ if (pCTD==NULL) {
+ LOGDEBUG(0,(" WCD32OpenFileDialog ERROR: pCTD==NULL\n"));
+ goto Error;
+ }
+
+ // If pCTD->vpfnHook is NULL, then something is broken; we
+ // certainly can't continue because we don't know what 16-bit func to call
+
+ if (!vpfnHook) {
+ LOGDEBUG(0,(" WCD32OpenFileDialog ERROR: no hook proc for message %04x Dlg = %08lx\n", uMsg, hdlg ));
+ goto Error;
+ }
+#endif
+
+ // This should be removed when all thunk functions appropiately fill these
+ // in, till then we must have these 3 lines before calling thunk functions !
+ // ChandanC, 2/28/92 HACK32
+ //
+
+ wm32mpex.Parm16.WndProc.hwnd = GETHWND16(hdlg);
+ wm32mpex.Parm16.WndProc.wMsg = (WORD)uMsg;
+ wm32mpex.Parm16.WndProc.wParam = (WORD)uParam;
+ wm32mpex.Parm16.WndProc.lParam = (LONG)lParam;
+ wm32mpex.Parm16.WndProc.hInst = (WORD)GetWindowLong(hdlg, GWL_HINSTANCE);
+
+ if (uMsg == WM_INITDIALOG) {
+
+ //
+ // The address of the 16-bit structure must be provided
+ // in the WM_INITDIALOG message
+ //
+
+ wm32mpex.Parm16.WndProc.lParam = lParam = (LPARAM)pCTD->vpData;
+
+ // The flags in the APPS OPENFILENAME structure get updated by
+ // CommDlg16 in fileopen.c\InitFileDlg(). This happens in
+ // FileOpenDlgProc() & FileSaveDlgProc() while processing the
+ // WM_INITDIALOG message. Persuasion 3.0 depends on it.
+ GETVDMPTR(lParam, sizeof(DWORD), pStruct16);
+ if(pStruct16->lStructSize == sizeof(OPENFILENAME16)) {
+ if(pStruct16->Flags & OFN_CREATEPROMPT) {
+ pStruct16->Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
+ }
+ else if(pStruct16->Flags & OFN_FILEMUSTEXIST) {
+ pStruct16->Flags |= OFN_PATHMUSTEXIST;
+ }
+ }
+ pfnThunkMsg = aw32Msg[uMsg].lpfnM32;
+
+ } else if (uMsg < 0x400) {
+ LOGDEBUG(3,("%04X (%s)\n", CURRENTPTD()->htask16, (aw32Msg[uMsg].lpszW32)));
+
+ pfnThunkMsg = aw32Msg[uMsg].lpfnM32;
+
+ //
+ // Some apps (Claris FileMaker Pro) will change the OPENFILENAME
+ // struct in their hookproc for the IDOK message.
+ // So if this is an IDOK message, and it is a FileOpen/SaveAs
+ // common dialog call, we need to make sure everything gets
+ // thunked back to 16-bits.
+ //
+ if ((uMsg==WM_COMMAND) &&
+ (LOWORD(uParam)==IDOK) &&
+ (pCTD->pData32 != NULL) &&
+ (pCTD->Flags & WOWCD_ISOPENFILE)) {
+
+ POPENFILENAME16 FileName16;
+
+ GETVDMPTR(pCTD->vpData, sizeof(*FileName16), FileName16);
+ ThunkOpenFileName32to16((OPENFILENAME *)pCTD->pData32, FileName16, FALSE);
+ FREEVDMPTR(FileName16);
+ }
+ } else {
+ //
+ // Check for unique messages
+ //
+ if (uMsg == msgFILEOK) {
+ pfnThunkMsg = WM32msgFILEOK;
+
+ } else if (uMsg == msgSHAREVIOLATION) {
+ pfnThunkMsg = WM32msgSHAREVIOLATION;
+ } else if (uMsg == msgWOWDIRCHANGE) {
+ pfnThunkMsg = WM32msgWOWDIRCHANGE;
+ } else if (uMsg == msgWOWLFCHANGE) {
+ pfnThunkMsg = WM32msgWOWLFCHANGE;
+ } else if (pCTD->Flags & WOWCD_ISCHOOSEFONT) {
+ //
+ // special ChooseFont thunks to handle goofy GETLOGFONT message
+ //
+ if (uMsg == WM_CHOOSEFONT_GETLOGFONT) {
+
+ pfnThunkMsg = WM32msgCHOOSEFONTGETLOGFONT;
+
+ } else if (uMsg == msgWOWCHOOSEFONT) {
+ //
+ // no wow app will expect this, so don't send it.
+ //
+ return(FALSE);
+ } else {
+ pfnThunkMsg = WM32NoThunking;
+ }
+ } else {
+ pfnThunkMsg = WM32NoThunking;
+ }
+ }
+
+ fMessageNeedsThunking = (pfnThunkMsg != WM32NoThunking);
+ if (fMessageNeedsThunking) {
+ wm32mpex.fThunk = THUNKMSG;
+ wm32mpex.hwnd = hdlg;
+ wm32mpex.uMsg = uMsg;
+ wm32mpex.uParam = uParam;
+ wm32mpex.lParam = lParam;
+ wm32mpex.pww = NULL;
+ wm32mpex.lpfnM32 = pfnThunkMsg;
+
+ if (!(pfnThunkMsg)(&wm32mpex)) {
+ LOGDEBUG(LOG_ERROR,(" WCD32OpenFileDialog ERROR: cannot thunk 32-bit message %04x\n", uMsg));
+ goto Error;
+ }
+ } else {
+ LOGDEBUG(6,("WCD32CommonDialogProc, No Thunking was required for the 32-bit message %s(%04x)\n", (LPSZ)GetWMMsgName(uMsg), uMsg));
+ }
+
+
+ fSuccess = CallBack16(RET_WNDPROC, &wm32mpex.Parm16, vpfnHook, (PVPVOID)&wm32mpex.lReturn);
+
+ // the callback function of a dialog is of type FARPROC whose return value
+ // is of type 'int'. Since dx:ax is copied into lReturn in the above
+ // CallBack16 call, we need to zero out the hiword, otherwise we will be
+ // returning an erroneous value.
+
+ wm32mpex.lReturn = (LONG)LOWORD(wm32mpex.lReturn);
+
+ //
+ // Some apps (Claris FileMaker Pro) will change the OPENFILENAME
+ // struct in their hookproc for the IDOK message.
+ // So if this is an IDOK message, and it is a FileOpen/SaveAs
+ // common dialog call, we need to make sure everything gets
+ // thunked back to 32-bits.
+ //
+ if ((uMsg==WM_COMMAND) &&
+ (LOWORD(uParam)==IDOK) &&
+ (pCTD->pData32 != NULL) &&
+ (pCTD->Flags & WOWCD_ISOPENFILE)) {
+
+ POPENFILENAME16 FileName16;
+
+ GETVDMPTR(pCTD->vpData, sizeof(*FileName16), FileName16);
+ ThunkOpenFileName16to32(FileName16, (OPENFILENAME *)pCTD->pData32);
+ FREEVDMPTR(FileName16);
+ }
+
+ if (fMessageNeedsThunking) {
+ wm32mpex.fThunk = UNTHUNKMSG;
+ (pfnThunkMsg)(&wm32mpex);
+ }
+
+ if (!fSuccess)
+ goto Error;
+
+Done:
+ // Uncomment to receive message on exit
+ // LOGDEBUG(10, ("CommonDialogProc Out: Return %lX\n", wm32mpex.lReturn));
+
+ return wm32mpex.lReturn;
+
+Error:
+ LOGDEBUG(5,(" WCD32OpenFileDialog WARNING: cannot call back, using default message handling\n"));
+SilentError:
+ wm32mpex.lReturn = 0;
+ goto Done;
+}
+
+ULONG FASTCALL WCD32ChooseColor( PVDMFRAME pFrame )
+
+/*++
+
+Routine Description:
+
+ This routine thunks the 16-bit ChooseColor common dialog to the 32-bit
+ side.
+
+Arguments:
+
+ pFrame - Supplies 16-bit argument frame
+
+Return Value:
+
+ 16-bit BOOLEAN to be returned.
+
+--*/
+
+{
+ ULONG ul;
+ register PCHOOSECOLOR16 parg16;
+ VPCHOOSECOLORDATA vpcc;
+ CHOOSECOLOR ChooseColorData;
+ PCHOOSECOLORDATA16 ChooseColorData16;
+ PRES hRes;
+ COMMDLGTD ThreadData;
+ DWORD CustColors32[16];
+ DWORD *pCustColors16;
+
+ GETARGPTR(pFrame, sizeof(CHOOSECOLOR16), parg16);
+
+ vpcc = parg16->lpcc;
+ GETVDMPTR(vpcc, sizeof(*ChooseColorData16), ChooseColorData16);
+
+ SETEXTENDEDERROR( 0 );
+ ThreadData.Previous = CURRENTPTD()->CommDlgTd;
+ ThreadData.hdlg = (HWND16)-1;
+ ThreadData.pData32 = NULL;
+ ThreadData.Flags = 0;
+ CURRENTPTD()->CommDlgTd = &ThreadData;
+
+ WCDDUMPCHOOSECOLORDATA16(ChooseColorData16);
+
+ ChooseColorData.lStructSize = sizeof(CHOOSECOLOR);
+ ChooseColorData.hwndOwner = HWND32(ChooseColorData16->hwndOwner);
+ ChooseColorData.Flags = DWORD32(ChooseColorData16->Flags) | CD_WOWAPP;
+ ChooseColorData.rgbResult = DWORD32(ChooseColorData16->rgbResult);
+
+ //
+ // Note we have to copy the 16-bit array of dwords to our stack in
+ // order to satisfy alignment restrictions in the 32-bit world.
+ //
+ ChooseColorData.lpCustColors = CustColors32;
+ GETVDMPTR(ChooseColorData16->lpCustColors,
+ 16*sizeof(DWORD),
+ pCustColors16);
+ RtlCopyMemory(CustColors32, pCustColors16, sizeof(CustColors32));
+
+ if (ChooseColorData16->Flags & CC_ENABLEHOOK) {
+ ThreadData.vpfnHook = ChooseColorData16->lpfnHook;
+ ThreadData.vpData = vpcc;
+ ChooseColorData.lpfnHook = WCD32DialogProc;
+ }
+
+ if (ChooseColorData16->Flags & CC_ENABLETEMPLATE) {
+
+ hRes = GetTemplate16(ChooseColorData16->hInstance,
+ ChooseColorData16->lpTemplateName,
+ FALSE);
+
+ // memory may have moved
+ FREEVDMPTR( pCustColors16 );
+ FREEVDMPTR( ChooseColorData16 );
+
+ if (hRes==NULL) {
+ ul = GETBOOL16(FALSE);
+ goto ChooseColorError;
+ }
+
+ ChooseColorData.hInstance = (HWND)LockResource16(hRes);
+ ChooseColorData.Flags &= ~CC_ENABLETEMPLATE;
+ ChooseColorData.Flags |= CC_ENABLETEMPLATEHANDLE;
+ } else if (ChooseColorData16->Flags & CC_ENABLETEMPLATEHANDLE) {
+
+ ChooseColorData.hInstance=(HWND)GetTemplate16(ChooseColorData16->hInstance,
+ (VPCSTR)NULL,
+ TRUE);
+
+ // memory may have moved
+ FREEVDMPTR( pCustColors16 );
+ FREEVDMPTR( ChooseColorData16 );
+ }
+
+ WCDDUMPCHOOSECOLORDATA32(&ChooseColorData);
+
+ FREEVDMPTR( pCustColors16 );
+ FREEVDMPTR( ChooseColorData16 );
+
+ ul = GETBOOL16(ChooseColor(&ChooseColorData));
+
+ GETVDMPTR(vpcc, sizeof(*ChooseColorData16), ChooseColorData16);
+ GETVDMPTR(ChooseColorData16->lpCustColors,
+ 16*sizeof(DWORD),
+ pCustColors16);
+
+ if (ul) {
+ WCDDUMPCHOOSECOLORDATA32(&ChooseColorData);
+
+ STOREDWORD(ChooseColorData16->rgbResult, ChooseColorData.rgbResult);
+ RtlCopyMemory(pCustColors16, CustColors32, sizeof(CustColors32));
+
+ WCDDUMPCHOOSECOLORDATA16(ChooseColorData16);
+
+ FLUSHVDMPTR(vpcc, sizeof(*ChooseColorData16), ChooseColorData16);
+ FLUSHVDMPTR(ChooseColorData16->lpCustColors, 16*sizeof(COLORREF), ChooseColorData.lpCustColors);
+
+ } else {
+ LOGDEBUG(1, ("CHOOSECOLOR32 Failed - Extended Error %08lx\n",CommDlgExtendedError()));
+ }
+
+ if (ChooseColorData16->Flags & CC_ENABLETEMPLATE) {
+ UnlockResource16(hRes);
+ FreeResource16(hRes);
+ } else if ((ChooseColorData16->Flags & CC_ENABLETEMPLATEHANDLE) &&
+ (ChooseColorData.hInstance != NULL)) {
+ free_w((PVOID)ChooseColorData.hInstance);
+ }
+
+ChooseColorError:
+ FREEVDMPTR( pCustColors16 );
+ FREEVDMPTR( ChooseColorData16 );
+ FREEARGPTR( parg16 );
+
+ CURRENTPTD()->CommDlgTd = ThreadData.Previous;
+
+ return(ul);
+
+}
+
+ULONG FASTCALL WCD32ChooseFont( PVDMFRAME pFrame )
+
+/*++
+
+Routine Description:
+
+ This routine thunks the 16-bit ChooseFont common dialog to the 32-bit
+ side.
+
+Arguments:
+
+ pFrame - Supplies 16-bit argument frame
+
+Return Value:
+
+ 16-bit BOOLEAN to be returned.
+
+--*/
+{
+ ULONG ul;
+ register PCHOOSEFONT16 parg16;
+ VPCHOOSEFONTDATA vpcf;
+ CHOOSEFONT ChooseFontData;
+ LOGFONT LogFont;
+ PCHOOSEFONTDATA16 ChooseFontData16;
+ PRES hRes;
+ COMMDLGTD ThreadData;
+
+ GETARGPTR(pFrame, sizeof(CHOOSEFONT16), parg16);
+ vpcf = parg16->lpcf;
+ GETVDMPTR(vpcf, sizeof(*ChooseFontData16), ChooseFontData16);
+
+ SETEXTENDEDERROR( 0 );
+ ThreadData.Previous = CURRENTPTD()->CommDlgTd;
+ ThreadData.hdlg = (HWND16)-1;
+ ThreadData.pData32 = NULL;
+ ThreadData.Flags = WOWCD_ISCHOOSEFONT;
+ CURRENTPTD()->CommDlgTd = &ThreadData;
+
+ if (msgWOWCHOOSEFONT == 0) {
+ //
+ // initialize private WOW<->comdlg32 message for handling
+ // WM_CHOOSEFONT_GETLOGFONT
+ //
+ msgWOWCHOOSEFONT = RegisterWindowMessage("WOWCHOOSEFONT_GETLOGFONT");
+ }
+
+ if (msgWOWLFCHANGE == 0) {
+
+ // initialize private message for thunking logfont changes
+ msgWOWLFCHANGE = RegisterWindowMessage("WOWLFChange");
+ }
+
+ WCDDUMPCHOOSEFONTDATA16(ChooseFontData16);
+
+ ChooseFontData.lStructSize = sizeof(CHOOSEFONT);
+ ChooseFontData.hwndOwner = HWND32(ChooseFontData16->hwndOwner);
+ ChooseFontData.Flags = DWORD32(ChooseFontData16->Flags) | CD_WOWAPP;
+ if (ChooseFontData16->Flags & CF_PRINTERFONTS) {
+ ChooseFontData.hDC = HDC32(ChooseFontData16->hDC);
+ }
+ GETPSZPTR(ChooseFontData16->lpszStyle,ChooseFontData.lpszStyle);
+ if (ChooseFontData16->Flags & CF_INITTOLOGFONTSTRUCT) {
+ GETLOGFONT16(ChooseFontData16->lpLogFont, &LogFont);
+ }
+ if (ChooseFontData16->Flags & CF_ENABLEHOOK) {
+ ThreadData.vpfnHook = ChooseFontData16->lpfnHook;
+ ThreadData.vpData = vpcf;
+ ChooseFontData.lpfnHook = WCD32DialogProc;
+ }
+ ChooseFontData.rgbColors = DWORD32(ChooseFontData16->rgbColors);
+
+ ChooseFontData.nFontType = WORD32(ChooseFontData16->nFontType);
+ ChooseFontData.nSizeMin = INT32(ChooseFontData16->nSizeMin);
+ ChooseFontData.nSizeMax = INT32(ChooseFontData16->nSizeMax);
+ ChooseFontData.lpLogFont = &LogFont;
+ if (ChooseFontData16->Flags & CF_ENABLETEMPLATE) {
+
+ hRes = GetTemplate16(ChooseFontData16->hInstance,
+ ChooseFontData16->lpTemplateName,
+ FALSE);
+ // Memory may have moved - invalidate the flat pointers now
+ FREEVDMPTR( ChooseFontData16 );
+ FREEVDMPTR( pFrame );
+ FREEARGPTR( parg16 );
+
+ if (hRes==NULL) {
+ ul = GETBOOL16(FALSE);
+ goto ChooseFontError;
+ }
+
+ ChooseFontData.hInstance = (HINSTANCE)LockResource16(hRes);
+ ChooseFontData.Flags &= ~CF_ENABLETEMPLATE;
+ ChooseFontData.Flags |= CF_ENABLETEMPLATEHANDLE;
+ } else if (ChooseFontData16->Flags & CF_ENABLETEMPLATEHANDLE) {
+
+ ChooseFontData.hInstance=(HINSTANCE)GetTemplate16(ChooseFontData16->hInstance,
+ (VPCSTR)NULL,
+ TRUE);
+ // Memory may have moved - invalidate the flat pointers now
+ FREEVDMPTR( ChooseFontData16 );
+ FREEVDMPTR( pFrame );
+ FREEARGPTR( parg16 );
+ }
+
+ WCDDUMPCHOOSEFONTDATA32(&ChooseFontData);
+
+ // memory may move because of ChooseFont - invalidate all flat pointers now
+ FREEVDMPTR( ChooseFontData16 );
+ FREEVDMPTR( pFrame );
+ FREEARGPTR( parg16 );
+
+ ul = GETBOOL16(ChooseFont(&ChooseFontData));
+
+ GETVDMPTR(vpcf, sizeof(*ChooseFontData16), ChooseFontData16);
+
+ if (ul) {
+ WCDDUMPCHOOSEFONTDATA32(&ChooseFontData);
+
+ ChooseFontData16->Flags &= ~CF_OUTPUTFLAGS;
+ ChooseFontData16->Flags |= ChooseFontData.Flags & CF_OUTPUTFLAGS;
+
+ STOREWORD(ChooseFontData16->iPointSize, ChooseFontData.iPointSize);
+ STOREDWORD(ChooseFontData16->rgbColors, ChooseFontData.rgbColors);
+ STOREWORD(ChooseFontData16->nFontType, ChooseFontData.nFontType);
+
+ PUTLOGFONT16(ChooseFontData16->lpLogFont, sizeof(LOGFONT),&LogFont);
+
+ WCDDUMPCHOOSEFONTDATA16(ChooseFontData16);
+
+ FLUSHVDMPTR(vpcf, sizeof(*ChooseFontData16), ChooseFontData16);
+ } else {
+ LOGDEBUG(1, ("CHOOSEFONT32 Failed - Extended Error %08lx\n",CommDlgExtendedError()));
+ }
+
+ if (ChooseFontData16->Flags & CF_USESTYLE) {
+ FLUSHVDMPTR(ChooseFontData16->lpszStyle,LF_FACESIZE,ChooseFontData.lpszStyle);
+ }
+
+ if (ChooseFontData16->Flags & CF_ENABLETEMPLATE) {
+ UnlockResource16(hRes);
+ FreeResource16(hRes);
+ } else if ((ChooseFontData16->Flags & CF_ENABLETEMPLATEHANDLE) &&
+ (ChooseFontData.hInstance != NULL)) {
+ free_w((PVOID)ChooseFontData.hInstance);
+ }
+
+ChooseFontError:
+ FREEVDMPTR( ChooseFontData16 );
+ FREEARGPTR( parg16 );
+
+ CURRENTPTD()->CommDlgTd = ThreadData.Previous;
+
+ return(ul);
+}
+
+ULONG FASTCALL WCD32GetOpenFileName( PVDMFRAME pFrame )
+
+/*++
+
+Routine Description:
+
+ This routine thunks the 16-bit GetOpenFileName common dialog to the
+ 32-bit side.
+
+Arguments:
+
+ pFrame - Supplies 16-bit argument frame
+
+Return Value:
+
+ 16-bit BOOLEAN to be returned.
+
+--*/
+{
+ return(WCD32GetFileName(pFrame,GetOpenFileName));
+}
+
+ULONG FASTCALL WCD32GetSaveFileName( PVDMFRAME pFrame )
+
+/*++
+
+Routine Description:
+
+ This routine thunks the 16-bit GetOpenFileName common dialog to the
+ 32-bit side.
+
+Arguments:
+
+ pFrame - Supplies 16-bit argument frame
+
+Return Value:
+
+ 16-bit BOOLEAN to be returned.
+
+--*/
+{
+ return(WCD32GetFileName(pFrame,GetSaveFileName));
+}
+
+ULONG FASTCALL WCD32FindText( PVDMFRAME pFrame )
+
+/*++
+
+Routine Description:
+
+ This routine thunks the 16-bit FindText common dialog to the
+ 32-bit side.
+
+Arguments:
+
+ pFrame - Supplies 16-bit argument frame
+
+Return Value:
+
+ 16-bit BOOLEAN to be returned.
+
+--*/
+{
+ return(WCD32FindReplaceText(pFrame, FindText));
+}
+
+ULONG FASTCALL WCD32ReplaceText( PVDMFRAME pFrame )
+
+/*++
+
+Routine Description:
+
+ This routine thunks the 16-bit ReplaceText common dialog to the
+ 32-bit side.
+
+Arguments:
+
+ pFrame - Supplies 16-bit argument frame
+
+Return Value:
+
+ 16-bit BOOLEAN to be returned.
+
+--*/
+{
+ return(WCD32FindReplaceText(pFrame, ReplaceText));
+}
+
+
+
+
+
+ULONG FASTCALL WCD32PrintDlg( IN PVDMFRAME pFrame )
+/*++
+
+Routine Description:
+
+ This routine thunks the 16-bit PrintDlg common dialog to the 32-bit
+ side.
+
+Arguments:
+
+ pFrame - Supplies 16-bit argument frame
+
+Return Value:
+
+ 16-bit BOOLEAN to be returned
+
+--*/
+
+{
+ ULONG ul;
+ register PPRINTDLG16 parg16;
+ VPPRINTDLGDATA vppd;
+ PRINTDLG PrintDlg32;
+ PPRINTDLGDATA16 PrintDlg16;
+ PRINTDLGDATA16 OrigDlg16;
+ PRES hSetupRes;
+ PRES hPrintRes;
+ HAND16 hDevMode16, hDevNames16;
+ COMMDLGTD ThreadData;
+ INT nSize;
+
+ GETARGPTR(pFrame, sizeof(PRINTDLG16), parg16);
+ vppd = parg16->lppd;
+ GETVDMPTR(vppd, sizeof(*PrintDlg16), PrintDlg16);
+ SETEXTENDEDERROR(0);
+
+ RtlZeroMemory((PVOID)&PrintDlg32, (DWORD)sizeof(PrintDlg32));
+
+ ThreadData.Previous = CURRENTPTD()->CommDlgTd;
+ ThreadData.hdlg = (HWND16)-1;
+ ThreadData.pData32 = NULL;
+ ThreadData.Flags = 0;
+ CURRENTPTD()->CommDlgTd = &ThreadData;
+
+ WCDDUMPPRINTDLGDATA16(PrintDlg16);
+
+ // save orignal 16bit data for later comparisons
+
+ OrigDlg16 = *PrintDlg16;
+
+ PrintDlg32.lStructSize = sizeof(PRINTDLG);
+ PrintDlg32.hwndOwner = HWND32(PrintDlg16->hwndOwner);
+ PrintDlg32.Flags = DWORD32(PrintDlg16->Flags) | CD_WOWAPP;
+ PrintDlg32.nFromPage = WORD32(PrintDlg16->nFromPage);
+ PrintDlg32.nToPage = WORD32(PrintDlg16->nToPage);
+ PrintDlg32.nMinPage = WORD32(PrintDlg16->nMinPage);
+ PrintDlg32.nMaxPage = WORD32(PrintDlg16->nMaxPage);
+ PrintDlg32.nCopies = WORD32(PrintDlg16->nCopies);
+ PrintDlg32.hDevMode = ThunkhDevMode16to32(PrintDlg16->hDevMode);
+
+ if (FETCHDWORD(PrintDlg16->hDevNames)==0L) {
+ PrintDlg32.hDevNames=NULL;
+ } else {
+ VPDEVNAMES vpDevNames;
+
+ vpDevNames = GlobalLock16(PrintDlg16->hDevNames,&nSize);
+ if (nSize==0) {
+ PrintDlg32.hDevNames=NULL;
+ } else {
+ LPDEVNAMES pdn32;
+ PDEVNAMES16 pdn16;
+
+ GETVDMPTR(vpDevNames, sizeof(DEVNAMES16),pdn16);
+ PrintDlg32.hDevNames = GlobalAlloc(GMEM_MOVEABLE,nSize);
+ if (pdn32=GlobalLock(PrintDlg32.hDevNames)) {
+ RtlCopyMemory((PVOID)pdn32,(PVOID)pdn16,nSize);
+ GlobalUnlock(PrintDlg32.hDevNames);
+ }
+ FREEVDMPTR(pdn16);
+ GlobalUnlock16(PrintDlg16->hDevNames);
+ }
+
+ }
+
+ if (PrintDlg16->Flags & PD_ENABLEPRINTTEMPLATE) {
+ hPrintRes = GetTemplate16(PrintDlg16->hInstance,
+ PrintDlg16->lpPrintTemplateName,
+ FALSE);
+ // Memory may have moved - invalidate the flat pointers now
+ FREEVDMPTR( PrintDlg16 );
+ FREEVDMPTR( pFrame );
+ FREEARGPTR( parg16 );
+
+ if (hPrintRes == NULL) {
+ ul = GETBOOL16(FALSE);
+ goto PrintDlgError;
+ }
+
+ PrintDlg32.hPrintTemplate = (HANDLE)LockResource16(hPrintRes);
+ PrintDlg32.Flags &= ~PD_ENABLEPRINTTEMPLATE;
+ PrintDlg32.Flags |= PD_ENABLEPRINTTEMPLATEHANDLE;
+
+ } else if (PrintDlg16->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) {
+
+ PrintDlg32.hPrintTemplate = (HANDLE)GetTemplate16(PrintDlg16->hPrintTemplate,
+ (VPCSTR)NULL,
+ TRUE);
+ // Memory may have moved - invalidate the flat pointers now
+ FREEVDMPTR( PrintDlg16 );
+ FREEVDMPTR( pFrame );
+ FREEARGPTR( parg16 );
+
+ }
+
+ GETVDMPTR(vppd, sizeof(*PrintDlg16), PrintDlg16);
+ if (PrintDlg16->Flags & PD_ENABLESETUPTEMPLATE) {
+ hSetupRes = GetTemplate16(PrintDlg16->hInstance,
+ PrintDlg16->lpSetupTemplateName,
+ FALSE);
+
+ // Memory may have moved - invalidate the flat pointers now
+ FREEVDMPTR( PrintDlg16 );
+ FREEVDMPTR( pFrame );
+ FREEARGPTR( parg16 );
+
+ if (hSetupRes == NULL) {
+ ul = GETBOOL16(FALSE);
+ goto PrintDlgError;
+ }
+
+ PrintDlg32.hSetupTemplate = (HANDLE)LockResource16(hSetupRes);
+ PrintDlg32.Flags &= ~PD_ENABLESETUPTEMPLATE;
+ PrintDlg32.Flags |= PD_ENABLESETUPTEMPLATEHANDLE;
+
+ } else if (PrintDlg16->Flags & PD_ENABLESETUPTEMPLATEHANDLE) {
+
+ PrintDlg32.hSetupTemplate = (HANDLE)GetTemplate16(PrintDlg16->hSetupTemplate,
+ (VPCSTR)NULL,
+ TRUE);
+
+ // Memory may have moved - invalidate the flat pointers now
+ FREEVDMPTR( PrintDlg16 );
+ FREEVDMPTR( pFrame );
+ FREEARGPTR( parg16 );
+
+ }
+
+ GETVDMPTR(vppd, sizeof(*PrintDlg16), PrintDlg16);
+ if (PrintDlg16->Flags & PD_RETURNDEFAULT) {
+ if (PrintDlg16->hDevMode || PrintDlg16->hDevNames) {
+ //
+ // spec says these must be NULL
+ //
+ SETEXTENDEDERROR(PDERR_RETDEFFAILURE);
+ ul = GETBOOL16(FALSE);
+ goto PrintDlgError;
+ } else {
+ PrintDlg32.hDevMode = NULL;
+ PrintDlg32.hDevNames = NULL;
+ }
+ }
+
+ if (PrintDlg16->Flags & PD_PRINTSETUP) {
+ if (PrintDlg16->Flags & PD_ENABLESETUPHOOK) {
+ ThreadData.vpfnHook = PrintDlg16->lpfnSetupHook;
+ ThreadData.vpfnSetupHook = (VPVOID)NULL;
+ ThreadData.vpData = vppd;
+ PrintDlg32.lpfnSetupHook = WCD32DialogProc;
+ }
+ } else {
+ if (PrintDlg16->Flags & (PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK)) {
+ ThreadData.vpfnHook = PrintDlg16->lpfnPrintHook;
+ ThreadData.vpfnSetupHook = PrintDlg16->lpfnSetupHook;
+ ThreadData.vpData = vppd;
+ PrintDlg32.lpfnPrintHook = WCD32DialogProc;
+ PrintDlg32.lpfnSetupHook = WCD32PrintSetupDialogProc;
+ }
+ }
+
+
+ WCDDUMPPRINTDLGDATA32(&PrintDlg32);
+
+ // memory may move - invalidate flat pointers now
+ FREEVDMPTR( PrintDlg16 );
+ FREEARGPTR( parg16 );
+ FREEVDMPTR( pFrame );
+
+ ul = GETBOOL16(PrintDlg(&PrintDlg32));
+
+ GETVDMPTR(vppd, sizeof(*PrintDlg16), PrintDlg16);
+
+ if (ul) {
+ WCDDUMPPRINTDLGDATA32(&PrintDlg32);
+
+ if (PrintDlg32.Flags & (PD_RETURNIC | PD_RETURNDC)) {
+ PrintDlg16->hDC = GETHDC16(PrintDlg32.hDC);
+ }
+
+ //
+ // thunk 32-bit DEVMODE structure back to 16-bit
+ //
+ // hDevXXXX16 take care of RISC alignment problems
+ hDevMode16 = PrintDlg16->hDevMode;
+ hDevNames16 = PrintDlg16->hDevNames;
+
+ ThunkhDevMode32to16(PrintDlg32.hDevMode, &hDevMode16);
+
+ // memory may move - invalidate flat pointers now
+ FREEVDMPTR( PrintDlg16 );
+ FREEARGPTR( parg16 );
+ FREEVDMPTR( pFrame );
+
+ ThunkDevNames32to16(PrintDlg32.hDevNames, &hDevNames16);
+
+ GETVDMPTR(vppd, sizeof(*PrintDlg16), PrintDlg16);
+
+ PrintDlg16->hDevMode = hDevMode16;
+ PrintDlg16->hDevNames = hDevNames16;
+
+ GlobalFree(PrintDlg32.hDevMode);
+ GlobalFree(PrintDlg32.hDevNames);
+
+ //
+ // some flags can be set on output, so propagate them back (don't
+ // propagate all the flags back because the 32-bit template flags
+ // will be different)
+ //
+ PrintDlg16->Flags &= ~PD_OUTPUTFLAGS;
+ PrintDlg16->Flags |= PrintDlg32.Flags & PD_OUTPUTFLAGS;
+ PrintDlg16->nFromPage = GETUINT16(PrintDlg32.nFromPage);
+ PrintDlg16->nToPage = GETUINT16(PrintDlg32.nToPage);
+
+
+ if (PrintDlg16->nMinPage == OrigDlg16.nMinPage) {
+ PrintDlg16->nMinPage = GETUINT16(PrintDlg32.nMinPage);
+ }
+ else {
+ // the app has updated its fields. so dont overwrite.
+ // for exampe: Adobe Photoshop updates its printdlgdata
+ // structure when it receives WM_INITDIALOG message. Since
+ // we pass a copy of the original printdlg structure to the
+ // api, this 32bit printdlg structure doesn't get updated.
+ //
+ // - Nanduri
+
+ LOGDEBUG(0, ("WOW:PrintDlg: app updated its nMinPage field\n"));
+ }
+
+ if (PrintDlg16->nMaxPage == OrigDlg16.nMaxPage) {
+ PrintDlg16->nMaxPage = GETUINT16(PrintDlg32.nMaxPage);
+ }
+ else {
+ LOGDEBUG(0, ("WOW:PrintDlg: app updated its nMaxPage field\n"));
+ }
+
+ PrintDlg16->nCopies = GETUINT16(PrintDlg32.nCopies);
+
+ WCDDUMPPRINTDLGDATA16(PrintDlg16);
+ } else {
+ LOGDEBUG(1,("PRINTDLG32 failed - Extended Error %08lx\n",CommDlgExtendedError()));
+ }
+
+ //
+ // cleanup
+ //
+ if (PrintDlg16->Flags & PD_ENABLEPRINTTEMPLATE) {
+ UnlockResource16(hPrintRes);
+ FreeResource16(hPrintRes);
+ } else if ((PrintDlg16->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) &&
+ (PrintDlg32.hPrintTemplate != NULL)) {
+ free_w(PrintDlg32.hPrintTemplate);
+ }
+ if (PrintDlg16->Flags & PD_ENABLESETUPTEMPLATE) {
+ UnlockResource16(hSetupRes);
+ FreeResource16(hSetupRes);
+ } else if ((PrintDlg16->Flags & PD_ENABLESETUPTEMPLATEHANDLE) &&
+ (PrintDlg32.hSetupTemplate != NULL)) {
+ free_w(PrintDlg32.hSetupTemplate);
+ }
+
+PrintDlgError:
+ FREEVDMPTR( PrintDlg16 );
+ FREEARGPTR( parg16 );
+ CURRENTPTD()->CommDlgTd = ThreadData.Previous;
+ return(ul);
+}
+
+
+ULONG FASTCALL WCD32ExtendedError( IN PVDMFRAME pFrame )
+
+/*++
+
+Routine Description:
+
+ 32-bit thunk for CommDlgExtendedError()
+
+Arguments:
+
+ pFrame - Supplies 16-bit argument frame
+
+Return Value:
+
+ error code to be returned
+
+--*/
+
+{
+
+ if (dwExtError != 0) {
+ return(dwExtError);
+ }
+ return(CommDlgExtendedError());
+}
+
+
+ULONG
+WCD32GetFileName(
+ IN PVDMFRAME pFrame,
+ IN FILENAMEPROC Function
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by WCD32GetOpenFileName and WCD32GetSaveFileName.
+ It does all the real thunking work.
+
+Arguments:
+
+ pFrame - Supplies 16-bit argument frame
+
+ Function - supplies a pointer to the 32-bit function to call (either
+ GetOpenFileName or GetSaveFileName)
+
+Return Value:
+
+ 16-bit BOOLEAN to be returned.
+
+--*/
+{
+ ULONG ul;
+ register PGETOPENFILENAME16 parg16;
+ VPOPENFILENAME vpof;
+ OPENFILENAME FileName;
+ POPENFILENAME16 OpenFileName16;
+ COMMDLGTD ThreadData;
+ PRES hRes;
+
+ GETARGPTR(pFrame, sizeof(GETOPENFILENAME16), parg16);
+
+ vpof = parg16->lpof;
+ GETVDMPTR(vpof, sizeof(*OpenFileName16), OpenFileName16);
+
+ SETEXTENDEDERROR(0);
+ ThreadData.Previous = CURRENTPTD()->CommDlgTd;
+ ThreadData.hdlg = (HWND16)-1;
+ ThreadData.pData32 = (PVOID)&FileName;
+ ThreadData.Flags = WOWCD_ISOPENFILE;
+ CURRENTPTD()->CommDlgTd = &ThreadData;
+ if (msgFILEOK == 0) {
+ //
+ // initialize private WOW-comdlg32 message
+ //
+ msgWOWDIRCHANGE = RegisterWindowMessage("WOWDirChange");
+
+ //
+ // initialize unique window messages
+ //
+ msgSHAREVIOLATION = RegisterWindowMessage(SHAREVISTRING);
+ msgFILEOK = RegisterWindowMessage(FILEOKSTRING);
+
+ }
+
+ WCDDUMPOPENFILENAME16(OpenFileName16);
+
+ ThunkOpenFileName16to32(OpenFileName16, &FileName);
+
+ // This is a hack to fix a bug in Win3.1 commdlg.dll.
+ // Win3.1 doesn't check nMaxFileTitle before copying the FileTitle string.
+ // This should be the correct place to put this since Win3.1 implements all
+ // the GetOpenFileName() type api's in terms of GetFileName() too.
+ // (see Win3.1 src's \\pucus\win31aro\src\sdk\commdlg\fileopen.c)
+ // TaxCut'95 depends on the title string being returned.
+ if(FileName.lpstrFileTitle) {
+
+ // if nMaxFileTitle > 0, NT will copy lpstrFileTitle
+ if(FileName.nMaxFileTitle == 0) {
+ WOW32WARNMSG(FALSE, ("WOW:nMaxFileTitle compatibility hack hit\n"));
+ FileName.nMaxFileTitle = 13; // 8.3 filename + NULL
+ }
+ }
+
+ //
+ // make sure the current directory is up to date
+ //
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+ if (FileName.Flags & OFN_ENABLETEMPLATE) {
+ hRes = GetTemplate16(OpenFileName16->hInstance,
+ OpenFileName16->lpTemplateName,
+ FALSE);
+ // Memory may have moved - invalidate the flat pointers now
+ FREEVDMPTR( OpenFileName16 );
+ FREEARGPTR( parg16 );
+ FREEVDMPTR( pFrame );
+
+ if (!hRes) {
+ ul = GETBOOL16(FALSE);
+ goto Error;
+ }
+
+ FileName.hInstance = (HINSTANCE)LockResource16(hRes);
+ FileName.Flags &= ~OFN_ENABLETEMPLATE;
+ FileName.Flags |= OFN_ENABLETEMPLATEHANDLE;
+ } else if (FileName.Flags & OFN_ENABLETEMPLATEHANDLE) {
+
+ FileName.hInstance = (HINSTANCE)GetTemplate16(OpenFileName16->hInstance,
+ OpenFileName16->lpTemplateName,
+ TRUE);
+ // memory may have moved - re-fetch flat pointers now
+ FREEVDMPTR( OpenFileName16 );
+ FREEARGPTR( parg16 );
+ FREEVDMPTR( pFrame );
+ }
+ if (FileName.Flags & OFN_ENABLEHOOK) {
+ GETVDMPTR(vpof, sizeof(*OpenFileName16), OpenFileName16);
+ ThreadData.vpfnHook = OpenFileName16->lpfnHook;
+ ThreadData.vpData = vpof;
+ FileName.lpfnHook = WCD32DialogProc;
+ }
+
+ // memory may move - free flat pointers now
+ FREEVDMPTR( OpenFileName16 );
+ FREEARGPTR( parg16 );
+ FREEVDMPTR( pFrame );
+
+ WCDDUMPOPENFILENAME32(&FileName);
+
+ ul = GETBOOL16((*Function)(&FileName));
+
+ WCDDUMPOPENFILENAME32(&FileName);
+
+ UpdateDosCurrentDirectory(DIR_NT_TO_DOS);
+
+ //
+ // get new vdm pointers, because autocad/win changes its selectors
+ // in its hookproc
+ //
+
+ GETVDMPTR(vpof, sizeof(*OpenFileName16), OpenFileName16);
+
+ if (ul) {
+ ThunkOpenFileName32to16(&FileName, OpenFileName16, TRUE);
+ } else if (CommDlgExtendedError()==FNERR_BUFFERTOOSMALL) {
+ FLUSHVDMPTR(OpenFileName16->lpstrFile,
+ sizeof(DWORD),
+ FileName.lpstrFile);
+ }
+
+ WCDDUMPOPENFILENAME16(OpenFileName16);
+
+ //
+ // clean up
+ //
+ if (OpenFileName16->Flags & OFN_ENABLETEMPLATE) {
+ UnlockResource16(hRes);
+ FreeResource16(hRes);
+ } else if ((OpenFileName16->Flags & OFN_ENABLETEMPLATEHANDLE) &&
+ (FileName.hInstance != NULL)) {
+ free_w((PVOID)FileName.hInstance);
+ }
+
+Error:
+
+ FREEVDMPTR( OpenFileName16 );
+ FREEARGPTR( parg16 );
+
+ CURRENTPTD()->CommDlgTd = ThreadData.Previous;
+
+ return(ul);
+}
+
+
+
+VOID
+ThunkOpenFileName16to32(
+ IN POPENFILENAME16 FileName16,
+ OUT OPENFILENAME *FileName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine thunks a 16-bit OPENFILENAME structure to the 32-bit
+ structure
+
+Arguments:
+
+ FileName16 - Supplies a pointer to the 16-bit structure.
+
+ Thunk - Supplies a pointer to the 32-bit structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ FileName->lStructSize = sizeof(OPENFILENAME);
+ FileName->hwndOwner = HWND32(FileName16->hwndOwner);
+ GETPSZPTR(FileName16->lpstrFilter, FileName->lpstrFilter);
+ GETPSZPTR(FileName16->lpstrCustomFilter, FileName->lpstrCustomFilter);
+ FileName->nMaxCustFilter = DWORD32(FileName16->nMaxCustFilter);
+ FileName->nFilterIndex = DWORD32(FileName16->nFilterIndex);
+ GETPSZPTR(FileName16->lpstrFile, FileName->lpstrFile);
+ FileName->nMaxFile = DWORD32(FileName16->nMaxFile);
+ GETPSZPTR(FileName16->lpstrFileTitle, FileName->lpstrFileTitle);
+ FileName->nMaxFileTitle = DWORD32(FileName16->nMaxFileTitle);
+ GETPSZPTR(FileName16->lpstrInitialDir, FileName->lpstrInitialDir);
+ GETPSZPTR(FileName16->lpstrTitle, FileName->lpstrTitle);
+ FileName->Flags = DWORD32(FileName16->Flags) | OFN_NOLONGNAMES | CD_WOWAPP;
+ GETPSZPTR(FileName16->lpstrDefExt, FileName->lpstrDefExt);
+}
+
+
+
+
+
+
+VOID
+ThunkhDevMode32to16(
+ IN HANDLE hDevMode32,
+ IN OUT HAND16 *phDevMode16
+ )
+
+/*++
+
+Routine Description:
+
+ This routine thunks a 32-bit DevMode structure back into the 16-bit one.
+ It will reallocate the 16-bit global memory block as necessary.
+
+ WARNING: This may cause 16-bit memory to move, invalidating flat pointers.
+
+Arguments:
+
+ hDevMode - Supplies a handle to a movable global memory object that
+ contains a 32-bit DEVMODE structure
+
+ phDevMode16 - Supplies a pointer to a 16-bit handle to a movable global
+ memory object that will return the 16-bit DEVMODE structure.
+ If the handle is NULL, the object will be allocated. It
+ may also be reallocated if its current size is not enough.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ UINT CurrentSize;
+ UINT RequiredSize;
+ VPDEVMODE31 vpDevMode16;
+ LPDEVMODE lpDevMode32;
+
+ if (hDevMode32 == NULL) {
+ *phDevMode16 = (HAND16)NULL;
+ return;
+ }
+
+ lpDevMode32 = GlobalLock(hDevMode32);
+ if (lpDevMode32==NULL) {
+ *phDevMode16 = (HAND16)NULL;
+ return;
+ }
+
+ RequiredSize = lpDevMode32->dmSize +
+ lpDevMode32->dmDriverExtra +
+ sizeof(WOWDM31); // see notes in wstruc.c
+
+ if (*phDevMode16 == (HAND16)NULL) {
+ vpDevMode16 = GlobalAllocLock16(GMEM_MOVEABLE,
+ RequiredSize,
+ phDevMode16);
+ } else {
+ vpDevMode16 = GlobalLock16(*phDevMode16, &CurrentSize);
+
+ if (CurrentSize < RequiredSize) {
+ GlobalUnlockFree16(vpDevMode16);
+ vpDevMode16 = GlobalAllocLock16(GMEM_MOVEABLE,
+ RequiredSize,
+ phDevMode16);
+ }
+ }
+
+ if(ThunkDevMode32to16(vpDevMode16, lpDevMode32, RequiredSize)) {
+ GlobalUnlock16(*phDevMode16);
+ }
+ else {
+ *phDevMode16 = (HAND16)NULL;
+ }
+
+ GlobalUnlock(hDevMode32);
+
+ return;
+}
+
+
+
+
+
+HGLOBAL ThunkhDevMode16to32(HAND16 hDevMode16)
+{
+ INT nSize;
+ LPDEVMODE lpdm32, pdm32;
+ HGLOBAL hDevMode32 = NULL;
+ VPDEVMODE31 vpDevMode16;
+
+ if (hDevMode16) {
+
+ vpDevMode16 = GlobalLock16(hDevMode16, NULL);
+
+ if(FETCHDWORD(vpDevMode16)) {
+
+ if(pdm32 = ThunkDevMode16to32(vpDevMode16)) {
+
+ nSize = FETCHWORD(pdm32->dmSize) +
+ FETCHWORD(pdm32->dmDriverExtra);
+
+ hDevMode32 = GlobalAlloc(GMEM_MOVEABLE, nSize);
+
+ if(lpdm32 = GlobalLock(hDevMode32)) {
+ RtlCopyMemory((PVOID)lpdm32, (PVOID)pdm32, nSize);
+ GlobalUnlock(hDevMode32);
+ }
+
+ free_w(pdm32);
+ }
+ GlobalUnlock16(hDevMode16);
+ }
+ }
+
+ return(hDevMode32);
+}
+
+
+
+
+
+VOID
+ThunkDevNames32to16(
+ IN HANDLE hDevNames,
+ IN OUT HAND16 *phDevNames16
+ )
+
+/*++
+
+Routine Description:
+
+ This routine thunks a 32-bit DevNames structure back into the 16-bit one.
+ It will reallocate the 16-bit global memory block as necessary.
+
+ WARNING: This may cause 16-bit memory to move, invalidating flat pointers.
+
+Arguments:
+
+ hDevNames - Supplies a handle to a movable global memory object that
+ contains a 32-bit DEVNAMES structure
+
+ phDevNames16 - Supplies a pointer to a 16-bit handle to a movable global
+ memory object that will return the 16-bit DEVNAMES structure.
+ If the handle is NULL, the object will be allocated. It
+ may also be reallocated if its current size is not enough.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ UINT CurrentSize;
+ UINT RequiredSize;
+ UINT CopySize;
+ UINT MaxOffset;
+ PDEVNAMES16 pdn16;
+ VPDEVNAMES DevNames16;
+ LPDEVNAMES DevNames32;
+
+ if (hDevNames==NULL) {
+ *phDevNames16=(HAND16)NULL;
+ return;
+ }
+
+ DevNames32 = GlobalLock(hDevNames);
+ if (DevNames32==NULL) {
+ *phDevNames16=(HAND16)NULL;
+ }
+ MaxOffset = max(max(DevNames32->wDriverOffset,DevNames32->wDeviceOffset),
+ DevNames32->wOutputOffset);
+
+ // ProComm Plus copies 0x48 constant bytes after Print Setup.
+ CopySize = MaxOffset + strlen((PCHAR)DevNames32+MaxOffset) + 1;
+ RequiredSize = max(CopySize, 0x48);
+
+ if (*phDevNames16==(HAND16)NULL) {
+ DevNames16 = GlobalAllocLock16(GMEM_MOVEABLE,
+ RequiredSize,
+ phDevNames16);
+ } else {
+ DevNames16 = GlobalLock16(*phDevNames16, &CurrentSize);
+ if (CurrentSize < RequiredSize) {
+ GlobalUnlockFree16(DevNames16);
+ DevNames16 = GlobalAllocLock16(GMEM_MOVEABLE,
+ RequiredSize,
+ phDevNames16);
+ }
+ }
+
+ GETVDMPTR(DevNames16, RequiredSize, pdn16);
+ if (pdn16==NULL) {
+ *phDevNames16=(HAND16)NULL;
+ GlobalUnlock(hDevNames);
+ return;
+ }
+ RtlCopyMemory(pdn16,DevNames32,CopySize);
+ FLUSHVDMPTR(DevNames16,RequiredSize, pdn16);
+ FREEVDMPTR(pdn16);
+ GlobalUnlock16(*phDevNames16);
+ GlobalUnlock(hDevNames);
+}
+
+
+
+VOID
+ThunkOpenFileName32to16(
+ IN OPENFILENAME *FileName,
+ OUT POPENFILENAME16 FileName16,
+ IN BOOLEAN bUpperStrings
+ )
+
+/*++
+
+Routine Description:
+
+ This routine thunks a 32-bit OPENFILENAME structure back to the 16-bit
+ structure.
+
+Arguments:
+
+ FileName - Supplies a pointer to the 32-bit thunk.
+
+ FileName16 - Supplies a pointer to the 16-bit OPENFILENAME structure,
+ which will be initialized with the data in the 32-bit
+ thunk.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD Length;
+
+ WOW32ASSERT(FileName != NULL);
+ FileName16->nFileOffset = FileName->nFileOffset;
+ FileName16->nFileExtension = FileName->nFileExtension;
+ FileName16->nFilterIndex = FileName->nFilterIndex;
+ FileName16->Flags &= ~FO_OUTPUTFLAGS;
+ FileName16->Flags |= FileName->Flags & FO_OUTPUTFLAGS;
+
+ //
+ // The selectors may have moved (autocad does this) so we
+ // need to get all the vdm pointers again here before trying
+ // to touch the 32-bit flat pointers.
+ //
+ GETPSZPTR(FileName16->lpstrFile, FileName->lpstrFile);
+ GETPSZPTR(FileName16->lpstrFileTitle, FileName->lpstrFileTitle);
+ GETPSZPTR(FileName16->lpstrFilter, FileName->lpstrFilter);
+
+ if (FileName->lpstrFilter != NULL) {
+ FLUSHVDMPTR(FileName16->lpstrFilter,
+ strlen(FileName->lpstrFilter),
+ FileName->lpstrFilter);
+ }
+ if (bUpperStrings && (FileName->lpstrFile != NULL)) {
+ //
+ // Note we have to upcase the filename here because some apps
+ // (notably QC/Win) do case-sensitive compares on the extension.
+ // In Win3.1, the upcasing happens as a side-effect of the
+ // OpenFile call. Here we do it explicitly.
+ //
+ Length = strlen(FileName->lpstrFile);
+
+ CharUpperBuff(FileName->lpstrFile,Length+1);
+ FLUSHVDMPTR(FileName16->lpstrFile,
+ (USHORT)Length,
+ FileName->lpstrFile);
+ }
+ if (bUpperStrings && (FileName->lpstrFileTitle)) {
+ //
+ // Not sure if we really need to upcase this or not, but I figure
+ // somewhere there is an app that depends on this being uppercased
+ // like Win3.1
+ //
+ Length = strlen(FileName->lpstrFileTitle);
+
+ CharUpperBuff(FileName->lpstrFileTitle,Length+1);
+
+ FLUSHVDMPTR(FileName16->lpstrFileTitle,
+ (USHORT)Length,
+ FileName->lpstrFileTitle);
+ }
+
+}
+
+
+PRES
+GetTemplate16(
+ IN HAND16 hInstance,
+ IN VPCSTR lpTemplateName,
+ IN BOOLEAN UseHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Finds and loads the specified 16-bit dialog template.
+
+ WARNING: This may cause memory movement, invalidating flat pointers
+
+Arguments:
+
+ hInstance - Supplies the data block containing the dialog box template
+
+ TemplateName - Supplies the name of the resource file for the dialog
+ box template. This may be either a null-terminated string or
+ a numbered resource created with the MAKEINTRESOURCE macro.
+
+ UseHandle - Indicates that hInstance identifies a pre-loaded dialog
+ box template. If this is TRUE, Templatename is ignored.
+
+Return Value:
+
+ success - A pointer to the loaded resource
+
+ failure - NULL, dwLastError will be set.
+
+--*/
+
+{
+ LPSZ TemplateName=NULL;
+ PRES hRes;
+ PBYTE pDlg=NULL;
+ INT cb, cb16;
+
+ if (!UseHandle) {
+
+ GETPSZIDPTR(lpTemplateName, TemplateName);
+
+ //
+ // Both custom instance handle and the dialog template name are
+ // specified. Locate the 16-bit dialog resource in the specified
+ // instance block and load it.
+ //
+ hRes = FindResource16(hInstance,
+ TemplateName,
+ (LPSZ)RT_DIALOG);
+ if (HIWORD(lpTemplateName) != 0) {
+ FREEVDMPTR(TemplateName);
+ }
+ if (!hRes) {
+ SETEXTENDEDERROR( CDERR_FINDRESFAILURE );
+ return(NULL);
+ }
+ if (!(hRes = LoadResource16(hInstance,hRes))) {
+ SETEXTENDEDERROR( CDERR_LOADRESFAILURE );
+ return(NULL);
+ }
+
+ return(hRes);
+ } else {
+ VPVOID pDlg16;
+
+ if (pDlg16 = RealLockResource16(hInstance, &cb16)) {
+ cb = ConvertDialog16(NULL, pDlg16, 0, cb16);
+ if (cb != 0) {
+ if (pDlg = malloc_w(cb)) {
+ ConvertDialog16(pDlg, pDlg16, cb, cb16);
+ }
+ }
+ GlobalUnlock16(hInstance);
+ }
+ return((PRES)pDlg);
+ }
+
+}
+
+
+PCOMMDLGTD
+GetCommdlgTd(
+ IN HWND Hwnd32
+ )
+
+/*++
+
+Routine Description:
+
+ Searches the thread's chain of commdlg data for the given 32-bit window.
+ If the window is not already in the chain, it is added.
+
+Arguments:
+
+ Hwnd32 - Supplies the 32-bit hwnd that the dialog procedure was called
+ with.
+
+Return Value:
+
+ Pointer to commdlg data.
+
+--*/
+
+{
+ PCOMMDLGTD Data;
+
+ if ((Data = CURRENTPTD()->CommDlgTd) == NULL) {
+ return(Data);
+ }
+
+ while (Data->hdlg != GETHWND16(Hwnd32)) {
+ Data = Data->Previous;
+ if (Data==NULL) {
+
+ //
+ // hwnd not found, this must be the first dialog callback for
+ // this hwnd. Search through the chain until we find a
+ // commdlg data with a hwnd == -1 (unused). This one will
+ // be ours. Initialize it and return.
+ //
+
+ Data = CURRENTPTD()->CommDlgTd;
+ while (Data->hdlg != (HWND16)-1) {
+ Data = Data->Previous;
+ WOW32ASSERT(Data != NULL);
+ }
+ Data->hdlg = GETHWND16(Hwnd32);
+ return(Data);
+ }
+ }
+
+ return(Data);
+}
+
+VOID
+ThunkFindReplace16to32(
+ IN PFINDREPLACE16 FindReplace16,
+ OUT FINDREPLACE *FindReplace
+ )
+/*++
+
+Routine Description:
+
+ This routine thunks a 16-bit FINDREPLACE structure to the 32-bit
+ structure
+
+Arguments:
+
+ FindReplace16 - Supplies a pointer to the 16-bit structure.
+
+ FindReplace - Supplies a pointer to the 32-bit structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FindReplace->lStructSize = sizeof(FINDREPLACE);
+ FindReplace->hwndOwner = HWND32(FindReplace16->hwndOwner);
+ FindReplace->hInstance = (HINSTANCE)(FindReplace16->hInstance);
+ FindReplace->Flags = DWORD32(FindReplace16->Flags);
+
+ strncpy(FindReplace->lpstrFindWhat,
+ VDMPTR(FindReplace16->lpstrFindWhat, FindReplace16->wFindWhatLen),
+ FindReplace16->wFindWhatLen);
+
+ strncpy(FindReplace->lpstrReplaceWith,
+ VDMPTR(FindReplace16->lpstrReplaceWith, FindReplace16->wReplaceWithLen),
+ FindReplace16->wReplaceWithLen);
+
+ FindReplace->wFindWhatLen = FindReplace16->wFindWhatLen;
+ FindReplace->wReplaceWithLen = FindReplace16->wReplaceWithLen;
+ FindReplace->lCustData = FindReplace16->lCustData;
+ FindReplace->lpfnHook = NULL;
+ GETPSZPTR(FindReplace16->lpTemplateName, FindReplace->lpTemplateName);
+}
+
+ULONG
+WCD32FindReplaceText(
+ IN PVDMFRAME pFrame,
+ IN FINDREPLACEPROC Function
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by WCD32FindText and WCD32RepalceText.
+ It copies a 16-bit FINDREPLACE structure to a 32-bit structure.
+ Two per thread data entries are maintained. One is indexed by the
+ owner hwnd, the other is indexed by the dialog hwnd. The dialog is
+ always hooked by WCD32FindReplaceDialogProc, which dispatches to the
+ 16-bit hookproc, and takes care of clean on WM_DESTROY, with dialog
+ per thread data providing context. WCD32UpdateFindReplaceTextAndFlags
+ updates the 16-bit FINDREPLACE structure when called by the WOW message
+ dispatching logic upon reciept of a WM_WOWNOTIFY message from COMDLG32.
+ The owner per thread data provides context for this operation.
+
+Arguments:
+
+ pFrame - Supplies 16-bit argument frame
+
+ Function - supplies a pointer to the 32-bit function to call (either
+ FindText or RepalceText)
+
+Return Value:
+
+ 16-bit BOOLEAN to be returned.
+
+--*/
+{
+ register PFINDTEXT16 parg16;
+ VPFINDREPLACE vpfr;
+ LPFINDREPLACE lpfr = NULL;
+ PFINDREPLACE16 FindReplace16;
+ PCOMMDLGTD ptdDlg = NULL, ptdOwner = NULL;
+ HWND hwndDlg;
+ PRES hRes;
+
+ // WCD32UpdateFindReplaceTextAndFlags will update the 16-bit FINDREPLACE
+ // struct and help thunk the WM_WOWNOTIFY message to the
+ // "commdlg_FindReplace" registered message.
+ if (msgFINDREPLACE == 0) {
+ msgFINDREPLACE = RegisterWindowMessage(FINDMSGSTRING);
+ }
+
+ GETARGPTR(pFrame, sizeof(GETFindReplace16), parg16);
+
+ vpfr = (VPFINDREPLACE)FETCHDWORD(parg16->lpfr);
+ GETVDMPTR(vpfr, sizeof(*FindReplace16), FindReplace16);
+
+ SETEXTENDEDERROR(0);
+
+ if ((lpfr = (LPFINDREPLACE) malloc_w_zero(sizeof(*lpfr))) != NULL) {
+ lpfr->lpstrFindWhat = (LPTSTR) malloc_w(FindReplace16->wFindWhatLen);
+ lpfr->lpstrReplaceWith = (LPTSTR) malloc_w(FindReplace16->wReplaceWithLen);
+ }
+ ptdDlg = (PCOMMDLGTD) malloc_w_zero(sizeof(*ptdDlg));
+ ptdOwner = (PCOMMDLGTD) malloc_w_zero(sizeof(*ptdOwner));
+
+ if (((lpfr) && (lpfr->lpstrFindWhat) && (lpfr->lpstrReplaceWith) &&
+ (ptdDlg) && (ptdOwner)) == FALSE) {
+ goto Error;
+ LOGDEBUG(0, ("WCD32FindReplaceText, 32-bit memory allocation failed!\n"));
+ }
+
+ // Link both per thread data structs into the list
+ ptdDlg->Previous = CURRENTPTD()->CommDlgTd;
+ ptdOwner->Previous = ptdDlg;
+ CURRENTPTD()->CommDlgTd = ptdOwner;
+
+ ptdDlg->pData32 = ptdOwner->pData32 = (PVOID)lpfr;
+ ptdDlg->vpData = ptdOwner->vpData = vpfr;
+
+ WCDDUMPFINDREPLACE16(FindReplace16);
+
+ ThunkFindReplace16to32(FindReplace16, lpfr);
+
+ // Set the per thread data indicies
+ ptdDlg->hdlg = (HWND16)-1;
+ ptdOwner->hdlg = FindReplace16->hwndOwner;
+
+ // If 16-bit dlg hook is spec'ed, set it up.
+ if (FindReplace16->Flags & FR_ENABLEHOOK) {
+ ptdDlg->vpfnHook = ptdOwner->vpfnHook = FindReplace16->lpfnHook;
+ }
+
+ if (FindReplace16->Flags & FR_ENABLETEMPLATE) {
+ hRes = GetTemplate16(FindReplace16->hInstance,
+ FindReplace16->lpTemplateName,
+ FALSE);
+ if (!hRes) {
+ goto Error;
+ }
+
+ lpfr->hInstance = (HINSTANCE)LockResource16(hRes);
+ lpfr->Flags &= ~FR_ENABLETEMPLATE;
+ lpfr->Flags |= FR_ENABLETEMPLATEHANDLE;
+ ptdDlg->pRes = (PVOID) hRes;
+ } else if (FindReplace16->Flags & FR_ENABLETEMPLATEHANDLE) {
+
+ lpfr->hInstance = (HINSTANCE)GetTemplate16(FindReplace16->hInstance,
+ FindReplace16->lpTemplateName,
+ TRUE);
+ }
+
+ // memory may move - free flat pointers now
+ FREEVDMPTR(FindReplace16);
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+ lpfr->Flags |= FR_ENABLEHOOK | CD_WOWAPP;
+ lpfr->lpfnHook = WCD32FindReplaceDialogProc;
+
+ hwndDlg = (*Function)(lpfr);
+
+ if (hwndDlg) {
+ ptdDlg->hdlg = (HWND16)hwndDlg;
+ } else {
+Error:
+ LOGDEBUG(0, ("WCD32FindReplaceText, Failed!\n"));
+ CURRENTPTD()->CommDlgTd = ptdDlg->Previous;
+ if (lpfr) {
+ if (lpfr->lpstrFindWhat) free_w(lpfr->lpstrFindWhat);
+ if (lpfr->lpstrReplaceWith) free_w(lpfr->lpstrReplaceWith);
+ free_w(lpfr);
+ }
+ if (ptdDlg) free_w(ptdDlg);
+ if (ptdOwner) free_w(ptdOwner);
+ return(GETHWND16(0));
+ }
+
+ return(GETHWND16(hwndDlg));
+}
+
+UINT APIENTRY
+WCD32FindReplaceDialogProc(
+ HWND hdlg,
+ UINT uMsg,
+ WPARAM uParam,
+ LPARAM lParam
+ )
+/*++
+
+Routine Description:
+
+ This is the hook proc used by FindText and ReplaceText. It does cleanup
+ on WM_DESTROY and calls WCD32CommonDialogProc to handle the 16-bit
+ dialog hook callback on all messages, if needed.
+
+--*/
+
+{
+ PFINDREPLACE16 FindReplace16;
+ VPFINDREPLACE vpfr;
+ LPFINDREPLACE lpfr;
+ PCOMMDLGTD ptdDlg, ptdOwner;
+ UINT uRet = FALSE;
+
+ // If the ptdDlg is invalid, do nothing.
+ if ((ptdDlg = GetCommdlgTd(hdlg)) == NULL) {
+ return(uRet);
+ }
+
+ if (uMsg != WM_DESTROY) {
+
+ if (ptdDlg->vpfnHook) {
+
+ uRet = WCD32CommonDialogProc(hdlg,
+ uMsg,
+ uParam,
+ lParam,
+ ptdDlg,
+ ptdDlg->vpfnHook);
+ }
+ }
+ else {
+
+ // CleanUp template if used.
+ vpfr = ptdDlg->vpData;
+ GETVDMPTR(vpfr, sizeof(*FindReplace16), FindReplace16);
+ lpfr = (LPFINDREPLACE)ptdDlg->pData32;
+
+ if (FindReplace16->Flags & FR_ENABLETEMPLATE) {
+ UnlockResource16((PRES)ptdDlg->pRes);
+ FreeResource16((PRES)ptdDlg->pRes);
+ } else if ((FindReplace16->Flags & FR_ENABLETEMPLATEHANDLE) &&
+ (lpfr->hInstance != NULL)) {
+ free_w(lpfr->hInstance);
+ }
+
+ FREEVDMPTR(FindReplace16);
+
+ // UnLink both per thread data structs from the list.
+ ptdOwner = GetCommdlgTd(lpfr->hwndOwner);
+ CURRENTPTD()->CommDlgTd = ptdDlg->Previous;
+ WOW32ASSERT(ptdOwner->Previous == ptdDlg);
+
+ // Free the per thread data structs.
+ free_w(ptdDlg);
+ free_w(ptdOwner);
+
+ // Free the 32-bit FINDREPLACE structure.
+ free_w(lpfr->lpstrFindWhat);
+ free_w(lpfr->lpstrReplaceWith);
+ free_w(lpfr);
+ }
+
+ if (uMsg == WM_INITDIALOG) {
+ // Force COMDLG32!FindReplaceDialogProc to handle WM_INITDIALOG.
+ uRet = TRUE;
+ }
+
+ return(uRet);
+}
+
+LONG APIENTRY
+WCD32UpdateFindReplaceTextAndFlags(
+ HWND hwndOwner,
+ LPARAM lParam
+ )
+{
+ PCOMMDLGTD ptdOwner;
+ PFINDREPLACE16 FindReplace16;
+ VPFINDREPLACE vpfr;
+ LPFINDREPLACE lpfr = (LPFINDREPLACE) lParam;
+ LONG lRet = 0;
+
+ ptdOwner = GetCommdlgTd(hwndOwner);
+ vpfr = ptdOwner->vpData;
+ GETVDMPTR(vpfr, sizeof(*FindReplace16), FindReplace16);
+
+ // Update the 16-bit structure.
+ FindReplace16->Flags &= ~FR_OUTPUTFLAGS;
+ FindReplace16->Flags |= lpfr->Flags & FR_OUTPUTFLAGS;
+
+ strncpy(VDMPTR(FindReplace16->lpstrFindWhat, FindReplace16->wFindWhatLen),
+ lpfr->lpstrFindWhat, FindReplace16->wFindWhatLen);
+ strncpy(VDMPTR(FindReplace16->lpstrReplaceWith, FindReplace16->wReplaceWithLen),
+ lpfr->lpstrReplaceWith, FindReplace16->wReplaceWithLen);
+
+ WCDDUMPFINDREPLACE16(FindReplace16);
+
+ FREEVDMPTR(FindReplace16);
+
+ return(vpfr);
+}
diff --git a/private/mvdm/wow32/wcommdlg.h b/private/mvdm/wow32/wcommdlg.h
new file mode 100644
index 000000000..b0581f851
--- /dev/null
+++ b/private/mvdm/wow32/wcommdlg.h
@@ -0,0 +1,26 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1993, Microsoft Corporation
+ *
+ * WCOMDLG.H
+ * WOW32 16-bit COMMDLG support
+ *
+ * History:
+ * John Vert (jvert) 31-Dec-1992 - created
+--*/
+
+
+
+ULONG FASTCALL WCD32ChooseColor(PVDMFRAME pFrame);
+ULONG FASTCALL WCD32ChooseFont(PVDMFRAME pFrame);
+ULONG FASTCALL WCD32ExtendedError(PVDMFRAME pFrame);
+ULONG FASTCALL WCD32GetOpenFileName(PVDMFRAME pFrame);
+ULONG FASTCALL WCD32GetSaveFileName(PVDMFRAME pFrame);
+ULONG FASTCALL WCD32PrintDlg(PVDMFRAME pFrame);
+ULONG FASTCALL WCD32FindText(PVDMFRAME pFrame);
+ULONG FASTCALL WCD32ReplaceText(PVDMFRAME pFrame);
+
+LONG APIENTRY WCD32UpdateFindReplaceTextAndFlags(HWND hwnd, LPARAM lParam);
+
diff --git a/private/mvdm/wow32/wctlm32.c b/private/mvdm/wow32/wctlm32.c
new file mode 100644
index 000000000..a60218a8f
--- /dev/null
+++ b/private/mvdm/wow32/wctlm32.c
@@ -0,0 +1,232 @@
+ case EM_GETSEL: // 0x00B0
+ case EM_SETSEL: // 0x00B1
+ case EM_GETRECT: // 0x00B2
+ case EM_SETRECT: // 0x00B3
+ case EM_SETRECTNP: // 0x00B4
+ case EM_SCROLL: // 0x00B5
+ case EM_LINESCROLL: // 0x00B6
+ case EM_GETMODIFY: // 0x00B8
+ case EM_SETMODIFY: // 0x00B9
+ case EM_GETLINECOUNT: // 0x00BA
+ case EM_LINEINDEX: // 0x00BB
+ case EM_SETHANDLE: // 0x00BC
+ case EM_GETHANDLE: // 0x00BD
+ case EM_GETTHUMB: // 0x00BE
+ case EM_LINELENGTH: // 0x00C1
+ case EM_REPLACESEL: // 0x00C2
+ case EM_SETFONT: // 0x00C3
+ case EM_GETLINE: // 0x00C4
+ case EM_LIMITTEXT: // 0x00C5
+ case EM_CANUNDO: // 0x00C6
+ case EM_UNDO: // 0x00C7
+ case EM_FMTLINES: // 0x00C8
+ case EM_LINEFROMCHAR: // 0x00C9
+ case EM_SETWORDBREAK: // 0x00CA
+ case EM_SETTABSTOPS: // 0x00CB
+ case EM_SETPASSWORDCHAR: // 0x00CC
+ case EM_EMPTYUNDOBUFFER: // 0x00CD
+ case EM_GETFIRSTVISIBLE: // 0x00CE
+ case EM_SETREADONLY: // 0x00CF
+ case EM_MSGMAX: // 0x00D0
+ return ThunkEMMsg32(hwnd, uMsg, uParam, lParam,
+ pwMsgNew, pwParamNew, plParamNew);
+
+ case SBM_SETPOS: // 0x00E0
+ case SBM_GETPOS: // 0x00E1
+ case SBM_SETRANGE: // 0x00E2
+ case SBM_GETRANGE: // 0x00E3
+ case SBM_ENABLE_ARROWS: // 0x00E4
+ return ThunkSBMMsg32(hwnd, uMsg, uParam, lParam,
+ pwMsgNew, pwParamNew, plParamNew);
+
+
+ case BM_GETCHECK: // 0x00F0
+ case BM_SETCHECK: // 0x00F1
+ case BM_GETSTATE: // 0x00F2
+ case BM_SETSTATE: // 0x00F3
+ case BM_SETSTYLE: // 0x00F4
+ return ThunkBMMsg32(hwnd, uMsg, uParam, lParam,
+ pwMsgNew, pwParamNew, plParamNew);
+
+
+
+ case CB_GETEDITSEL: // 0x0140
+ case CB_LIMITTEXT: // 0x0141
+ case CB_SETEDITSEL: // 0x0142
+ case CB_ADDSTRING: // 0x0143
+ case CB_DELETESTRING: // 0x0144
+ case CB_DIR: // 0x0145
+ case CB_GETCOUNT: // 0x0146
+ case CB_GETCURSEL: // 0x0147
+ case CB_GETLBTEXT: // 0x0148
+ case CB_GETLBTEXTLEN: // 0x0149
+ case CB_INSERTSTRING: // 0x014A
+ case CB_RESETCONTENT: // 0x014B
+ case CB_FINDSTRING: // 0x014C
+ case CB_SELECTSTRING: // 0x014D
+ case CB_SETCURSEL: // 0x014E
+ case CB_SHOWDROPDOWN: // 0x014F
+ case CB_GETITEMDATA: // 0x0150
+ case CB_SETITEMDATA: // 0x0151
+ case CB_GETDROPPEDCONTROLRECT: // 0x0152
+ case CB_SETITEMHEIGHT: // 0x0153
+ case CB_GETITEMHEIGHT: // 0x0154
+ case CB_SETEXTENDEDUI: // 0x0155
+ case CB_GETEXTENDEDUI: // 0x0156
+ case CB_GETDROPPEDSTATE: // 0x0157
+ case CB_MSGMAX: // 0x0158
+ return ThunkCBMsg32(hwnd, uMsg, uParam, lParam,
+ pwMsgNew, pwParamNew, plParamNew);
+
+
+
+ case LB_ADDSTRING: // 0x0180
+ case LB_INSERTSTRING: // 0x0181
+ case LB_DELETESTRING: // 0x0182
+ case LB_RESETCONTENT: // 0x0184
+ case LB_SETSEL: // 0x0185
+ case LB_SETCURSEL: // 0x0186
+ case LB_GETSEL: // 0x0187
+ case LB_GETCURSEL: // 0x0188
+ case LB_GETTEXT: // 0x0189
+ case LB_GETTEXTLEN: // 0x018A
+ case LB_GETCOUNT: // 0x018B
+ case LB_SELECTSTRING: // 0x018C
+ case LB_DIR: // 0x018D
+ case LB_GETTOPINDEX: // 0x018E
+ case LB_FINDSTRING: // 0x018F
+ case LB_GETSELCOUNT: // 0x0190
+ case LB_GETSELITEMS: // 0x0191
+ case LB_SETTABSTOPS: // 0x0192
+ case LB_GETHORIZONTALEXTENT: // 0x0193
+ case LB_SETHORIZONTALEXTENT: // 0x0194
+ case LB_SETCOLUMNWIDTH: // 0x0195
+ case LB_SETTOPINDEX: // 0x0197
+ case LB_GETITEMRECT: // 0x0198
+ case LB_GETITEMDATA: // 0x0199
+ case LB_SETITEMDATA: // 0x019A
+ case LB_SELITEMRANGE: // 0x019B
+ case LB_SETITEMHEIGHT: // 0x01A0
+ case LB_GETITEMHEIGHT: // 0x01A1
+ case LBCB_CARETON: // 0x01A3
+ case LBCB_CARETOFF: // 0x01A4
+ case LB_MSGMAX: // 0x01A5
+ return ThunkLBMsg32(hwnd, uMsg, uParam, lParam,
+ pwMsgNew, pwParamNew, plParamNew);
+
+
+BOOL ThunkEMMsg32(HWND hwnd, UINT uMsg, UINT uParam, LONG lParam,
+ PWORD pwMsgNew, PWORD pwParamNew, PLONG plParamNew)
+{
+ // case EM_GETSEL: // 0x00B0
+ // case EM_SETSEL: // 0x00B1
+ // case EM_GETRECT: // 0x00B2
+ // case EM_SETRECT: // 0x00B3
+ // case EM_SETRECTNP: // 0x00B4
+ // case EM_SCROLL: // 0x00B5
+ // case EM_LINESCROLL: // 0x00B6
+ // case EM_GETMODIFY: // 0x00B8
+ // case EM_SETMODIFY: // 0x00B9
+ // case EM_GETLINECOUNT: // 0x00BA
+ // case EM_LINEINDEX: // 0x00BB
+ // case EM_SETHANDLE: // 0x00BC
+ // case EM_GETHANDLE: // 0x00BD
+ // case EM_GETTHUMB: // 0x00BE
+ // case EM_LINELENGTH: // 0x00C1
+ // case EM_REPLACESEL: // 0x00C2
+ // case EM_SETFONT: // 0x00C3
+ // case EM_GETLINE: // 0x00C4
+ // case EM_LIMITTEXT: // 0x00C5
+ // case EM_CANUNDO: // 0x00C6
+ // case EM_UNDO: // 0x00C7
+ // case EM_FMTLINES: // 0x00C8
+ // case EM_LINEFROMCHAR: // 0x00C9
+ // case EM_SETWORDBREAK: // 0x00CA
+ // case EM_SETTABSTOPS: // 0x00CB
+ // case EM_SETPASSWORDCHAR: // 0x00CC
+ // case EM_EMPTYUNDOBUFFER: // 0x00CD
+ // case EM_GETFIRSTVISIBLE: // 0x00CE
+ // case EM_SETREADONLY: // 0x00CF
+ // case EM_MSGMAX: // 0x00D0
+
+
+ *pwMsgNew = WM_USER + (uMsg - EM_GETSEL); // EM_GETSEL is the base
+
+ switch(uMsg) {
+ case EM_GETSEL: // 0x00B0
+ *pwParamNew = (WORD)0;
+ *plParamNew = (LONG)0;
+ break;
+
+ case EM_SETSEL: // 0x00B1
+ LOW(*plParamNew) = (WORD)((SHORT)uParam);
+ HIW(*plParamNew) = (WORD)((SHORT)lParam);
+ break;
+
+ case EM_GETRECT: // 0x00B2
+ *plParamNew = GlobalAllocLock16(GMEM_MOVEABLE,
+ sizeof(RECT16), NULL);
+ if (!(*plParamNew))
+ return FALSE;
+
+ break;
+
+ case EM_SETRECT: // 0x00B3
+ case EM_SETRECTNP: // 0x00B4
+ if (lParam) {
+ *plParamNew = GlobalAllocLock16(GMEM_MOVEABLE,
+ sizeof(RECT16), NULL);
+ if (!(*plParamNew))
+ return FALSE;
+ putrect16((VPRECT16)*plParamNew, (LPRECT)lParam);
+ }
+ break;
+
+ case EM_LINESCROLL: // 0x00B6
+ LOW(*plParamNew) = (WORD)(uParam);
+ HIW(*plParamNew) = (WORD)(lParam);
+ break;
+
+ case EM_SETHANDLE: // 0x00BC
+ case EM_GETHANDLE: // 0x00BD
+ LOGDEBUG(0, "ThunkEMMsg32:EM_xxxHANDLE - What to do\n");
+ break;
+
+ case EM_REPLACESEL: // 0x00C2
+ if (lParam) {
+ INT cb;
+
+ cb = strlen((LPSZ)lParam+1);
+ *plParamNew = GlobalAllocLock16(GMEM_MOVEABLE, cb, NULL);
+ if (!(*plParamNew))
+ return FALSE;
+ putstr16((VPSZ16)*plParamNew, (LPSZ)lParam, cb);
+ }
+ break;
+
+ case EM_SETFONT: // 0x00C3
+ LOGDEBUG(0, "ThunkEMMsg32:EM_SETFONT - What to do\n");
+ break;
+
+ case EM_GETLINE: // 0x00C4
+*************************************
+
+ case EM_SETWORDBREAK: // 0x00CA
+ LOGDEBUG(0, "ThunkEMMsg32:EM_SETWORDBREAK - What to do\n");
+ break;
+
+ case EM_SETTABSTOPS: // 0x00CB
+ if (wParam != 0) {
+ *plParamNew = GlobalAllocLock16(GMEM_MOVEABLE,
+ wParam * sizeof(WORD), NULL);
+ if (!(*plParamNew))
+ return FALSE;
+**********************putrect16((VPRECT16)*plParamNew, (LPRECT)lParam);
+ }
+ break;
+
+ }
+
+ return TRUE;
+}
+
diff --git a/private/mvdm/wow32/wctlm32.h b/private/mvdm/wow32/wctlm32.h
new file mode 100644
index 000000000..649f28c3a
--- /dev/null
+++ b/private/mvdm/wow32/wctlm32.h
@@ -0,0 +1,15 @@
+//*****************************************************************************
+//
+// 32bit Control message thunking
+//
+//
+// 01-FEB-92 NanduriR Created
+//*****************************************************************************
+
+
+BOOL ThunkEMMsg32(HWND hwnd, UINT uMsg, UINT uParam, LONG lParam,
+ PWORD pwMsgNew, PWORD pwParamNew, PLONG plParamNew);
+BOOL ThunkCBMsg32(HWND hwnd, UINT uMsg, UINT uParam, LONG lParam,
+ PWORD pwMsgNew, PWORD pwParamNew, PLONG plParamNew);
+BOOL ThunkLBMsg32(HWND hwnd, UINT uMsg, UINT uParam, LONG lParam,
+ PWORD pwMsgNew, PWORD pwParamNew, PLONG plParamNew);
diff --git a/private/mvdm/wow32/wcurcash.c b/private/mvdm/wow32/wcurcash.c
new file mode 100644
index 000000000..8cb8b1de1
--- /dev/null
+++ b/private/mvdm/wow32/wcurcash.c
@@ -0,0 +1,197 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WCURCASH.H
+ * WOW32 Cursor & Icon cash worker routines.
+ *
+ * History:
+ * Created on Jan 27th-93 by ChandanC
+ *
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+STATIC PCURICON pCurIconFirst = NULL; // pointer to first hCurIcon entry
+
+
+HICON16 W32CheckWOWCashforIconCursors(VPVOID pData, WORD ResType)
+{
+ register PICONCUR16 parg16;
+ HICON16 hIcon16;
+ HICON16 hRes16;
+ PSZ psz;
+ HAND32 h32;
+
+ GETMISCPTR(pData, parg16);
+ GETPSZIDPTR(parg16->lpStr, psz);
+
+ hIcon16 = W32FindCursorIcon (parg16->hInst, psz, ResType, &hRes16);
+
+ if (hIcon16) {
+ if (ResType == (WORD) RT_ICON) {
+ h32 = HICON32(hIcon16);
+ ResType = HANDLE_TYPE_ICON;
+ }
+ else {
+ h32 = HCURSOR32(hIcon16);
+ ResType = HANDLE_TYPE_CURSOR;
+ }
+
+ hIcon16 = SetupResCursorIconAlias((HAND16) parg16->hInst, h32, (HANDLE) hRes16, (UINT) ResType);
+ }
+
+ FREEPSZIDPTR(psz);
+ FREEMISCPTR(parg16);
+
+ return (hIcon16);
+}
+
+
+HICON16 W32FindCursorIcon (WORD hInst, LPSTR psz, WORD ResType, HICON16 *phRes16)
+{
+ PCURICON pTemp;
+
+ pTemp = pCurIconFirst;
+
+ while (pTemp) {
+ if (pTemp->ResType == ResType) {
+ if (pTemp->hInst == hInst) {
+ if ((HIWORD(psz) != 0) && (HIWORD(pTemp->lpszIcon) != 0)) {
+ if (!(_stricmp(psz, (LPSTR)pTemp->lpszIcon))) {
+ *phRes16 = pTemp->hRes16;
+ return (pTemp->hIcon16);
+ }
+ }
+ else if ((HIWORD(psz) == 0) && (HIWORD(pTemp->lpszIcon) == 0)) {
+ if ((WORD) pTemp->lpszIcon == (WORD)psz) {
+ *phRes16 = pTemp->hRes16;
+ return (pTemp->hIcon16);
+ }
+ }
+ }
+ }
+ pTemp = pTemp->pNext;
+ }
+ return 0;
+}
+
+
+BOOL W32AddCursorIconCash (WORD hInst, LPSTR psz1, HICON16 hIcon16, HICON16 hRes16, WORD ResType)
+{
+ PCURICON pCurIcon;
+ PSZ psz2;
+ WORD cb;
+
+ // if "psz1" is a string, allocate the memory for it
+
+ if ((WORD)HIWORD(psz1) != (WORD)NULL) {
+ cb = strlen(psz1)+1;
+ if (psz2 = malloc_w_small(cb)) {
+ memcpy (psz2, psz1, cb);
+ }
+ else {
+ LOGDEBUG (0, ("WOW::W32AddCursorIcon: Memory allocation failed *** \n"));
+ return (0);
+ }
+ }
+ else {
+ psz2 = psz1;
+ }
+
+ if (pCurIcon = malloc_w_small (sizeof(CURICON))) {
+ pCurIcon->pNext = pCurIconFirst;
+ pCurIconFirst = pCurIcon; // update list head
+ pCurIcon->hInst = hInst;
+ pCurIcon->lpszIcon = (DWORD)psz2;
+ pCurIcon->hIcon16 = hIcon16;
+ pCurIcon->hRes16 = hRes16;
+ pCurIcon->ResType = ResType;
+ pCurIcon->dwThreadID = CURRENTPTD()->dwThreadID;
+ return (TRUE);
+ }
+ else {
+ LOGDEBUG(0, ("WOW::WAddCursorIcon(): *** memory allocation failed *** \n"));
+ return (FALSE);
+ }
+}
+
+
+// This routine deletes a resource (Cursor or Icon) from the cash.
+
+VOID W32DeleteCursorIconCash (HICON16 hRes16)
+{
+ PCURICON pTemp;
+ PCURICON pTempLast;
+
+ pTemp = pCurIconFirst;
+
+ while (pTemp) {
+ if (pTemp->hRes16 == hRes16) {
+ if (pTemp == pCurIconFirst) {
+ pCurIconFirst = pTemp->pNext;
+ }
+ else {
+ pTempLast->pNext = pTemp->pNext;
+ }
+
+ // if its a string, delete the memory that we allocated for it
+
+ if ((WORD)HIWORD(pTemp->lpszIcon) != (WORD)NULL) {
+ free_w_small ((PVOID)pTemp->lpszIcon);
+ }
+
+ free_w_small (pTemp);
+ pTemp = NULL;
+ }
+ else {
+ pTempLast = pTemp;
+ pTemp = pTemp->pNext;
+ }
+ }
+}
+
+
+// This routine deletes all the cursors and Icons when a task terminates.
+
+VOID W32DeleteCursorIconCashForTask ()
+{
+ DWORD dwThreadID;
+ PCURICON pTemp;
+ PCURICON pTempLast;
+ PCURICON pTempNext;
+
+ dwThreadID = CURRENTPTD()->dwThreadID;
+
+ pTemp = pCurIconFirst;
+
+ while (pTemp) {
+ if (pTemp->dwThreadID == dwThreadID) {
+ if (pTemp == pCurIconFirst) {
+ pCurIconFirst = pTemp->pNext;
+ }
+ else {
+ pTempLast->pNext = pTemp->pNext;
+ }
+
+ // if its a string, delete the memory that we allocated for it
+
+ if ((WORD)HIWORD(pTemp->lpszIcon) != (WORD)NULL) {
+ free_w_small ((PVOID)pTemp->lpszIcon);
+ }
+
+ pTempNext = pTemp->pNext;
+ free_w_small (pTemp);
+ pTemp = pTempNext;
+ }
+ else {
+ pTempLast = pTemp;
+ pTemp = pTemp->pNext;
+ }
+ }
+}
diff --git a/private/mvdm/wow32/wcurcash.h b/private/mvdm/wow32/wcurcash.h
new file mode 100644
index 000000000..0d48a2c85
--- /dev/null
+++ b/private/mvdm/wow32/wcurcash.h
@@ -0,0 +1,31 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WCURCASH.H
+ * WOW32 Cursor & Icon cash worker routines.
+ *
+ * History:
+ * Created on Jan 27th-93 by ChandanC
+ *
+--*/
+
+
+typedef struct _CURICON {
+ struct _CURICON *pNext; // pointer to next hDDE alias
+ DWORD lpszIcon; // name of resource
+ HICON16 hIcon16; // 16 bit handle of the Icon/Cursor given to app
+ HICON16 hRes16; // 16 bit handle of the resource
+ WORD ResType; // type of resource, ie RT_ICON or RT_CURSOR
+ HAND16 hInst; // instance handle that owns the resource
+ DWORD dwThreadID; // ID of the thread
+} CURICON, *PCURICON;
+
+
+HICON16 W32CheckWOWCashforIconCursors(VPVOID pData, WORD ResType);
+BOOL W32AddCursorIconCash (WORD hInst, LPSTR psz1, HICON16 hIcon16, HICON16 hRes16, WORD ResType);
+HICON16 W32FindCursorIcon (WORD hInst, LPSTR psz, WORD ResType, HICON16 *phRes16);
+VOID W32DeleteCursorIconCash (HICON16 hRes16);
+VOID W32DeleteCursorIconCashForTask ();
diff --git a/private/mvdm/wow32/wcuricon.c b/private/mvdm/wow32/wcuricon.c
new file mode 100644
index 000000000..ce6f19390
--- /dev/null
+++ b/private/mvdm/wow32/wcuricon.c
@@ -0,0 +1,1114 @@
+//*****************************************************************************
+//
+// Cursor and Icon compatibility Support -
+//
+// Support for apps - which do a GlobalLock on Cursors and Icons to
+// create headaches for us.
+//
+// A compatibility issue.
+//
+//
+// 21-Apr-92 NanduriR Created.
+//
+//*****************************************************************************
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wcuricon.c);
+
+
+extern void FreeAccelAliasEntry(LPACCELALIAS lpT);
+
+LPCURSORICONALIAS lpCIAlias = NULL;
+UINT cPendingCursorIconUpdates = 0;
+
+//*****************************************************************************
+//
+// W32CreateCursorIcon32 -
+//
+// Creates a 32bit Cursor or Icon given a WIN31 Cursor or Icon HANDLE.
+// The Cursor of Icon handle must correspond to an object that has
+// been created (like CreateIcon). That is because the format of a
+// resource cursor differs from that of a 'created' cursor.
+//
+// Returns the 32bit handle
+//
+//*****************************************************************************
+
+
+HANDLE W32CreateCursorIcon32(LPCURSORICONALIAS lpCIAliasIn)
+{
+ HANDLE hT;
+ PCURSORSHAPE16 pcurs16;
+ UINT flType;
+
+ int nWidth;
+ int nHeight;
+ int nPlanes;
+ int nBitsPixel;
+ DWORD nBytesAND;
+ LPBYTE lpBitsAND;
+ LPBYTE lpBitsXOR;
+ int ScanLen16;
+
+
+ pcurs16 = (PCURSORSHAPE16)lpCIAliasIn->pbDataNew;
+
+ flType = lpCIAliasIn->flType;
+ if (flType & HANDLE_TYPE_UNKNOWN) {
+ if (PROBABLYCURSOR(FETCHWORD(pcurs16->BitsPixel),
+ FETCHWORD(pcurs16->Planes)))
+ flType = HANDLE_TYPE_CURSOR;
+ else
+ flType = HANDLE_TYPE_ICON;
+ }
+
+ nWidth = INT32(FETCHWORD(pcurs16->cx));
+ nHeight = INT32(FETCHWORD(pcurs16->cy));
+
+ nPlanes = 1;
+ nBitsPixel = 1; // Monochrome
+
+ // Get the AND mask bits
+
+ ScanLen16 = (((nWidth*nBitsPixel)+15)/16) * 2 ; // bytes/scan in 16 bit world
+ // effectively nBitsPixel is 1
+ nBytesAND = ScanLen16*nHeight*nPlanes;
+ lpBitsAND = (LPBYTE)pcurs16 + sizeof(CURSORSHAPE16);
+
+ // Get the XOR mask bits
+
+ if (flType == HANDLE_TYPE_ICON) {
+ nPlanes = INT32(FETCHWORD(pcurs16->Planes));
+ nBitsPixel = INT32(FETCHWORD(pcurs16->BitsPixel)); // the actual value
+ }
+
+ lpBitsXOR = (LPBYTE)lpBitsAND + nBytesAND;
+
+ lpCIAliasIn->flType = flType;
+
+ if (flType & HANDLE_TYPE_CURSOR) {
+ hT = CreateCursor(HMODINST32(lpCIAliasIn->hInst16),
+ (INT)FETCHWORD(pcurs16->xHotSpot),
+ (INT)FETCHWORD(pcurs16->yHotSpot),
+ nWidth, nHeight, lpBitsAND, lpBitsXOR);
+ }
+ else if (flType & HANDLE_TYPE_ICON) {
+ hT = CreateIcon(HMODINST32(lpCIAliasIn->hInst16), nWidth, nHeight,
+ (BYTE)nPlanes, (BYTE)nBitsPixel, lpBitsAND, lpBitsXOR);
+
+ }
+
+ return hT;
+}
+
+
+//*****************************************************************************
+//
+// W32Create16BitCursorIcon -
+//
+// Creates a WIN31 compatible Cursor or Icon given the full 16bit
+// definition of the object to be created.
+//
+//
+//*****************************************************************************
+
+
+HAND16 W32Create16BitCursorIcon(HAND16 hInst16, INT xHotSpot, INT yHotSpot,
+ INT nWidth, INT nHeight,
+ INT nPlanes, INT nBitsPixel,
+ LPBYTE lpBitsAND, LPBYTE lpBitsXOR,
+ INT nBytesAND, INT nBytesXOR )
+{
+ WORD h16 = 0;
+ WORD wTotalSize;
+ PCURSORSHAPE16 pcshape16;
+ VPVOID vp;
+ LPBYTE lpT;
+
+ UNREFERENCED_PARAMETER(hInst16);
+
+ wTotalSize = (WORD)(sizeof(CURSORSHAPE16) + nBytesAND + nBytesXOR);
+
+ vp = GlobalAllocLock16(GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_SHARE,
+ wTotalSize, &h16);
+ if (vp != (VPVOID)NULL) {
+ GETVDMPTR(vp, wTotalSize, pcshape16);
+
+ STOREWORD(pcshape16->xHotSpot, xHotSpot);
+ STOREWORD(pcshape16->yHotSpot, yHotSpot);
+ STOREWORD(pcshape16->cx, nWidth);
+ STOREWORD(pcshape16->cy, nHeight);
+ STOREWORD(pcshape16->cbWidth, (((nWidth + 0x0F) & ~0x0F) >> 3));
+ pcshape16->Planes = (BYTE)nPlanes;
+ pcshape16->BitsPixel = (BYTE)nBitsPixel;
+
+ lpT = (LPBYTE)pcshape16 + sizeof(CURSORSHAPE16);
+ RtlCopyMemory(lpT, lpBitsAND, nBytesAND);
+ RtlCopyMemory(lpT+nBytesAND, lpBitsXOR, nBytesXOR);
+
+ FLUSHVDMPTR(vp, wTotalSize, pcshape16);
+ FREEVDMPTR(pcshape16);
+ }
+
+ GlobalUnlock16(h16);
+ return (HAND16)h16;
+}
+
+
+
+//*****************************************************************************
+//
+// GetCursorIconAlias32 -
+//
+// Returns a 32bit handle given a 16bit Cursor or Icon HANDLE
+// Creates the 32bit Cursor or Icon if necessary.
+//
+// Returns the 32bit handle
+//
+//*****************************************************************************
+
+
+HANDLE GetCursorIconAlias32(HAND16 h16, UINT flType)
+{
+
+ LPCURSORICONALIAS lpT;
+ VPVOID vp;
+ UINT cb;
+ PCURSORSHAPE16 pcurs16;
+
+ if (h16 == (HAND16)0)
+ return (ULONG)NULL;
+
+ lpT = FindCursorIconAlias((ULONG)h16, HANDLE_16BIT);
+ if (lpT) {
+ return lpT->h32;
+ }
+ else {
+
+ //
+ // BEGIN: Check for Bogus handle
+ //
+
+ if (BOGUSHANDLE(h16))
+ return (HANDLE)NULL;
+
+ vp = RealLockResource16(h16, (PINT)&cb);
+ if (vp == (VPVOID)NULL)
+ return (ULONG)NULL;
+
+ GETVDMPTR(vp, cb, pcurs16);
+
+ if (pcurs16->cbWidth != (SHORT)(((pcurs16->cx + 0x0f) & ~0x0f) >> 3))
+ return (ULONG)NULL;
+
+ //
+ // END: Check for Bogus handle
+ //
+
+ lpT = AllocCursorIconAlias();
+ lpT->h16 = h16;
+ lpT->hTask16 = CURRENTPTD()->htask16;
+
+ lpT->vpData = vp;
+ lpT->cbData = cb;
+ lpT->pbDataNew = (LPBYTE)pcurs16;
+
+ lpT->pbDataOld = malloc_w(cb);
+ if (lpT->pbDataOld) {
+ RtlCopyMemory(lpT->pbDataOld, lpT->pbDataNew, cb);
+ }
+
+ lpT->h32 = (HAND32)W32CreateCursorIcon32(lpT);
+
+ GlobalUnlock16(h16);
+ FREEVDMPTR(pcurs16);
+ lpT->pbDataNew = (LPBYTE)NULL;
+
+ if (lpT->h32) {
+ lpT->fInUse = TRUE;
+ SetCursorIconFlag(h16, TRUE);
+ }
+ else
+ lpT->fInUse = FALSE;
+
+ return lpT->h32;
+ }
+}
+
+
+//*****************************************************************************
+//
+// GetCursorIconAlias16 -
+//
+// Returns a 16bit handle given a 32bit Cursor or Icon HANDLE
+// Creates the 16bit Cursor or Icon if necessary.
+//
+// Returns the 16bit handle
+//
+//*****************************************************************************
+
+
+HAND16 GetCursorIconAlias16(HAND32 h32, UINT flType)
+{
+
+ LPCURSORICONALIAS lpT;
+
+ if (h32 == (HAND32)0)
+ return (HAND16)NULL;
+
+ lpT = FindCursorIconAlias((ULONG)h32, HANDLE_32BIT);
+ if (lpT) {
+ return lpT->h16;
+ }
+ else {
+ HAND16 h16;
+
+ // HACK:
+ // From experience: numeric values of 32bit standard cursors and icons
+ // are very small. so check for these handles.
+ // we should not create aliases for standard cursors and
+ // icons here.
+
+ WOW32ASSERT((UINT)h32 >= 100);
+
+ //
+ // Always generate valid handles.
+ //
+
+ h16 = W32Create16BitCursorIconFrom32BitHandle(h32, (HAND16)NULL,
+ (PUINT)NULL);
+ if (h16) {
+ h16 = SetupCursorIconAlias((HAND16)NULL, h32, h16, flType,
+ NULL, (WORD)NULL);
+ }
+ return h16;
+ }
+}
+
+
+//*****************************************************************************
+//
+// AllocCursorIconAlias -
+//
+// Allocates and reurns pointer to CURSORICONALIAS buffer.
+//
+//*****************************************************************************
+
+
+LPCURSORICONALIAS AllocCursorIconAlias()
+{
+ LPCURSORICONALIAS lpT;
+
+ for (lpT = lpCIAlias; lpT != NULL; lpT = lpT->lpNext) {
+ if (!lpT->fInUse)
+ break;
+ }
+
+ if (lpT == NULL) {
+ lpT = (LPCURSORICONALIAS)malloc_w_small(sizeof(CURSORICONALIAS));
+ if (lpT) {
+ lpT->lpNext = lpCIAlias;
+ lpCIAlias = lpT;
+ }
+ else {
+ LOGDEBUG(0, ("AllocCursorIconAlias: malloc_w_small for alias failed\n"));
+ }
+ }
+
+ if (lpT != NULL) {
+ lpT->fInUse = TRUE;
+ lpT->h16 = (HAND16)0;
+ lpT->h32 = (HAND32)0;
+ lpT->vpData = (VPVOID)NULL;
+ lpT->cLock = 0;
+ lpT->cbData = 0;
+ lpT->pbDataOld = (LPBYTE)NULL;
+ lpT->pbDataNew = (LPBYTE)NULL;
+ lpT->lpszName = (LPBYTE)NULL;
+
+ lpT->flType = HANDLE_TYPE_UNKNOWN;
+ lpT->hInst16 = (HAND16)0;
+ lpT->hMod16 = (HAND16)0;
+ lpT->hTask16 = (HTASK16)0;
+ lpT->hRes16 = 0;
+ }
+
+ return lpT;
+}
+
+
+//*****************************************************************************
+//
+// FindCursorIconAlias -
+//
+// Searches for the given handle and returns corresponding
+// LPCURSORICONALIAS.
+//
+//*****************************************************************************
+
+
+LPCURSORICONALIAS FindCursorIconAlias(ULONG hCI, UINT flHandleSize)
+{
+ LPCURSORICONALIAS lpT;
+ LPCURSORICONALIAS lpTprev;
+
+ lpTprev = (LPCURSORICONALIAS)NULL;
+ for (lpT = lpCIAlias; lpT != NULL; lpTprev = lpT, lpT = lpT->lpNext) {
+ if (lpT->fInUse) {
+ if ((flHandleSize == HANDLE_16BIT && lpT->h16 == (HAND16)hCI) ||
+ (flHandleSize == HANDLE_32BIT && lpT->h32 == (HAND32)hCI))
+ break;
+ else if (flHandleSize == HANDLE_16BITRES && lpT->hRes16 &&
+ (lpT->hRes16 == (HAND16)hCI))
+
+
+ break;
+ }
+
+ }
+
+ if (lpT) {
+ if (lpTprev) {
+ lpTprev->lpNext = lpT->lpNext;
+ lpT->lpNext = lpCIAlias;
+ lpCIAlias = lpT;
+ }
+ }
+ return lpT;
+}
+
+
+
+//*****************************************************************************
+//
+// DeleteCursorIconAlias -
+//
+// Searches for the given handle and if a 16bit handle frees the memory
+// allocated for the Object. The alias table is not freed.
+//
+//*****************************************************************************
+
+
+BOOL DeleteCursorIconAlias(ULONG hCI, UINT flHandleSize)
+{
+ LPCURSORICONALIAS lpT;
+
+ WOW32ASSERT(flHandleSize == HANDLE_16BIT);
+
+ for (lpT = lpCIAlias; lpT != NULL; lpT = lpT->lpNext) {
+ if (lpT->fInUse && !(lpT->flType & HANDLE_TYPE_WOWGLOBAL)) {
+
+ // Have we found the handle mapping?
+
+ if (flHandleSize == HANDLE_16BIT && lpT->h16 == (HAND16)hCI) {
+
+ if (lpT->hTask16) {
+
+ // We don't want to free the handle mapping when
+ // the handle corresponds to a 16-bit resource, i.e.
+ // hRes16 is non-null.
+
+ if (!(lpT->hRes16)) {
+ SetCursorIconFlag(lpT->h16, FALSE);
+ GlobalUnlockFree16(RealLockResource16((HMEM16)hCI, NULL));
+ free_w(lpT->pbDataOld);
+ lpT->fInUse = FALSE;
+ return TRUE;
+ }
+ }
+ else {
+ WOW32ASSERT(FALSE);
+ }
+
+ break;
+ }
+ }
+
+ }
+
+ return FALSE;
+}
+
+
+
+
+//*****************************************************************************
+//
+// FreeCursorIconAlias -
+//
+// Frees all Cursors and Icons of the specified task.
+//
+//
+//*****************************************************************************
+
+
+BOOL FreeCursorIconAlias(HAND16 hand16, ULONG ulFlags)
+{
+ LPCURSORICONALIAS lpT;
+
+ for (lpT = lpCIAlias; lpT != NULL; lpT = lpT->lpNext) {
+ if (lpT->fInUse &&
+ (((ulFlags & CIALIAS_HMOD) && (lpT->hMod16 == hand16)) ||
+ ((ulFlags & CIALIAS_HTASK) && (lpT->hTask16 == hand16)))) {
+
+ if (ulFlags & CIALIAS_TASKISGONE) {
+ // We're here if this function is called after the task
+ // cleanup on the 16bit side... then we really can't
+ // callback. Setting appropriate fields to NULL will
+ // avoid callbacks, but will leak the corresponding
+ // memory. The asserts will catch this on a checked
+ // build.
+ WOW32ASSERT(lpT->h16==(HAND16)NULL);
+ WOW32ASSERT(lpT->hRes16==(HAND16)NULL);
+ lpT->h16 = (HAND16)NULL;
+ lpT->hRes16 = (HAND16)NULL;
+ }
+ InvalidateCursorIconAlias(lpT);
+ }
+ }
+
+ return TRUE;
+}
+
+
+//*****************************************************************************
+//
+// SetupCursorIconAlias -
+//
+// Sets up association (alias) between a 32bit and a 16bit handle.
+// given both the handles.
+//
+//
+//*****************************************************************************
+
+
+HAND16 SetupCursorIconAlias(HAND16 hInst16, HAND32 h32, HAND16 h16, UINT flType,
+ LPBYTE lpResName, WORD hRes16)
+
+{
+ LPCURSORICONALIAS lpT;
+ VPVOID vp;
+ INT cb;
+
+ lpT = AllocCursorIconAlias();
+ lpT->fInUse = TRUE;
+ lpT->h16 = h16;
+ lpT->h32 = h32;
+ lpT->flType = flType;
+ if (!(flType & HANDLE_TYPE_WOWGLOBAL)) {
+ lpT->hInst16 = hInst16;
+ lpT->hMod16 = GETHMOD16(HMODINST32(hInst16));
+ lpT->hTask16 = CURRENTPTD()->htask16;
+ lpT->hRes16 = hRes16;
+
+ vp = RealLockResource16(h16, &cb);
+ if (vp == (VPVOID)NULL)
+ return (HAND16)NULL;
+
+ lpT->vpData = vp;
+ lpT->cbData = cb;
+ GETVDMPTR(vp, cb, lpT->pbDataNew);
+
+ lpT->pbDataOld = malloc_w(cb);
+ if (lpT->pbDataOld) {
+ RtlCopyMemory(lpT->pbDataOld, lpT->pbDataNew, cb);
+ }
+
+ if (hRes16) {
+ lpT->lpszName = lpResName;
+ if ((WORD)HIWORD(lpResName) != (WORD)NULL) {
+ UINT cb;
+ cb = strlen(lpResName)+1;
+ if (lpT->lpszName = malloc_w_small(cb)) {
+ memcpy (lpT->lpszName, lpResName, cb);
+ }
+ }
+ }
+
+
+ }
+ // the alias has been setup. Now turn on the GAH_CURSORICON flag.
+
+ SetCursorIconFlag(h16, TRUE);
+
+ return h16;
+}
+
+
+
+//*****************************************************************************
+//
+// SetupResCursorIconAlias -
+//
+// Sets up association (alias) between a 32bit and a 16bit handle.
+// given the 32bit handle and a handle to a 16bit resource.
+//
+//
+//*****************************************************************************
+
+
+HAND16 SetupResCursorIconAlias(HAND16 hInst16, HAND32 h32, LPBYTE lpResName, WORD hRes16, UINT flType)
+{
+ LPCURSORICONALIAS lpT;
+ HAND16 h16 = 0;
+ HAND16 h16Res = 0;
+ UINT cb;
+
+
+ if (hRes16) {
+ // 16bit resource has been loaded. We always want to return the
+ // SAME 16bit handle no matter howmany times the 'LoadIcon' or
+ // LoadCursor has been called.
+
+ h16Res = LOWORD(hRes16);
+ lpT = FindCursorIconAlias(h16Res, HANDLE_16BITRES);
+ }
+ else {
+
+ // Resource handle is NULL. The Resource must have been a
+ // standard predefined resource like ARROW etc.
+
+ lpT = FindCursorIconAlias((ULONG)h32, HANDLE_32BIT);
+ flType |= HANDLE_TYPE_WOWGLOBAL;
+ }
+
+ if (lpT == NULL) {
+ h16 = W32Create16BitCursorIconFrom32BitHandle(h32, hInst16, &cb);
+ h16 = SetupCursorIconAlias(hInst16, h32, h16, flType, lpResName, hRes16);
+ }
+ else {
+ if (lpT->flType & HANDLE_TYPE_WOWGLOBAL) {
+
+ // eachtime we should get the same h32 from usersrv.
+ //
+
+ WOW32ASSERT(lpT->h32 == h32);
+ }
+ else {
+ if (lpT->h32 != h32) {
+ if (lpT->flType == HANDLE_TYPE_CURSOR)
+ DestroyCursor(h32);
+ else
+ DestroyIcon(h32);
+ }
+ ReplaceCursorIcon(lpT);
+ }
+
+ h16 = lpT->h16;
+ }
+
+ return h16;
+}
+
+
+//*****************************************************************************
+//
+// SetCursorIconFlag -
+//
+// Sets/Clears the GAH_CURSORICONFLAG in the global arean header. This flag
+// is used to identify Cursors and Icon when they are GlobaLocked and
+// GlobalUnlocked
+//
+//*****************************************************************************
+
+ULONG SetCursorIconFlag(HAND16 h16, BOOL fSet)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+
+ Parm16.WndProc.wParam = h16;
+ Parm16.WndProc.wMsg = fSet;
+ CallBack16(RET_SETCURSORICONFLAG, &Parm16, 0, &vp);
+ return (ULONG)0;
+}
+
+
+//*****************************************************************************
+//
+// UpdateCursorIcon -
+//
+// Compares the new object data with the old. If any of the bytes differ
+// the old object is replaced with the new.
+//
+//*****************************************************************************
+
+VOID UpdateCursorIcon()
+{
+ LPCURSORICONALIAS lpT;
+ UINT cbData;
+ LPBYTE lpBitsNew, lpBitsOld;
+ UINT i = 0;
+
+ for (lpT = lpCIAlias; lpT != NULL ; lpT = lpT->lpNext) {
+ if (lpT->fInUse && lpT->cLock) {
+ GETVDMPTR(lpT->vpData, lpT->cbData, lpT->pbDataNew);
+ if (lpT->hRes16) {
+ if (lpT->flType == HANDLE_TYPE_ICON) {
+ lpBitsNew = lpT->pbDataNew + sizeof(BITMAPINFOHEADER16);
+ lpBitsOld = lpT->pbDataOld + sizeof(BITMAPINFOHEADER16);
+ cbData = lpT->cbData - sizeof(BITMAPINFOHEADER16);
+ }
+ else {
+ lpBitsNew = lpT->pbDataNew + sizeof(CURSORRESOURCE16);
+ lpBitsOld = lpT->pbDataOld + sizeof(CURSORRESOURCE16);
+ cbData = lpT->cbData - sizeof(CURSORRESOURCE16);
+ }
+
+ }
+ else {
+ lpBitsNew = lpT->pbDataNew + sizeof(CURSORSHAPE16);
+ lpBitsOld = lpT->pbDataOld + sizeof(CURSORSHAPE16);
+ cbData = lpT->cbData - sizeof(CURSORSHAPE16);
+ }
+
+ if (! RtlEqualMemory(lpBitsNew, lpBitsOld, cbData))
+ ReplaceCursorIcon(lpT);
+
+ if (cPendingCursorIconUpdates == ++i)
+ break;
+ }
+
+ }
+
+}
+
+//*****************************************************************************
+//
+// ReplaceCursorIcon -
+//
+// Updates the current cursor or icon. Creates a new icon or cursor and
+// replaces the contents of the old handle with that of the new.
+//
+// returns TRUE for success.
+//
+//*****************************************************************************
+
+BOOL ReplaceCursorIcon(LPCURSORICONALIAS lpIn)
+{
+ HANDLE hT32;
+
+
+ if (lpIn != NULL) {
+
+ // Get the data
+
+ GETVDMPTR(lpIn->vpData, lpIn->cbData, lpIn->pbDataNew);
+
+ // Create the object
+
+ hT32 = (HAND32)W32CreateCursorIcon32(lpIn);
+
+ // SetCursorConents will replace the contents of OLD cursor/icon
+ // with that of the new handle and destroy the new handle
+
+ SetCursorContents(lpIn->h32, hT32);
+
+ // replace the old object data with the new
+
+ RtlCopyMemory(lpIn->pbDataOld, lpIn->pbDataNew, lpIn->cbData);
+ FREEVDMPTR(lpIn->pbDataNew);
+ lpIn->pbDataNew = (LPBYTE)NULL;
+
+ }
+
+
+ return (BOOL)TRUE;
+
+}
+
+
+//*****************************************************************************
+//
+// WK32WowCursorIconOp -
+//
+// Gets called when/from GlobalLock or GlobalUnlock are called. The fLock
+// flag is TRUE if called from GlobalLock else it is FALSE.
+//
+//*****************************************************************************
+
+BOOL FASTCALL WK32WowCursorIconOp(PVDMFRAME pFrame)
+{
+
+ PWOWCURSORICONOP16 prci16;
+ HAND16 h16;
+ LPCURSORICONALIAS lpT;
+ BOOL fLock;
+ WORD wFuncId;
+ UINT cLockT;
+
+
+ GETARGPTR(pFrame, sizeof(WOWCURSORICONOP16), prci16);
+ wFuncId = FETCHWORD(prci16->wFuncId);
+ h16 = (HAND16)FETCHWORD(prci16->h16);
+
+ lpT = FindCursorIconAlias((ULONG)h16, HANDLE_16BIT);
+ // This is a Cursor or Icon
+ if (lpT != NULL) {
+
+ if (wFuncId == FUN_GLOBALLOCK || wFuncId == FUN_GLOBALUNLOCK) {
+
+ if (!(lpT->flType & HANDLE_TYPE_WOWGLOBAL)) {
+
+ fLock = (wFuncId == FUN_GLOBALLOCK);
+
+ // Store the current lockcount.
+
+ cLockT = lpT->cLock;
+
+ // Update the Lock count
+
+ lpT->cLock = fLock ? ++lpT->cLock : --lpT->cLock;
+
+ if (lpT->cLock == 0) {
+
+ // New lock count == 0 implies that it was decremented from
+ // 1 to 0 thereby impling that it was one of the cursors that
+ // was being updated regularly.
+
+ // Decrement the global count and update the cursor one last
+ // time
+
+ cPendingCursorIconUpdates--;
+ ReplaceCursorIcon(lpT);
+ }
+ else if (fLock && cLockT == 0) {
+
+ // If previous Lockcount was zero and the object is being locked
+ // then it means that this is the very first time that the object
+ // is being locked
+
+ cPendingCursorIconUpdates++;
+ }
+ }
+ }
+ else if (wFuncId == FUN_GLOBALFREE) {
+
+ // The h16 has not yet been GlobalFreed. We return TRUE if h16 can
+ // be freed else FALSE. The h16 can be freed only if it is not a
+ // global handle. ie, it doesn't correspond to a predefined cursor
+
+ // Also we donot free the handle if h16 corresponds to a resource.
+ // CorelDraw 3.0 calls FreeResource(h16) and then SetCursor(h16)
+ // thus GPing.
+
+ BOOL fFree;
+
+ fFree = !((lpT->flType & HANDLE_TYPE_WOWGLOBAL) || lpT->hRes16);
+ if (fFree) {
+ // Set handle to NULL so that InvalidateCursorIconAlias
+ // doesn't try to free it.
+
+ lpT->h16 = 0;
+ InvalidateCursorIconAlias(lpT);
+ }
+
+ return (BOOL)fFree;
+
+ }
+ else {
+ LOGDEBUG(0, ("WK32WowCursorIconOp: Unknown Func Id\n"));
+ }
+ }
+
+ // else if this is a GlobalFree call
+ else if (wFuncId == FUN_GLOBALFREE) {
+
+ // and if this is a handle to an accelerator
+ if(lpT = (LPCURSORICONALIAS)FindAccelAlias((HANDLE)h16, HANDLE_16BIT)) {
+
+ // free it from the accelerator alias list
+ FreeAccelAliasEntry((LPACCELALIAS) lpT);
+
+ // cause this hMem16 to really be free'd in 16-bit GlobalFree
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+//*****************************************************************************
+//
+// W32Create16BitResCursorIconFrom32BitHandle -
+//
+// Creates a WIN31 compatible Cursor or Icon given a 32bit cursor or icon
+// handle. This is primarily used to create a 16bit Cursor or Icon which
+// has been loaded from a 16bit resource.
+//
+//
+// returns 16bit handle
+//*****************************************************************************
+
+
+HAND16 W32Create16BitCursorIconFrom32BitHandle(HANDLE h32, HAND16 hInst16,
+ PUINT pcbData)
+{
+ HAND16 h16 = 0;
+ ICONINFO iinfo;
+ BITMAP bm;
+ BITMAP bmClr;
+ UINT nBytesAND = 0;
+ UINT nBytesXOR = 0;
+ LPBYTE lpBitsAND, lpBitsXOR;
+
+ if (GetIconInfo(h32, &iinfo)) {
+ if (GetObject(iinfo.hbmMask, sizeof(BITMAP), &bm)) {
+ nBytesAND = GetBitmapBits(iinfo.hbmMask, 0, (LPBYTE)NULL);
+ if (iinfo.hbmColor) {
+ GetObject(iinfo.hbmColor, sizeof(BITMAP), &bmClr);
+ nBytesXOR = GetBitmapBits(iinfo.hbmColor, 0, (LPBYTE)NULL);
+ }
+ else {
+ bm.bmHeight /= 2;
+ nBytesAND /= 2;
+ nBytesXOR = nBytesAND;
+ }
+
+
+ if (pcbData) {
+ *pcbData = nBytesAND + nBytesXOR + sizeof(CURSORSHAPE16);
+ }
+
+ lpBitsAND = malloc_w(nBytesAND + nBytesXOR);
+ if (lpBitsAND != NULL) {
+ lpBitsXOR = lpBitsAND + nBytesAND;
+ GetBitmapBits(iinfo.hbmMask,
+ (iinfo.hbmColor) ? nBytesAND : (nBytesAND * 2),
+ lpBitsAND);
+ if (iinfo.hbmColor)
+ GetBitmapBits(iinfo.hbmColor, nBytesXOR, lpBitsXOR);
+
+ h16 = W32Create16BitCursorIcon(hInst16,
+ iinfo.xHotspot, iinfo.yHotspot,
+ bm.bmWidth, bm.bmHeight,
+ (iinfo.hbmColor) ? bmClr.bmPlanes :
+ bm.bmPlanes,
+ (iinfo.hbmColor) ? bmClr.bmBitsPixel :
+ bm.bmBitsPixel,
+ lpBitsAND, lpBitsXOR,
+ (INT)nBytesAND, (INT)nBytesXOR);
+ free_w(lpBitsAND);
+
+ }
+
+ }
+ DeleteObject(iinfo.hbmMask);
+ if (iinfo.hbmColor) {
+ DeleteObject(iinfo.hbmColor);
+ }
+ }
+
+ return h16;
+
+}
+
+//*****************************************************************************
+//
+// GetClassCursorIconAlias32 -
+//
+// Returns a 32bit handle given a 16bit Cursor or Icon HANDLE
+// DOES NOT Create the 32bit Cursor or Icon if there is no alias.
+// This is called in RegisterClass only - to support those apps which
+// pass a bogus handle for WNDCLASS.hIcon.
+//
+// Returns the 32bit handle
+//
+//*****************************************************************************
+
+
+HANDLE GetClassCursorIconAlias32(HAND16 h16)
+{
+
+ LPCURSORICONALIAS lpT;
+
+ if (h16 == (HAND16)0)
+ return (ULONG)NULL;
+
+ lpT = FindCursorIconAlias((ULONG)h16, HANDLE_16BIT);
+ if (lpT) {
+ return lpT->h32;
+ }
+ else
+ return (HANDLE)NULL;
+}
+
+
+
+//*****************************************************************************
+//
+// InvalidateCursorIconAlias -
+//
+// Frees the allocated objects.
+//
+//*****************************************************************************
+
+
+VOID InvalidateCursorIconAlias(LPCURSORICONALIAS lpT)
+{
+ VPVOID vp=0;
+ PARM16 Parm16;
+
+ if (!lpT->fInUse)
+ return;
+
+ if (lpT->h16) {
+ SetCursorIconFlag(lpT->h16, FALSE);
+ GlobalUnlockFree16(RealLockResource16((HMEM16)lpT->h16, NULL));
+ }
+
+ if (lpT->hRes16) {
+ Parm16.WndProc.wParam = (HAND16) lpT->hRes16;
+ CallBack16(RET_FREERESOURCE, &Parm16, 0, &vp);
+ }
+
+ if (lpT->h32) {
+ if (lpT->flType == HANDLE_TYPE_CURSOR)
+ DestroyCursor(lpT->h32);
+ else
+ DestroyIcon(lpT->h32);
+ }
+
+ if (lpT->pbDataOld)
+ free_w(lpT->pbDataOld);
+
+ if (lpT->cLock)
+ cPendingCursorIconUpdates--;
+
+
+ if ((WORD)HIWORD(lpT->lpszName) != (WORD)NULL) {
+ free_w_small ((PVOID)lpT->lpszName);
+ }
+
+ lpT->fInUse = FALSE;
+}
+
+
+//*****************************************************************************
+//
+// InitStdCursorIconAlias -
+//
+// Creates the aliases of standard cursors and icons.
+//
+// NOTES:
+//
+// The idea is to createaliases for all the standard cursors and icons to
+// make sure that we indeed generate valid handles.
+//
+// This problem cameup because of the following scenario
+// the app turbotax does the following:
+//
+// h16Cursor1 = GetClassWord(hwndEditControl, GCL_HCURSOR);
+// (bydefault, this is an I-beam)
+// .....
+// h16Cursor2 = LoadCursor(NULL, IDC_IBEAM);
+// Because of the way we create and maintain our 32-16 alias hCursor1 is a
+// a WOW bogus handle (ie > 0xf000) and since by default the "Edit" class is
+// registered with hCursor = IDC_IBEAM, the h32s are same ie.
+//
+// GetClassWord(hwndEditControl, GCL_HCURSOR) == LoadCursor(..IDC_IBEAM);
+//
+// Thus h16Cursor2 will be same as h16Cursor1 and that's a problem because we
+// are NOT returning a valid wow handle for a predefined cursor.
+//
+//
+// The solution is to createaliases for all standard cursors and icons during
+// init time so that we don't run into this problem. However I think this
+// approach as wasteful and am creating the alias for the only known case
+// ie IDC_IBEAM.
+//
+// - Nanduri Ramakrishna
+//*****************************************************************************
+
+DWORD InitCursorIds[] = {
+ (DWORD)IDC_ARROW,
+ (DWORD)IDC_IBEAM,
+ (DWORD)IDC_WAIT,
+ (DWORD)IDC_CROSS,
+ (DWORD)IDC_UPARROW,
+ (DWORD)IDC_SIZE,
+ (DWORD)IDC_ICON,
+ (DWORD)IDC_SIZENWSE,
+ (DWORD)IDC_SIZENESW,
+ (DWORD)IDC_SIZEWE,
+ (DWORD)IDC_SIZENS
+ };
+
+BOOL InitStdCursorIconAlias()
+{
+
+ HCURSOR h32;
+ UINT i;
+
+ for (i = 0; i < (sizeof(InitCursorIds) / sizeof(DWORD)); i++) {
+
+ //
+ // Create the alias for each standard cursor in the list
+ //
+
+ h32 = (HCURSOR)LoadCursor((HINSTANCE)NULL, (LPCSTR)InitCursorIds[i]);
+ WOW32ASSERT(h32);
+
+ if (h32) {
+ SetupResCursorIconAlias((HAND16)NULL, (HAND32)h32, NULL, (WORD)NULL,
+ HANDLE_TYPE_CURSOR);
+ }
+
+ }
+
+ //
+ // Add similar lines for standard icons.
+ //
+
+ return TRUE;
+}
+
+
+//*****************************************************************************
+//
+// W32CheckIfAlreadyLoaded -
+//
+// returns h16 if a cursoricon has previously been loaded.
+//
+//*****************************************************************************
+
+HAND16 W32CheckIfAlreadyLoaded(VPVOID pData, WORD ResType)
+{
+ LPCURSORICONALIAS lpT;
+ PICONCUR16 parg16;
+ PSZ psz;
+
+
+ GETMISCPTR(pData, parg16);
+ GETPSZIDPTR(parg16->lpStr, psz);
+
+ ResType = (ResType == FUN_LOADCURSOR) ? HANDLE_TYPE_CURSOR : HANDLE_TYPE_ICON;
+ for (lpT = lpCIAlias; lpT != NULL; lpT = lpT->lpNext) {
+ if (lpT->fInUse) {
+ LPBYTE lpszNameT = lpT->lpszName;
+ if (lpszNameT && (lpT->flType & ResType) &&
+ lpT->hInst16 == parg16->hInst) {
+ WOW32ASSERT(!(lpT->flType & HANDLE_TYPE_WOWGLOBAL));
+ if (HIWORD(lpszNameT) && HIWORD(psz)) {
+ if (!(_stricmp(psz, (LPSTR)lpszNameT)))
+ break;
+ }
+ else if (lpszNameT == psz) {
+ break;
+ }
+ }
+ }
+ }
+
+
+ FREEPSZIDPTR(psz);
+ FREEMISCPTR(parg16);
+
+
+ if (lpT && lpT->cLock)
+ ReplaceCursorIcon(lpT);
+
+ return (lpT ? lpT->h16 : 0);
+}
diff --git a/private/mvdm/wow32/wcuricon.h b/private/mvdm/wow32/wcuricon.h
new file mode 100644
index 000000000..a3ce02dcb
--- /dev/null
+++ b/private/mvdm/wow32/wcuricon.h
@@ -0,0 +1,96 @@
+//*****************************************************************************
+//
+// Cursor and Icon compatibility Support -
+//
+// Support for apps - which do a GlobalLock on Cursors and Icons to
+// create headaches for us.
+//
+// A compatibility issue.
+//
+//
+// 21-Apr-92 NanduriR Created.
+//
+//*****************************************************************************
+
+#define HANDLE_TYPE_UNKNOWN 0x01
+#define HANDLE_TYPE_ICON 0x02
+#define HANDLE_TYPE_CURSOR 0x04
+
+#define HANDLE_TYPE_WOWGLOBAL 0x08
+
+#define HANDLE_16BIT 0x01
+#define HANDLE_32BIT 0x02
+#define HANDLE_16BITRES 0x04
+
+#define CIALIAS_TASKISGONE 0x01
+#define CIALIAS_HMOD 0x02
+#define CIALIAS_HTASK 0x04
+
+typedef struct _CURSORICONALIAS {
+ struct _CURSORICONALIAS FAR *lpNext;
+ BYTE fInUse;
+ BYTE flType;
+ HAND16 h16;
+ HAND32 h32;
+ HAND16 hInst16;
+ HAND16 hMod16;
+ HTASK16 hTask16;
+ WORD hRes16; // 16bit resource handle
+ WORD cbData;
+ UINT cLock;
+ VPVOID vpData;
+ LPBYTE pbDataOld;
+ LPBYTE pbDataNew;
+ LPBYTE lpszName; // name of 16bit resource
+} CURSORICONALIAS, FAR *LPCURSORICONALIAS;
+
+
+#define PROBABLYCURSOR(BitsPixel, Planes) ((((BitsPixel) == 1) && \
+ ((Planes) == 1)) || \
+ (BitsPixel) == 0 || (Planes) == 0)
+#define BOGUSHANDLE(h) (~(h) & 0x4)
+
+extern UINT cPendingCursorIconUpdates;
+
+HANDLE W32CreateCursorIcon32(LPCURSORICONALIAS lpCIAlias);
+HAND16 W32Create16BitCursorIcon(HAND16 hInst16, INT xHotSpot, INT yHotSpot,
+ INT nWidth, INT nHeight, INT nPlanes, INT nBitsPixel,
+ LPBYTE lpBitsAND, LPBYTE lpBitsXOR, INT nBytesAND, INT nBytesXOR);
+
+HANDLE GetCursorIconAlias32(HAND16 h16, UINT flType);
+HAND16 GetCursorIconAlias16(HAND32 h32, UINT flType);
+LPCURSORICONALIAS AllocCursorIconAlias();
+LPCURSORICONALIAS FindCursorIconAlias(ULONG hCI, UINT flHandleSize);
+BOOL DeleteCursorIconAlias(ULONG hCI, UINT flHandleSize);
+BOOL FreeCursorIconAlias(HAND16 hand16, ULONG ulFLags);
+HAND16 SetupCursorIconAlias(HAND16 hInst16, HAND32 h32, HAND16 h16, UINT flType,
+ LPBYTE lpResName, WORD hRes16);
+HAND16 SetupResCursorIconAlias(HAND16 hInst16, HAND32 h32, LPBYTE lpResName, WORD hRes16, UINT flType);
+ULONG SetCursorIconFlag(HAND16 h16, BOOL fSet);
+BOOL ReplaceCursorIcon(LPCURSORICONALIAS lpCIAliasIn);
+BOOL FASTCALL WK32WowCursorIconOp(PVDMFRAME pFrame);
+VOID UpdateCursorIcon(VOID);
+HAND16 W32Create16BitCursorIconFrom32BitHandle(HANDLE h32, HAND16 hMod16,
+ PUINT cbData);
+BOOL InitStdCursorIconAlias(VOID);
+
+
+#define HCURSOR32(hobj16) GetCursorIconAlias32((HAND16)(hobj16), HANDLE_TYPE_CURSOR)
+#define GETHCURSOR16(hobj32) GetCursorIconAlias16((HAND32)(hobj32), HANDLE_TYPE_CURSOR)
+#define FREEHCURSOR16(hobj16) DeleteCursorIconAlias((ULONG)(hobj16), HANDLE_16BIT)
+
+#define HICON32(hobj16) GetCursorIconAlias32((HAND16)(hobj16), HANDLE_TYPE_ICON)
+#define GETHICON16(hobj32) GetCursorIconAlias16((HAND32)(hobj32), HANDLE_TYPE_ICON)
+#define FREEHICON16(hobj16) DeleteCursorIconAlias((ULONG)(hobj16), HANDLE_16BIT)
+
+#define HICON32_REGCLASS(hobj16) GetClassCursorIconAlias32((HAND16)(hobj16))
+HANDLE GetClassCursorIconAlias32(HAND16 h16);
+VOID InvalidateCursorIconAlias(LPCURSORICONALIAS lpT);
+
+//
+// In win32 USER
+//
+
+HANDLE WINAPI WOWLoadCursorIcon(HANDLE hInstance, LPCSTR lpIconName,
+ LPTSTR rt, LPHANDLE lphRes16);
+HAND16 W32CheckIfAlreadyLoaded(VPVOID pData, WORD ResType);
diff --git a/private/mvdm/wow32/wdde.c b/private/mvdm/wow32/wdde.c
new file mode 100644
index 000000000..1fbdbf5bb
--- /dev/null
+++ b/private/mvdm/wow32/wdde.c
@@ -0,0 +1,1138 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WDDE.C
+ * WOW32 DDE worker routines.
+ *
+ * History:
+ * WOW DDE support designed and developed by ChandanC
+ *
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+LPDDENODE DDEInitiateList = NULL;
+STATIC PHDDE phDDEFirst = NULL; // pointer to first hDDE entry
+STATIC PCPDATA pCPDataFirst = NULL; // pointer to first CopyData entry
+
+MODNAME(wdde.c);
+
+
+// This routine maintains a list of client windows that are in
+// Initiate mode. This is called from THUNKING of DDE_INITIATE
+// message (from both the WMDISP32.C and WMSG16.C).
+//
+
+VOID WI32DDEAddInitiator (HAND16 Initiator)
+{
+ LPDDENODE Node;
+
+ Node = (LPDDENODE) malloc_w(sizeof(DDENODE));
+
+ if (Node) {
+
+ //
+ // Initialize Node with the Initiator's window handle
+ //
+
+ Node->Initiator = Initiator;
+
+ //
+ // Insert this Node into the linked list of DDE_Initiate message
+ // in progress.
+ //
+
+ Node->Next = DDEInitiateList;
+ DDEInitiateList = Node;
+
+ LOGDEBUG(12, ("WOW::WI32DDEInitiator(): thunking -- adding an Initiator %04lX\n", Initiator));
+ }
+ else {
+
+ //
+ // We could not allocate memory.
+ //
+
+ LOGDEBUG(12, ("WOW::WI32DDEInitiator(): thunking -- Couldn't allocate memory\n"));
+ WOW32ASSERT (FALSE);
+ }
+}
+
+
+// This routine deletes the client window that was in Initiate mode. Because
+// the initiate message is completed now. This is called from UNTHUNKING
+// of DDE_INITIATE message (from both the WMDISP32.C and WMSG16.C).
+//
+
+VOID WI32DDEDeleteInitiator(HAND16 Initiator)
+{
+ LPDDENODE Node, Temp1;
+
+ Node = DDEInitiateList;
+
+ if (Node) {
+
+ while (Node) {
+ if (Node->Initiator == Initiator) {
+
+ if (Node == DDEInitiateList) {
+
+ //
+ // first guy in the list
+ //
+
+ DDEInitiateList = Node->Next;
+ }
+ else {
+
+ //
+ // update the list
+ //
+
+ Temp1->Next = Node->Next;
+ }
+
+ LOGDEBUG(12, ("WOW::WI32DDEDeleteInitiator(): unthunking -- deleting an Initiator %08lX\n", Initiator));
+
+ //
+ // free up the memory
+ //
+
+ free_w(Node);
+ Node = NULL;
+ }
+ else {
+
+ //
+ // traverse the list
+ //
+
+ Temp1 = Node;
+ Node = Node->Next;
+ }
+ }
+
+ }
+ else {
+
+ // This is an ERROR condition, which should never occur. If it does
+ // talk to CHANDANC as soon as possible.
+ //
+
+ LOGDEBUG(0, ("WOW::WI32DDEDeletInitiator(): unthunking -- no Initiator\n"));
+ WOW32ASSERT (FALSE);
+ }
+}
+
+
+// This routine is used by DDE_ACK thunk to figure out how to thunk the
+// DDE_ACK message, ie, whether lParam is a combination of 2 atoms or
+// its a pointer to 32 bit packed structure.
+//
+
+BOOL WI32DDEInitiate(HAND16 Initiator)
+{
+ LPDDENODE Node;
+
+ Node = DDEInitiateList;
+
+ while (Node) {
+ if (Node->Initiator == Initiator) {
+ //
+ // DDE_Initiate is in progress for this Window
+ //
+
+ LOGDEBUG(12, ("WOW::WI32DDEInitiate(): thunking -- found an Initiator %08lX\n", Initiator));
+ return (TRUE);
+ }
+ else {
+ Node = Node->Next;
+ }
+ }
+ LOGDEBUG(12, ("WOW::WI32DDEInitiate(): thunking -- did not find an Initiator %08lX\n", Initiator));
+
+ //
+ // DDE_Initiate is not in progress for this Window
+ //
+
+ return (FALSE);
+}
+
+
+//
+// This routine determines if the current dde operation is a poke to MSDRAW
+// Pokes to MSDRAW for metafilepicts are special because the metafile pict
+// is part of the POKE block.
+//
+
+BOOL DDEIsTargetMSDraw(HAND16 To_hwnd)
+{
+ BOOL fStatus = FALSE;
+ HANDLE hInst;
+ HAND16 hModuleName;
+ LPSTR lpszModuleName16, lpszMsDraw = "MSDRAW.EXE";
+ WORD cchModuleName = MAX_PATH, cchMsDraw = 10;
+ VPVOID vp;
+ LPSTR lpszNewMsDrawKey = "MSDRAW\\protocol\\StdFileEditing\\verb";
+ HKEY hKey = NULL;
+ LONG Status;
+
+ //
+ // To check if the target is msdraw, check the following.
+ //
+ // - That the destination window hInst is that of a 16 bit task (this is
+ // checking to see if the LOWORD of the hInst is not 0.
+ // - That the module name is MSDRAW.
+ //
+ // NOTE: THERE ARE THREE CALLBACK16 ROUTINES IN THIS CALL, MAKING IT AN
+ // EXPENSIVE CALL. HOWEVER THIS CALL IS RARELY MADE.
+ //
+
+ if (
+ (hInst = (HANDLE)GetWindowLong((HWND)HWND32(To_hwnd),GWL_HINSTANCE))
+ && (LOWORD(hInst) != 0 )
+ && (vp = GlobalAllocLock16(GMEM_MOVEABLE, cchModuleName, &hModuleName))
+ ) {
+
+ //
+ // Callback 16 to get the module name of the current hInst
+ //
+
+ if (cchModuleName = GetModuleFileName16( LOWORD(hInst), vp, cchModuleName )) {
+ GETMISCPTR(vp, lpszModuleName16);
+ fStatus = (cchModuleName >= cchMsDraw)
+ && !_stricmp( lpszModuleName16 + (cchModuleName - cchMsDraw), lpszMsDraw )
+ && (Status = RegOpenKeyEx( HKEY_CLASSES_ROOT, lpszNewMsDrawKey, 0, KEY_READ, &hKey)) != ERROR_SUCCESS;
+
+ if (hKey) {
+ RegCloseKey( hKey );
+ }
+ FREEMISCPTR(lpszModuleName16);
+ }
+
+ //
+ // Cleanup
+ //
+
+ GlobalUnlockFree16(vp);
+ }
+ return ( fStatus );
+}
+
+
+
+// This routine converts a 32 bit DDE memory object into a 16 bit DDE
+// memory object. It also, does the data conversion from 32 bit to 16 bit
+// for the type of data.
+//
+// WARNING: The Copyh32Toh16() calls may cause 16-bit memory movement
+//
+
+HAND16 DDECopyhData16(HAND16 To_hwnd, HAND16 From_hwnd, HANDLE h32, PDDEINFO pDdeInfo)
+{
+ HAND16 h16 = 0;
+ VPVOID vp1, vp2;
+ DDEDATA *lpMem32;
+ DDEDATA16 *lpMem16;
+ int cb;
+
+ //
+ // NULL handle ?
+ //
+
+ if (!h32) {
+ LOGDEBUG(12, ("WOW::DDECopyhData16(): h32 is %08x\n", h32));
+ return 0;
+ }
+
+ cb = GlobalSize(h32);
+ lpMem32 = GlobalLock(h32);
+ LOGDEBUG(12, ("WOW::DDECopyhData16(): CF_FORMAT is %04x\n", lpMem32->cfFormat));
+
+ switch (lpMem32->cfFormat) {
+
+ default:
+
+ // This is intentional to let it thru to "case statements".
+ // ChandanC 5/11/92.
+
+ case CF_TEXT:
+ case CF_DSPTEXT:
+ case CF_SYLK:
+ case CF_DIF:
+ case CF_TIFF:
+ case CF_OEMTEXT:
+ case CF_PENDATA:
+ case CF_RIFF:
+ case CF_WAVE:
+ case CF_OWNERDISPLAY:
+ h16 = Copyh32Toh16 (cb, (LPBYTE) lpMem32);
+
+ pDdeInfo->Format = lpMem32->cfFormat;
+ break;
+
+ case CF_BITMAP:
+ case CF_DSPBITMAP:
+ vp1 = GlobalAllocLock16(GMEM_DDESHARE, (sizeof(DDEDATA)-1+sizeof(HAND16)), &h16);
+ if (vp1) {
+ pDdeInfo->Format = lpMem32->cfFormat;
+ GETMISCPTR(vp1, lpMem16);
+ RtlCopyMemory(lpMem16, lpMem32, 4);
+ STOREWORD(lpMem16->Value, GETHBITMAP16(*((HANDLE *)lpMem32->Value)));
+ FLUSHVDMPTR(vp1, (sizeof(DDEDATA)-1+sizeof(HAND16)), lpMem16);
+ FREEMISCPTR(lpMem16);
+ GlobalUnlock16(h16);
+ }
+ break;
+
+ case CF_PALETTE:
+ vp1 = GlobalAllocLock16(GMEM_DDESHARE, (sizeof(DDEDATA)-1+sizeof(HAND16)), &h16);
+ if (vp1) {
+ pDdeInfo->Format = lpMem32->cfFormat;
+ GETMISCPTR(vp1, lpMem16);
+ RtlCopyMemory(lpMem16, lpMem32, 4);
+ STOREWORD(lpMem16->Value, GETHPALETTE16(*((HANDLE *)lpMem32->Value)));
+ FLUSHVDMPTR(vp1, (sizeof(DDEDATA)-1+sizeof(HAND16)), lpMem16);
+ FREEMISCPTR(lpMem16);
+ GlobalUnlock16(h16);
+ }
+ break;
+
+ case CF_DIB:
+ {
+ LPBYTE lpMemDib32;
+ HAND16 hDib16 = 0;
+ HANDLE hDib32;
+
+ vp1 = GlobalAllocLock16(GMEM_DDESHARE, (sizeof(DDEDATA)-1+sizeof(HAND16)), &h16);
+ if (vp1) {
+
+ GETMISCPTR(vp1, lpMem16);
+ RtlCopyMemory(lpMem16, lpMem32, 4);
+ FREEMISCPTR(lpMem16);
+
+ hDib32 = (*((HANDLE *)lpMem32->Value));
+ if (hDib32) {
+ lpMemDib32 = GlobalLock(hDib32);
+ cb = GlobalSize(hDib32);
+ hDib16 = Copyh32Toh16 (cb, (LPBYTE) lpMemDib32);
+ GlobalUnlock(hDib32);
+ pDdeInfo->Format = lpMem32->cfFormat;
+ pDdeInfo->Flags = 0;
+ pDdeInfo->h16 = 0;
+ DDEAddhandle(To_hwnd, From_hwnd, (HAND16) hDib16, hDib32, pDdeInfo);
+
+ }
+
+ GETMISCPTR(vp1, lpMem16);
+ STOREWORD(lpMem16->Value, hDib16);
+ GlobalUnlock16(h16);
+ FLUSHVDMPTR(vp1, (sizeof(DDEDATA)-1+sizeof(HAND16)), lpMem16);
+ FREEMISCPTR(lpMem16);
+ }
+ }
+ break;
+
+ case CF_METAFILEPICT:
+ case CF_DSPMETAFILEPICT:
+ {
+ HANDLE hMeta32, hMF32 = NULL;
+ HAND16 hMeta16 = 0, hMF16 = 0;
+ LPMETAFILEPICT lpMemMeta32;
+ LPMETAFILEPICT16 lpMemMeta16;
+ BOOL IsMSDRAWPoke;
+
+ //
+ // We need to find out if the to_handle is MSDRAW, in which case
+ // we should copy the METAFILEPICT data to the DDEPOKE instead
+ // of a handle to the METAFILEPICT.
+
+ if( IsMSDRAWPoke = ((pDdeInfo->Msg == WM_DDE_POKE) && DDEIsTargetMSDraw(To_hwnd)) ) {
+ cb = sizeof(DDEPOKE)-1+sizeof(METAFILEPICT16);
+ }
+ else {
+ cb = sizeof(DDEDATA)-1+sizeof(HAND16);
+ }
+ vp1 = GlobalAllocLock16(GMEM_DDESHARE, cb, &h16);
+
+
+ if (vp1) {
+ GETMISCPTR(vp1, lpMem16);
+ RtlCopyMemory(lpMem16, lpMem32, 4);
+ hMeta32 = (*((HANDLE *)lpMem32->Value));
+
+ if ( IsMSDRAWPoke ) {
+
+ lpMemMeta16 = (LPMETAFILEPICT16)((PBYTE)lpMem16 + sizeof(DDEPOKE) - 1);
+ RtlZeroMemory( (PVOID)lpMemMeta16, sizeof (METAFILEPICT16) );
+ if (hMeta32) {
+ lpMemMeta32 = GlobalLock(hMeta32);
+ FixMetafile32To16 (lpMemMeta32, lpMemMeta16);
+ FREEMISCPTR(lpMem16);
+
+ hMF32 = lpMemMeta32->hMF;
+ if (hMF32) {
+ hMF16 = WinMetaFileFromHMF(hMF32, FALSE);
+ pDdeInfo->Format = lpMem32->cfFormat;
+ pDdeInfo->h16 = 0;
+ pDdeInfo->Flags = DDE_METAFILE;
+ DDEAddhandle(To_hwnd, From_hwnd, (HAND16) hMF16, hMF32, pDdeInfo);
+ }
+
+ GETMISCPTR(vp1, lpMem16);
+ lpMemMeta16 = (LPMETAFILEPICT16)((PBYTE)lpMem16 + sizeof(DDEPOKE) - 1);
+ STOREWORD(lpMemMeta16->hMF, hMF16);
+ GlobalUnlock(hMeta32);
+ }
+
+ }
+ else {
+ if (hMeta32) {
+ lpMemMeta32 = GlobalLock(hMeta32);
+ FREEMISCPTR(lpMem16);
+ vp2 = GlobalAllocLock16(GMEM_DDESHARE, sizeof(METAFILEPICT16), &hMeta16);
+ WOW32ASSERT(vp2);
+ if (vp2) {
+ GETMISCPTR(vp2, lpMemMeta16);
+ FixMetafile32To16 (lpMemMeta32, lpMemMeta16);
+ FREEMISCPTR(lpMemMeta16);
+
+ pDdeInfo->Format = lpMem32->cfFormat;
+ pDdeInfo->Flags = 0;
+ pDdeInfo->h16 = 0;
+ DDEAddhandle(To_hwnd, From_hwnd, (HAND16) hMeta16, hMeta32, pDdeInfo);
+ hMF32 = lpMemMeta32->hMF;
+ if (hMF32) {
+ hMF16 = WinMetaFileFromHMF(hMF32, FALSE);
+ pDdeInfo->Flags = DDE_METAFILE;
+ DDEAddhandle(To_hwnd, From_hwnd, (HAND16) hMF16, hMF32, pDdeInfo);
+ }
+
+ GETMISCPTR(vp2, lpMemMeta16);
+ STOREWORD(lpMemMeta16->hMF, hMF16);
+ GlobalUnlock16(hMeta16);
+ FLUSHVDMPTR(vp2, 8, lpMemMeta16);
+ FREEMISCPTR(lpMemMeta16);
+ }
+ GlobalUnlock(hMeta32);
+ }
+ GETMISCPTR(vp1, lpMem16);
+ STOREWORD(lpMem16->Value, hMeta16);
+ }
+
+ GlobalUnlock16(h16);
+ FLUSHVDMPTR(vp1, cb, lpMem16);
+ FREEMISCPTR(lpMem16);
+ }
+ }
+ break;
+ }
+
+ GlobalUnlock(h32);
+
+ return (h16);
+}
+
+
+
+
+// This routine converts a 16 bit DDE memory object into a 32 bit DDE
+// memory object. It also, does the data conversion from 16 bit to 32 bit
+// for the type of data.
+//
+
+HANDLE DDECopyhData32(HAND16 To_hwnd, HAND16 From_hwnd, HAND16 h16, PDDEINFO pDdeInfo)
+{
+ HANDLE h32 = NULL;
+ INT cb;
+ VPVOID vp;
+ DDEDATA *lpMem16;
+ DDEDATA32 *lpMem32;
+
+ //
+ // AmiPro passes a NULL handle.
+ //
+
+ if (!h16) {
+ LOGDEBUG(12, ("WOW::DDECopyhData16(): h16 is %04x\n", h16));
+ return (HANDLE) NULL;
+ }
+
+ vp = GlobalLock16(h16, &cb);
+ GETMISCPTR(vp, lpMem16);
+ LOGDEBUG(12, ("WOW::DDECopyhData32(): CF_FORMAT is %04x\n", lpMem16->cfFormat));
+
+ switch(lpMem16->cfFormat) {
+
+ default:
+
+ // This is intentional to let it thru to the "case statements".
+ // ChandanC 5/11/92.
+
+ case CF_TEXT:
+ case CF_DSPTEXT:
+ case CF_SYLK:
+ case CF_DIF:
+ case CF_TIFF:
+ case CF_OEMTEXT:
+ case CF_PENDATA:
+ case CF_RIFF:
+ case CF_WAVE:
+ case CF_OWNERDISPLAY:
+ h32 = Copyh16Toh32 (cb, (LPBYTE) lpMem16);
+
+ pDdeInfo->Format = lpMem16->cfFormat;
+ break;
+
+ case CF_BITMAP:
+ case CF_DSPBITMAP:
+ h32 = GlobalAlloc(GMEM_DDESHARE, (sizeof(DDEDATA)-1+sizeof(HANDLE)));
+ if (h32) {
+ pDdeInfo->Format = lpMem16->cfFormat;
+ lpMem32 = GlobalLock(h32);
+ RtlCopyMemory(lpMem32, lpMem16, 4);
+ lpMem32->Value = HBITMAP32(FETCHWORD(*((WORD *)lpMem16->Value)));
+ GlobalUnlock(h32);
+ }
+ break;
+
+ case CF_PALETTE:
+ h32 = GlobalAlloc(GMEM_DDESHARE, (sizeof(DDEDATA)-1+sizeof(HANDLE)));
+ if (h32) {
+ pDdeInfo->Format = lpMem16->cfFormat;
+ lpMem32 = GlobalLock(h32);
+ RtlCopyMemory(lpMem32, lpMem16, 4);
+ lpMem32->Value = HPALETTE32(FETCHWORD(*((WORD *)lpMem16->Value)));
+ GlobalUnlock(h32);
+ }
+ break;
+
+ case CF_DIB:
+ {
+ LPBYTE lpMemDib16;
+ HAND16 hDib16;
+ HANDLE hDib32 = NULL;
+
+ h32 = GlobalAlloc(GMEM_DDESHARE, (sizeof(DDEDATA)-1+sizeof(HANDLE)));
+ if (h32) {
+ lpMem32 = GlobalLock(h32);
+ RtlCopyMemory(lpMem32, lpMem16, 4);
+
+ hDib16 = FETCHWORD(*((WORD *)lpMem16->Value));
+ if (hDib16) {
+ vp = GlobalLock16(hDib16, &cb);
+ GETMISCPTR(vp, lpMemDib16);
+ hDib32 = Copyh16Toh32 (cb, (LPBYTE) lpMemDib16);
+
+ pDdeInfo->Format = lpMem16->cfFormat;
+ pDdeInfo->Flags = 0;
+ pDdeInfo->h16 = 0;
+ DDEAddhandle(To_hwnd, From_hwnd, (HAND16) hDib16, hDib32, pDdeInfo);
+
+ GlobalUnlock16(hDib16);
+ FREEMISCPTR(lpMemDib16);
+ }
+ lpMem32->Value = hDib32;
+ GlobalUnlock(h32);
+ }
+ }
+ break;
+
+ case CF_METAFILEPICT:
+ case CF_DSPMETAFILEPICT:
+ {
+ HANDLE hMeta32 = NULL, hMF32 = NULL;
+ HAND16 hMeta16, hMF16 = 0;
+ LPMETAFILEPICT lpMemMeta32;
+ LPMETAFILEPICT16 lpMemMeta16;
+
+ h32 = GlobalAlloc(GMEM_DDESHARE, (sizeof(DDEDATA)-1+sizeof(HANDLE)));
+ if (h32) {
+ lpMem32 = GlobalLock(h32);
+ RtlCopyMemory(lpMem32, lpMem16, 4);
+
+ //
+ // MSDRAW has the METAFILEPICT in the DDEPOKE block instead of
+ // a handle to the METAFILEPICT. So we need to find out if the
+ // to handle belongs to MSDRAW. Since MSDRAW is a 16 bit
+ // server we needn't thunk the metafilepict at all, we will just
+ // use NULL as the 32 bit handle to the metafilepict.
+ //
+
+ hMeta32 = NULL;
+ if( !((pDdeInfo->Msg == WM_DDE_POKE) && DDEIsTargetMSDraw(To_hwnd)) ) {
+
+ hMeta16 = FETCHWORD(*((WORD *)lpMem16->Value));
+
+ //
+ // Make sure that a valid metafile pict handle has been
+ // passed in otherwise use NULL again as the hMeta32.
+ //
+
+ if (hMeta16 && (vp = GlobalLock16(hMeta16, &cb))) {
+ GETMISCPTR(vp, lpMemMeta16);
+ hMeta32 = GlobalAlloc(GMEM_DDESHARE, sizeof(METAFILEPICT));
+ WOW32ASSERT(hMeta32);
+ if (hMeta32) {
+ lpMemMeta32 = GlobalLock(hMeta32);
+ lpMemMeta32->mm = (LONG) FETCHSHORT(lpMemMeta16->mm);
+ lpMemMeta32->xExt = (LONG) FETCHSHORT(lpMemMeta16->xExt);
+ lpMemMeta32->yExt = (LONG) FETCHSHORT(lpMemMeta16->yExt);
+ pDdeInfo->Format = lpMem16->cfFormat;
+ pDdeInfo->Flags = 0;
+ pDdeInfo->h16 = 0;
+ DDEAddhandle(To_hwnd, From_hwnd, (HAND16) hMeta16, hMeta32, pDdeInfo);
+
+ hMF16 = FETCHWORD(lpMemMeta16->hMF);
+
+ if (hMF16) {
+ hMF32 = (HMETAFILE) HMFFromWinMetaFile(hMF16, FALSE);
+ pDdeInfo->Flags = DDE_METAFILE;
+ DDEAddhandle(To_hwnd, From_hwnd, (HAND16) hMF16, hMF32, pDdeInfo);
+ }
+
+ lpMemMeta32->hMF = (HMETAFILE) hMF32;
+ GlobalUnlock(hMeta32);
+ }
+ GlobalUnlock16(hMeta16);
+ FREEMISCPTR(lpMemMeta16);
+ }
+ }
+ lpMem32->Value = hMeta32;
+ GlobalUnlock(h32);
+ }
+ }
+ break;
+ }
+
+ GlobalUnlock16(h16);
+
+ FREEMISCPTR(lpMem16);
+ return (h32);
+}
+
+
+/****** These routines maintain a linked list of dde handles, which
+******* are the h16 and h32 pairs.
+******/
+
+
+
+// This routine adds the given h16-h32 pair to the linked list, and updates
+// the list.
+//
+
+BOOL DDEAddhandle(HAND16 To_hwnd, HAND16 From_hwnd, HAND16 hMem16, HANDLE hMem32, PDDEINFO pDdeInfo)
+{
+ PHDDE phTemp;
+
+ if (hMem16 && hMem32) {
+ if (phTemp = malloc_w (sizeof(HDDE))) {
+ phTemp->hMem16 = hMem16;
+ phTemp->hMem32 = hMem32;
+ phTemp->To_hwnd = To_hwnd;
+ phTemp->From_hwnd = From_hwnd;
+
+ phTemp->DdeMsg = pDdeInfo->Msg;
+ phTemp->DdeFormat = pDdeInfo->Format;
+ phTemp->DdeFlags = pDdeInfo->Flags;
+
+ phTemp->h16 = pDdeInfo->h16;
+
+ phTemp->pDDENext = phDDEFirst; // insert at the top
+ phDDEFirst = phTemp; // update list head
+
+ // Mark the GAH_WOWDDEFREEHANDLE (ie GAH_PAHTOM) bit in the global
+ // arena of this handle.
+
+ W32MarkDDEHandle (hMem16);
+
+ return (TRUE);
+ }
+ else {
+ LOGDEBUG(2, ("WOW::DDEAddhandle(): *** memory allocation failed *** \n"));
+ return (FALSE);
+ }
+ }
+
+ LOGDEBUG(2,("WOW::DDEAddhandle(): *** ERROR *** one of the handles is NULL \n"));
+ return (FALSE);
+}
+
+
+// This routine deletes the given h16-h32 pair from the list and frees up
+// the memory.
+//
+
+BOOL DDEDeletehandle(HAND16 h16, HANDLE h32)
+{
+ PHDDE phTemp1, phTemp2;
+
+ phTemp1 = phDDEFirst;
+
+ if ((phTemp1->hMem16 == h16) && (phTemp1->hMem32 == h32)) { // first node
+ phDDEFirst = phTemp1->pDDENext;
+ free_w(phTemp1);
+ return (TRUE);
+ }
+ else { // rest of the list
+ phTemp2 = phTemp1;
+ phTemp1 = phTemp1->pDDENext;
+
+ while (phTemp1) {
+ if ((phTemp1->hMem16 == h16) && (phTemp1->hMem32 == h32)) {
+ phTemp2->pDDENext = phTemp1->pDDENext;
+ free_w(phTemp1);
+ return (TRUE);
+ }
+ phTemp2 = phTemp1;
+ phTemp1 = phTemp1->pDDENext;
+ }
+
+ LOGDEBUG (2, ("WOW::DDEDeleteHandle : Can't find a 16-32 memory pair\n"));
+// WOW32ASSERT (FALSE);
+
+ return (FALSE);
+ }
+}
+
+
+// This routine finds a hMem16 for a DDE conversation, if one exists.
+//
+
+HAND16 DDEFindPair16(HAND16 To_hwnd, HAND16 From_hwnd, HANDLE hMem32)
+{
+ PHDDE phTemp;
+
+ phTemp = phDDEFirst;
+
+ while (phTemp) {
+ if ((phTemp->To_hwnd == To_hwnd) &&
+ (phTemp->From_hwnd == From_hwnd) &&
+ (phTemp->hMem32 == hMem32)) {
+ return (phTemp->hMem16);
+ }
+ else {
+ phTemp = phTemp->pDDENext;
+ }
+ }
+ return (HAND16) NULL;
+}
+
+
+// This routine finds a hMem32 for a DDE conversation, if one exists.
+//
+
+HANDLE DDEFindPair32(HAND16 To_hwnd, HAND16 From_hwnd, HAND16 hMem16)
+{
+ PHDDE phTemp;
+
+ phTemp = phDDEFirst;
+
+ while (phTemp) {
+ if ((phTemp->To_hwnd == To_hwnd) &&
+ (phTemp->From_hwnd == From_hwnd) &&
+ (phTemp->hMem16 == hMem16)) {
+ return (phTemp->hMem32);
+ }
+ else {
+ phTemp = phTemp->pDDENext;
+ }
+ }
+ return (HANDLE) NULL;
+}
+
+
+// This routine find the DDE node that is doing DDE conversation
+//
+
+PHDDE DDEFindNode16 (HAND16 h16)
+{
+ PHDDE phTemp;
+
+ phTemp = phDDEFirst;
+
+ while (phTemp) {
+ if (phTemp->hMem16 == h16) {
+ return (phTemp);
+ }
+ phTemp = phTemp->pDDENext;
+ }
+
+ return (NULL);
+}
+
+
+// This routine find the DDE node that is doing DDE conversation
+//
+
+PHDDE DDEFindNode32 (HANDLE h32)
+{
+ PHDDE phTemp;
+
+ phTemp = phDDEFirst;
+
+ while (phTemp) {
+ if (phTemp->hMem32 == h32) {
+ return (phTemp);
+ }
+ phTemp = phTemp->pDDENext;
+ }
+
+ return (NULL);
+}
+
+
+// This routine returns a pointer to the DDE node, if the conversation exists,
+// else it retunrs NULL
+
+PHDDE DDEFindAckNode (HAND16 To_hwnd, HAND16 From_hwnd, HANDLE hMem32)
+{
+ PHDDE phTemp;
+
+ phTemp = phDDEFirst;
+
+ while (phTemp) {
+ if ((phTemp->To_hwnd == To_hwnd) &&
+ (phTemp->From_hwnd == From_hwnd) &&
+ (phTemp->hMem32 == hMem32)) {
+ return (phTemp);
+ }
+ else {
+ phTemp = phTemp->pDDENext;
+ }
+ }
+ return (PHDDE) NULL;
+}
+
+
+// This function marks GAH_WOWDDEFREEHANDLE bit in the global arena of the
+// hMem16.
+//
+
+VOID W32MarkDDEHandle (HAND16 hMem16)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+
+ Parm16.WndProc.wParam = hMem16;
+ Parm16.WndProc.wMsg = 1;
+ CallBack16(RET_WOWDDEFREEHANDLE, &Parm16, 0, &vp);
+}
+
+VOID W32UnMarkDDEHandle (HAND16 hMem16)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+
+ Parm16.WndProc.wParam = hMem16;
+ Parm16.WndProc.wMsg = 0;
+ CallBack16(RET_WOWDDEFREEHANDLE, &Parm16, 0, &vp);
+}
+
+// This function frees the 32 and 16 bit memory. It is called by 32 bit
+// BASE by GlobalFree.
+//
+
+BOOL W32DDEFreeGlobalMem32 (HANDLE h32)
+{
+ HAND16 h16;
+ PHDDE pDdeNode;
+ BOOL fOkToFree = TRUE;
+
+ if (h32) {
+ if (pDdeNode = DDEFindNode32(h32)) {
+
+ if (pDdeNode->DdeFlags & DDE_METAFILE) {
+ LOGDEBUG (12, ("WOW32: W32DDEFreeGlobalMem32: Freeing MetaFile hMF32 %x\n", h32));
+ DeleteMetaFile (h32);
+ fOkToFree = FALSE;
+ }
+
+ while ((pDdeNode) && (h16 = pDdeNode->hMem16)) {
+ W32UnMarkDDEHandle (h16);
+ GlobalUnlockFree16(GlobalLock16(h16, NULL));
+ DDEDeletehandle(h16, h32);
+ pDdeNode = DDEFindNode32(h32);
+ }
+ }
+ else {
+
+ LOGDEBUG (2, ("WOW32: W32DDEFreeGlobalMem32: Can't find a 16-32 memory pair\n"));
+ }
+ }
+ else {
+ WOW32ASSERTMSG(FALSE, "WOW32: W32DDEFreeGlobalMem32: h32 is NULL to Win32 GlobalFree\n");
+ /*
+ * since in this case the Failure and Success return values from
+ * GlobalFree are NULL, just return false so things are faster
+ * in GlobalFree.
+ */
+ fOkToFree = FALSE;
+ }
+
+ return(fOkToFree);
+}
+
+
+// This function frees only the 32 bit memory because the 16 bit memory
+// is being free'd by the 16 bit app. We are just getting the
+// notification of this fact. So free the corresponding 32 bit memory.
+//
+
+BOOL FASTCALL W32WowDdeFreeHandle (PVDMFRAME pFrame)
+{
+ ULONG ul;
+ HAND16 h16;
+ PWOWDDEFREEHANDLE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(WOWDDEFREEHANDLE16), parg16);
+
+ h16 = (HAND16) parg16->h16;
+
+ ul = W32DdeFreeHandle16 (h16);
+
+ FREEARGPTR(parg16);
+ RETURN (ul);
+}
+
+
+BOOL W32DdeFreeHandle16 (HAND16 h16)
+{
+ HANDLE h32;
+ PHDDE pDdeNode;
+
+ if (!(pDdeNode = DDEFindNode16(h16))) {
+ LOGDEBUG (12, ("WOW::W32DdeFreeHandle16 : Not found h16 -> %04x\n", h16));
+ return (TRUE);
+ }
+
+ LOGDEBUG (12, ("WOW::W32DdeFreeHandle16 : Entering... h16 -> %04x\n", h16));
+
+ if (pDdeNode->DdeMsg == WM_DDE_EXECUTE) {
+ LOGDEBUG (12, ("WOW::W32DdeFreeHandle16 : App TRYING !!! to freeing EXECUTE h16 -> %04x\n", h16));
+ pDdeNode->DdeFlags = pDdeNode->DdeFlags | DDE_EXECUTE_FREE_MEM;
+ return (FALSE);
+ }
+ else {
+ while ((pDdeNode) && (h32 = pDdeNode->hMem32)) {
+ if (pDdeNode->DdeFlags & DDE_METAFILE) {
+ DDEDeletehandle(h16, h32);
+ DeleteMetaFile (h32);
+ }
+ else {
+ /*
+ * REMOVE THE PAIR FIRST!!!
+ * Since GlobalFree will hook back to W32DDEFreeGlobalMem32
+ * we want to remove the handle from our tables before
+ * the call.
+ */
+ DDEDeletehandle(h16, h32);
+ GlobalFree(h32);
+ }
+
+ pDdeNode = DDEFindNode16(h16);
+ }
+ }
+
+ LOGDEBUG (12, ("WOW::W32DdeFreeHandle16 : Leaving ...\n"));
+ return (TRUE);
+}
+
+
+// This routine adds the given h16-h32 CopyData pair to the linked list,
+// and updates the list.
+//
+
+BOOL CopyDataAddNode (HAND16 To_hwnd, HAND16 From_hwnd, DWORD Mem16, DWORD Mem32, DWORD Flags)
+{
+ PCPDATA pTemp;
+
+ if (Mem16 && Mem32) {
+ if (pTemp = malloc_w (sizeof(CPDATA))) {
+ pTemp->Mem16 = Mem16;
+ pTemp->Mem32 = Mem32;
+ pTemp->To_hwnd = To_hwnd;
+ pTemp->From_hwnd= From_hwnd;
+ pTemp->Flags = Flags;
+ pTemp->Next = pCPDataFirst; // insert at the top
+ pCPDataFirst = pTemp; // update list head
+
+ return (TRUE);
+ }
+ else {
+ LOGDEBUG(2, ("WOW::CopyDataAddNode: *** memory allocation failed *** \n"));
+ return (FALSE);
+ }
+ }
+
+ LOGDEBUG(2,("WOW::CopyDataAddNode: *** ERROR *** one of the memory pointers is NULL \n"));
+ return (FALSE);
+}
+
+
+VPVOID CopyDataFindData16 (HWND16 To_hwnd, HWND16 From_hwnd, DWORD Mem)
+{
+ PCPDATA pTemp;
+
+ pTemp = pCPDataFirst;
+
+ while (pTemp) {
+ if ((pTemp->To_hwnd == To_hwnd) &&
+ (pTemp->From_hwnd == From_hwnd) &&
+ (pTemp->Mem32 == Mem)) {
+ return (pTemp->Mem16);
+ }
+ else {
+ pTemp = pTemp->Next;
+ }
+ }
+ return 0;
+}
+
+
+PCPDATA CopyDataFindData32 (HWND16 To_hwnd, HWND16 From_hwnd, DWORD Mem)
+{
+ PCPDATA pTemp;
+
+ pTemp = pCPDataFirst;
+
+ while (pTemp) {
+ if ((pTemp->To_hwnd == To_hwnd) &&
+ (pTemp->From_hwnd == From_hwnd) &&
+ (pTemp->Mem16 == Mem)) {
+ return (pTemp);
+ }
+ else {
+ pTemp = pTemp->Next;
+ }
+ }
+ return 0;
+}
+
+
+// This routine deletes the given h16-h32 pair from the list.
+//
+//
+
+BOOL CopyDataDeleteNode (HWND16 To_hwnd, HWND16 From_hwnd, DWORD Mem)
+{
+ PCPDATA pTemp1;
+ PCPDATA pTemp2;
+
+ pTemp1 = pCPDataFirst;
+
+ if ((pTemp1->To_hwnd == To_hwnd) &&
+ (pTemp1->From_hwnd == From_hwnd) &&
+ (pTemp1->Mem32 == Mem)) {
+ pCPDataFirst = pTemp1->Next;
+ free_w (pTemp1);
+ return (TRUE);
+ }
+ else {
+ pTemp2 = pTemp1;
+ pTemp1 = pTemp1->Next;
+
+ while (pTemp1) {
+ if ((pTemp1->To_hwnd == To_hwnd) &&
+ (pTemp1->From_hwnd == From_hwnd) &&
+ (pTemp1->Mem32 == Mem)) {
+ pTemp2->Next = pTemp1->Next;
+ free_w (pTemp1);
+ return (TRUE);
+ }
+
+ pTemp2 = pTemp1;
+ pTemp1 = pTemp1->Next;
+ }
+ return (FALSE);
+ }
+
+}
+
+
+// While allocating GMEM_DDESHARE memory object should we have GMEM_MOVEABLE
+// flag or not ???????????????????
+// ChandanC Sept 23rd 1993.
+//
+// WARNING: This function may cause 16-bit memory movement.
+//
+
+HAND16 Copyh32Toh16 (int cb, LPBYTE lpMem32)
+{
+ HAND16 h16 = 0;
+ LPBYTE lpMem16;
+ VPVOID vp;
+
+ vp = GlobalAllocLock16(GMEM_DDESHARE | GMEM_MOVEABLE, cb, &h16);
+ WOW32ASSERT(vp);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ RtlCopyMemory(lpMem16, lpMem32, cb);
+ GlobalUnlock16(h16);
+ FLUSHVDMPTR(vp, cb, lpMem16);
+ FREEMISCPTR(lpMem16);
+ }
+
+ return (h16);
+}
+
+
+HANDLE Copyh16Toh32 (int cb, LPBYTE lpMem16)
+{
+ HANDLE hMem32;
+ LPBYTE lpMem32;
+
+ hMem32 = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cb);
+ WOW32ASSERT(hMem32);
+ if (hMem32) {
+ lpMem32 = GlobalLock(hMem32);
+ RtlCopyMemory (lpMem32, lpMem16, cb);
+ GlobalUnlock(hMem32);
+ }
+
+ return (hMem32);
+}
+
+
+VOID FixMetafile32To16 (LPMETAFILEPICT lpMemMeta32, LPMETAFILEPICT16 lpMemMeta16)
+{
+
+ if (lpMemMeta32->mm == MM_ANISOTROPIC) {
+ LONG xExt = lpMemMeta32->xExt;
+ LONG yExt = lpMemMeta32->yExt;
+
+ while (xExt < (LONG)(SHORT)MINSHORT
+ || xExt > (LONG)(SHORT)MAXSHORT
+ || yExt < (LONG)(SHORT)MINSHORT
+ || yExt > (LONG)(SHORT)MAXSHORT) {
+ xExt = xExt / 2;
+ yExt = yExt / 2;
+ }
+ STORESHORT(lpMemMeta16->mm, MM_ANISOTROPIC);
+ STORESHORT(lpMemMeta16->xExt, xExt);
+ STORESHORT(lpMemMeta16->yExt, yExt);
+ }
+ else {
+ STORESHORT(lpMemMeta16->mm, lpMemMeta32->mm);
+ STORESHORT(lpMemMeta16->xExt, lpMemMeta32->xExt);
+ STORESHORT(lpMemMeta16->yExt, lpMemMeta32->yExt);
+ }
+}
+
+//
+// CHEESE ALERT: This function is exported for the OLE DDE code
+// to call so it can correctly free up metafile handle pairs in
+// a VDM. This function is NOT found in any header files. If you
+// change this, you need to find its use in the OLE project.
+// Probably best to just leave it alone.
+//
+BOOL WINAPI WOWFreeMetafile( HANDLE h32 )
+{
+ return( W32DDEFreeGlobalMem32( h32 ) );
+}
diff --git a/private/mvdm/wow32/wdde.h b/private/mvdm/wow32/wdde.h
new file mode 100644
index 000000000..78ffe834e
--- /dev/null
+++ b/private/mvdm/wow32/wdde.h
@@ -0,0 +1,120 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WDDE.H
+ * WOW32 DDE worker routines.
+ *
+ * History:
+ * WOW DDE support designed and developed by ChandanC
+ *
+--*/
+
+#include "wowclip.h"
+
+typedef struct _DDENODE {
+ HAND16 Initiator;
+ struct _DDENODE *Next;
+} DDENODE, *LPDDENODE;
+
+
+/* DDE h16 and h32 object alias structure
+ */
+
+typedef struct _HDDE {
+ struct _HDDE *pDDENext; // pointer to next hDDE alias
+ HAND16 To_hwnd; // window that will receive this message
+ HAND16 From_hwnd; // window that sent this message
+ HAND16 hMem16; // handle of WOW app allocated 16 bit object
+ HANDLE hMem32; // handle of WOW allocated 32 bit object
+ WORD DdeMsg; // message id
+ WORD DdeFormat; // message format
+ WORD DdeFlags; // indicates if it is metafile handle
+ HAND16 h16; // original h16 for bad apps doing EXECUTE
+} HDDE, *PHDDE;
+
+
+typedef struct _DDEINFO {
+ WORD Msg; // message id
+ WORD Format; // message format
+ WORD Flags; // indicates if it is metafile handle
+ HAND16 h16; // original h16 for bad apps doing EXECUTE
+} DDEINFO, *PDDEINFO;
+
+
+typedef struct _CPDATA {
+ struct _CPDATA *Next; // pointer to next CopyData alias
+ HAND16 To_hwnd; // window that will receive this message
+ HAND16 From_hwnd; // window that sent this message
+ DWORD Mem16; // handle of allocated 16 bit object
+ DWORD Mem32; // handle of allocated 32 bit object
+ DWORD Flags; // No real structure is complete without flags
+} CPDATA, *PCPDATA;
+
+
+// This is used by GetMessage to thunk a 32 bit message to the 16 bit
+// message.
+
+#define FREEDDEML 0x0001
+#define DDE_EXECUTE_FREE_H16 0x0001
+#define DDE_EXECUTE_FREE_MEM 0x0002
+#define DDE_METAFILE 0x0004
+#define DDE_PACKET 0x0008
+
+
+// This flag is used when a 16 bit app sends data using WM_COPYDATA message
+//
+
+#define COPYDATA_16 0x0001
+
+/*----------------------------------------------------------------------------
+| DDEDATA structure
+|
+| WM_DDE_DATA parameter structure for hData (LOWORD(lParam)).
+| The actual size of this structure depends on the size of
+| the Value array.
+|
+----------------------------------------------------------------------------*/
+
+typedef struct {
+ unsigned short wStatus;
+ short cfFormat;
+ HAND16 Value;
+} DDEDATA16;
+
+typedef struct {
+ unsigned short wStatus;
+ short cfFormat;
+ HANDLE Value;
+} DDEDATA32;
+
+
+VOID WI32DDEAddInitiator (HAND16 Initiator);
+VOID WI32DDEDeleteInitiator(HAND16 Initiator);
+BOOL WI32DDEInitiate(HAND16 Initiator);
+BOOL DDEDeletehandle(HAND16 h16, HANDLE h32);
+HANDLE DDEFind32(HAND16 h16);
+HAND16 DDEFind16(HANDLE h32);
+BOOL DDEAddhandle(HAND16 To_hwnd, HAND16 From_hwnd, HAND16 hMem16, HANDLE hMem32, PDDEINFO pDdeInfo);
+HAND16 DDECopyhData16(HAND16 To_hwnd, HAND16 From_hwnd, HANDLE h32, PDDEINFO pDdeInfo);
+HANDLE DDECopyhData32(HAND16 To_hwnd, HAND16 From_hwnd, HAND16 h16, PDDEINFO pDdeInfo);
+VOID W32MarkDDEHandle (HAND16 hMem16);
+VOID W32UnMarkDDEHandle (HAND16 hMem16);
+HANDLE DDEFindPair32(HAND16 To_hwnd, HAND16 From_hwnd, HAND16 hMem16);
+HAND16 DDEFindPair16(HAND16 To_hwnd, HAND16 From_hwnd, HANDLE hMem32);
+BOOL W32DDEFreeGlobalMem32 (HANDLE h32);
+BOOL FASTCALL W32WowDdeFreeHandle (PVDMFRAME pFrame);
+BOOL W32DdeFreeHandle16 (HAND16 h16);
+PHDDE DDEFindNode16 (HAND16 h16);
+PHDDE DDEFindNode32 (HANDLE h32);
+PHDDE DDEFindAckNode (HAND16 To_hwnd, HAND16 From_hwnd, HANDLE hMem32);
+BOOL CopyDataAddNode (HAND16 To_hwnd, HAND16 From_hwnd, DWORD Mem16, DWORD Mem32, DWORD Flags);
+VPVOID CopyDataFindData16 (HWND16 To_hwnd, HWND16 From_hwnd, DWORD Mem);
+PCPDATA CopyDataFindData32 (HWND16 To_hwnd, HWND16 From_hwnd, DWORD Mem);
+BOOL CopyDataDeleteNode (HWND16 To_hwnd, HWND16 From_hwnd, DWORD Mem);
+BOOL DDEIsTargetMSDraw(HAND16 To_hwnd);
+HAND16 Copyh32Toh16 (int cb, LPBYTE lpMem32);
+HANDLE Copyh16Toh32 (int cb, LPBYTE lpMem16);
+VOID FixMetafile32To16 (LPMETAFILEPICT lpMemMeta32, LPMETAFILEPICT16 lpMemMeta16);
diff --git a/private/mvdm/wow32/wddeml32.c b/private/mvdm/wow32/wddeml32.c
new file mode 100644
index 000000000..48ab06047
--- /dev/null
+++ b/private/mvdm/wow32/wddeml32.c
@@ -0,0 +1,1360 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WDDEML.C
+ * WOW32 16-bit DDEML API support
+ *
+ * History:
+ * Jan-23-1993 Chandan Chauhan (ChandanC)
+ * Created.
+ *
+ * Things needed:
+ * CALLBACK to user to find out if a given data handle has been initialized.
+ * Have DdeDataBuf routines check the handle tables before converting DIBS
+ * and METAFILEPICT formatted data so we don't have a leak.
+ *
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wowclip.h"
+#include "wddeml32.h"
+#include "wowddeml.h"
+
+MODNAME(wddeml32.c);
+
+#ifdef DEBUG
+#define WOW32SAFEASSERTWARN(exp,msg) {\
+ if ((exp) == 0) {\
+ LOGDEBUG(1,(" WOW32 ERROR: %s failed", msg));\
+ WOW32ASSERT(FALSE); \
+ }\
+}
+#else
+#define WOW32SAFEASSERTWARN(exp,msg)
+#endif
+
+#ifdef DEBUG
+WORD ddeloglevel = 3;
+#define LOGDDEMLENTRY(pFrame) LOGARGS(ddeloglevel, pFrame)
+#define LOGDDEMLRETURN(pFrame, ret) LOGRETURN(ddeloglevel, pFrame, ret)
+#else
+#define LOGDDEMLENTRY(pFrame)
+#define LOGDDEMLRETURN(pFrame, ret)
+#endif
+
+BIND1632 aCallBack[MAX_CONVS] = {0};
+BIND1632 aAccessData[MAX_CONVS] = {0};
+
+ULONG FASTCALL WD32DdeInitialize(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ DWORD IdInst;
+ PDWORD16 p;
+ register PDDEINITIALIZE16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+
+ GETARGPTR(pFrame, sizeof(DDEINITIALIZE16), parg16);
+ GETMISCPTR (parg16->f1, p);
+
+ IdInst = *p;
+
+ ul = (ULONG)DdeInitialize(&IdInst, W32DdemlCallBack,
+ parg16->f3, parg16->f4);
+
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(DDEINITIALIZE16), parg16);
+
+ if (!*p) {
+ WOWDdemlBind ((DWORD)parg16->f2, IdInst, aCallBack);
+ }
+
+ *p = IdInst;
+
+ WOW32SAFEASSERTWARN(!ul, "WD32DdeInitialize\n");
+ FREEMISCPTR(p);
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+
+ FREEVDMPTR(pFrame);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeUninitialize(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDDEUNINITIALIZE16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEUNINITIALIZE16), parg16);
+
+ ul = (ULONG)DdeUninitialize(parg16->f1);
+
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(DDEUNINITIALIZE16), parg16);
+
+ if (ul) {
+ WOWDdemlUnBind ((DWORD)parg16->f1, aCallBack);
+ }
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeUninitialize\n");
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeConnectList(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ CONVCONTEXT CC;
+ register PDDECONNECTLIST16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDECONNECTLIST16), parg16);
+
+ W32GetConvContext (parg16->f5, &CC);
+
+ ul = (ULONG)DdeConnectList(parg16->f1, parg16->f2,
+ parg16->f3, parg16->f4,
+ (parg16->f5) ? &CC : NULL);
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeQueryNextServer(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDDEQUERYNEXTSERVER16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEQUERYNEXTSERVER16), parg16);
+
+ ul = (ULONG)DdeQueryNextServer(parg16->f1, parg16->f2);
+
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+#ifdef DEBUG
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ LOGDDEMLRETURN(pFrame, ul);
+ FREEVDMPTR(pFrame);
+#endif
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeDisconnectList(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDDEDISCONNECTLIST16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEDISCONNECTLIST16), parg16);
+
+ ul = (ULONG)DdeDisconnectList(parg16->f1);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeDisconnectList\n");
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+#ifdef DEBUG
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ LOGDDEMLRETURN(pFrame, ul);
+ FREEVDMPTR(pFrame);
+#endif
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeConnect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ CONVCONTEXT CC;
+ register PDDECONNECT16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDECONNECT16), parg16);
+
+ W32GetConvContext (parg16->f4, &CC);
+
+ ul = (ULONG)DdeConnect(parg16->f1, parg16->f2,
+ parg16->f3, (parg16->f4) ? &CC : NULL);
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+#ifdef DEBUG
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ LOGDDEMLRETURN(pFrame, ul);
+ FREEVDMPTR(pFrame);
+#endif
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeDisconnect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDDEDISCONNECT16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEDISCONNECT16), parg16);
+
+ ul = (ULONG)DdeDisconnect(parg16->f1);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeDisconnect\n");
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+#ifdef DEBUG
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ LOGDDEMLRETURN(pFrame, ul);
+ FREEVDMPTR(pFrame);
+#endif
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeQueryConvInfo(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ DWORD cb16;
+ CONVINFO ConvInfo;
+ CONVINFO16 ConvInfo16;
+ PCONVINFO16 pCI16;
+ register PDDEQUERYCONVINFO16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEQUERYCONVINFO16), parg16);
+
+ // Initialize the size to be of NT CONVINFO structure
+
+ ConvInfo.cb = sizeof(CONVINFO);
+ ul = (ULONG)DdeQueryConvInfo(parg16->f1, parg16->f2, &ConvInfo);
+
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(DDEQUERYCONVINFO16), parg16);
+
+ if (ul && parg16->f3) {
+ GETMISCPTR(parg16->f3, pCI16);
+ cb16 = pCI16->cb;
+ RtlCopyMemory (&ConvInfo16, &ConvInfo, (LPBYTE)&ConvInfo.wFmt - (LPBYTE)&ConvInfo);
+ ConvInfo16.wFmt = (WORD) ConvInfo.wFmt;
+ ConvInfo16.wType = (WORD) ConvInfo.wType;
+ ConvInfo16.wStatus = (WORD) ConvInfo.wStatus;
+ ConvInfo16.wConvst = (WORD) ConvInfo.wConvst;
+ ConvInfo16.wLastError = (WORD) ConvInfo.wLastError;
+ ConvInfo16.hConvList = (DWORD) ConvInfo.hConvList;
+ ConvInfo16.ConvCtxt.cb = (WORD) ConvInfo.ConvCtxt.cb;
+ ConvInfo16.ConvCtxt.wFlags = (WORD) ConvInfo.ConvCtxt.wFlags;
+ ConvInfo16.ConvCtxt.wCountryID = (WORD) ConvInfo.ConvCtxt.wCountryID;
+ ConvInfo16.ConvCtxt.iCodePage = (INT16) ConvInfo.ConvCtxt.iCodePage;
+ ConvInfo16.ConvCtxt.dwLangID = (DWORD) ConvInfo.ConvCtxt.dwLangID;
+ ConvInfo16.ConvCtxt.dwSecurity = (DWORD) ConvInfo.ConvCtxt.dwSecurity;
+ ConvInfo16.hwnd = (HWND16) ConvInfo.hwnd;
+ ConvInfo16.hwndPartner = (HWND16) ConvInfo.hwndPartner;
+ if (pCI16->cb > sizeof(CONVINFO16) || pCI16->cb == 0) {
+ /*
+ * If cb field is screwey assume it wasn't initialized properly
+ * by the app. Set it to the old CONVINFO16 size. (pre hwnd days)
+ */
+ pCI16->cb = sizeof(CONVINFO16) - sizeof(HAND16) - sizeof(HAND16);;
+ }
+ RtlCopyMemory (pCI16, (PVOID)&ConvInfo16, cb16);
+ pCI16->cb = cb16;
+ FREEMISCPTR(pCI16);
+ }
+ else {
+ WOW32SAFEASSERTWARN(ul, "WD32QueryConvInfo\n");
+ }
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+ FREEVDMPTR(pFrame);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeSetUserHandle(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDDESETUSERHANDLE16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDESETUSERHANDLE16), parg16);
+
+ ul = (ULONG)DdeSetUserHandle(parg16->f1, parg16->f2, parg16->f3);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeSetUserHandle\n");
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+#ifdef DEBUG
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ LOGDDEMLRETURN(pFrame, ul);
+ FREEVDMPTR(pFrame);
+#endif
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeClientTransaction(PVDMFRAME pFrame)
+{
+ ULONG ul = 1;
+ LPBYTE lpByte = NULL;
+ DWORD Uresult;
+ PVOID p;
+ PDWORD16 pul;
+ register PDDECLIENTTRANSACTION16 parg16;
+ DWORD cbData;
+ DWORD cbOffset;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDECLIENTTRANSACTION16), parg16);
+
+ cbData = parg16->f2;
+ cbOffset = 0;
+ if (parg16->f1 && cbData && cbData != -1) { // -1 means p is a data handle
+ GETMISCPTR(parg16->f1, p);
+ ul = (ULONG)DdeDataBuf16to32 (p, &lpByte, &cbData, &cbOffset, parg16->f5);
+ WOW32SAFEASSERTWARN(ul, "WD32DdeClientTransaction:data conversion failed.\n");
+ FREEMISCPTR(p);
+ }
+ if (ul) {
+ ul = (ULONG)DdeClientTransaction(lpByte ? lpByte : (LPBYTE)parg16->f1,
+ cbData,
+ parg16->f3,
+ parg16->f4,
+ parg16->f5,
+ parg16->f6,
+ parg16->f7,
+ &Uresult);
+ }
+ if (lpByte) {
+ free_w (lpByte);
+ }
+
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(DDECLIENTTRANSACTION16), parg16);
+
+ if (ul && parg16->f8) {
+ GETMISCPTR (parg16->f8, pul);
+ *pul = Uresult;
+ FREEMISCPTR(pul);
+ }
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+
+ FREEVDMPTR(pFrame);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeAbandonTransaction(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDDEABANDONTRANSACTION16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEABANDONTRANSACTION16), parg16);
+
+ ul = (ULONG)DdeAbandonTransaction(parg16->f1, parg16->f2, parg16->f3);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeAbandonTransaction\n");
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+#ifdef DEBUG
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ LOGDDEMLRETURN(pFrame, ul);
+ FREEVDMPTR(pFrame);
+#endif
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdePostAdvise(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDDEPOSTADVISE16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEPOSTADVISE16), parg16);
+
+ ul = (ULONG)DdePostAdvise(parg16->f1, parg16->f2, parg16->f3);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdePostAdvise\n");
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+#ifdef DEBUG
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ LOGDDEMLRETURN(pFrame, ul);
+ FREEVDMPTR(pFrame);
+#endif
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeCreateDataHandle(PVDMFRAME pFrame)
+{
+ ULONG ul = 1;
+ LPBYTE lpByte = NULL;
+ register PDDECREATEDATAHANDLE16 parg16;
+ DWORD cbData;
+ DWORD cbOffset;
+ PVOID p;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDECREATEDATAHANDLE16), parg16);
+
+ cbData = parg16->f3;
+ cbOffset = parg16->f4;
+ GETMISCPTR(parg16->f2, p);
+ if (p != NULL) {
+ ul = DdeDataBuf16to32 (p, &lpByte, &cbData, &cbOffset, parg16->f6);
+ WOW32SAFEASSERTWARN(ul, "WD32DdeCreateDataHandle:data conversion failed.\n");
+ }
+ FREEMISCPTR(p);
+ if (ul) {
+ ul = (ULONG)DdeCreateDataHandle(parg16->f1,
+ lpByte ? lpByte : 0,
+ cbData,
+ cbOffset,
+ parg16->f5,
+ parg16->f6,
+ parg16->f7);
+ }
+
+ // There Could have been a Task Switch Before GetMessage Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been compacted or
+ // moved.
+
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+ if (lpByte) {
+ free_w (lpByte);
+ }
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeCreateDataHandle\n");
+
+#ifdef DEBUG
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ LOGDDEMLRETURN(pFrame, ul);
+ FREEVDMPTR(pFrame);
+#endif
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeAddData(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ LPBYTE lpByte = NULL;
+ UINT DataFormat;
+ register PDDEADDDATA16 parg16;
+ DWORD cbData;
+ DWORD cbOffset;
+ PVOID p;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEADDDATA16), parg16);
+
+ DataFormat = DdeGetDataHandleFormat ((DWORD)parg16->f1); // -1 is an error
+
+ if (DataFormat != -1) {
+ cbData = parg16->f3;
+ cbOffset = parg16->f4;
+ GETMISCPTR(parg16->f2, p);
+ if (DdeDataBuf16to32 (p, &lpByte, &cbData, &cbOffset, DataFormat)) {
+ ul = (ULONG)DdeAddData(parg16->f1, lpByte, cbData, cbOffset);
+ } else {
+ WOW32SAFEASSERTWARN(0, "WD32DdeAddData:data conversion failed.\n");
+ }
+ // memory may have moved - invalidate all flat pointers
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ FREEMISCPTR(p);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeAddData\n");
+
+ if (lpByte) {
+ free_w (lpByte);
+ }
+ }
+
+#ifdef DEBUG
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ LOGDDEMLRETURN(pFrame, ul);
+ FREEVDMPTR(pFrame);
+#endif
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeGetData(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPBYTE lpByte = NULL;
+ UINT DataFormat;
+ PVOID p;
+ register PDDEGETDATA16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEGETDATA16), parg16);
+
+ DataFormat = DdeGetDataHandleFormat (parg16->f1); // -1 is an error
+
+ if (DataFormat != -1) {
+ if (parg16->f2) {
+ if ((lpByte = malloc_w(parg16->f3)) == NULL) {
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, 0);
+ RETURN(0);
+ }
+ }
+
+ DdeDataSize16to32(&(parg16->f3), &(parg16->f4), DataFormat);
+ ul = (ULONG)DdeGetData(parg16->f1, lpByte, parg16->f3, parg16->f4);
+
+ // memory may have moved - invalidate all flat pointers
+ FREEVDMPTR(pFrame);
+ FREEARGPTR(parg16);
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(DDEGETDATA16), parg16);
+
+ GETMISCPTR (parg16->f2, p);
+ if (!DdeDataBuf32to16 (p, lpByte, parg16->f3, parg16->f4, DataFormat)) {
+ WOW32SAFEASSERTWARN(0, "WD32DdeGetData:data conversion failed.\n");
+ ul = 0;
+ }
+ FREEMISCPTR (p);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeGetData failed\n");
+ if (lpByte) {
+ free_w (lpByte);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeAccessData(PVDMFRAME pFrame)
+{
+ VPVOID vp = 0;
+ DWORD cbData;
+ DWORD cbData16;
+ PVOID p;
+ PDWORD16 pd16;
+ LPBYTE lpByte;
+ register PDDEACCESSDATA16 parg16;
+ DWORD DataFormat;
+ HAND16 h16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEACCESSDATA16), parg16);
+
+ DataFormat = DdeGetDataHandleFormat (parg16->f1); // -1 is an error
+
+ if (DataFormat != -1) {
+ lpByte = DdeAccessData(parg16->f1, &cbData);
+
+ if (lpByte) {
+ cbData16 = cbData;
+ DdeDataSize32to16(&cbData16, NULL, DataFormat);
+ if (vp = GlobalAllocLock16(GMEM_MOVEABLE, cbData16, &h16)) {
+ // 16-bit memory may have moved - invalidate all flat pointers
+ FREEARGPTR(parg16);
+ FREEFRAMEPTR(pFrame);
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(DDEACCESSDATA16), parg16);
+
+ GETMISCPTR (vp, p);
+ if (!DdeIsDataHandleInitialized(parg16->f1) ||
+ DdeDataBuf32to16 (p, lpByte, cbData, 0, DataFormat)) {
+
+ if (parg16->f2) {
+ GETMISCPTR (parg16->f2, pd16);
+ *pd16 = cbData16;
+ FREEMISCPTR(pd16);
+ }
+
+ WOWDdemlBind (h16, (DWORD)parg16->f1, aAccessData);
+ } else {
+ WOW32SAFEASSERTWARN(0, "WD32DdeAccessData:data conversion failed.\n");
+ GlobalUnlockFree16(h16);
+ vp = NULL;
+ }
+ FREEMISCPTR (p);
+ }
+ }
+ }
+
+ WOW32SAFEASSERTWARN(vp, "WD32DdeAccessData\n");
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, vp);
+
+ RETURN((ULONG)vp);
+}
+
+
+ULONG FASTCALL WD32DdeUnaccessData(PVDMFRAME pFrame)
+{
+ VPVOID vp;
+ ULONG ul = 1;
+ DWORD cbData;
+ DWORD cbOffset = 0;
+ LPBYTE lpByte;
+ PVOID p;
+ register PDDEUNACCESSDATA16 parg16;
+ UINT DataFormat;
+ HAND16 h16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEUNACCESSDATA16), parg16);
+
+ DataFormat = DdeGetDataHandleFormat (parg16->f1); // -1 is an error
+
+ if (DataFormat != -1) {
+ h16 = (VPVOID)WOWDdemlGetBind16 ((DWORD)parg16->f1, aAccessData);
+ GlobalUnlock16(h16);
+ vp = GlobalLock16(h16, NULL);
+
+ if (!DdeIsDataHandleReadOnly((HDDEDATA)parg16->f1)) {
+ lpByte = DdeAccessData(parg16->f1, &cbData);
+ DdeDataSize32to16(&cbData, &cbOffset, DataFormat);
+ GETMISCPTR (vp, p);
+ ul = DdeDataBuf16to32 (p, &lpByte, &cbData, &cbOffset, DataFormat);
+ WOW32SAFEASSERTWARN(ul, "WD32DdeAccessData:data conversion failed.\n");
+ FREEMISCPTR (p);
+ }
+
+ WOWDdemlUnBind ((DWORD)parg16->f1, aAccessData);
+ GlobalUnlockFree16(GlobalLock16(h16, NULL));
+ if (ul) {
+ ul = GETBOOL16(DdeUnaccessData(parg16->f1));
+ }
+ } else {
+ ul = 0;
+ }
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeAccessData\n");
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeFreeDataHandle(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PDDEFREEDATAHANDLE16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEFREEDATAHANDLE16), parg16);
+
+ ul = (ULONG)DdeFreeDataHandle(parg16->f1);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeFreeDataHandle\n");
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeGetLastError(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PDDEGETLASTERROR16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEGETLASTERROR16), parg16);
+
+ ul = (ULONG)DdeGetLastError(parg16->f1);
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeCreateStringHandle(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ LPSTR p;
+ register PDDECREATESTRINGHANDLE16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDECREATESTRINGHANDLE16), parg16);
+ GETPSZPTR (parg16->f2, p);
+
+ ul = (ULONG)DdeCreateStringHandle(parg16->f1, p, INT32(parg16->f3));
+
+ FREEPSZPTR(p);
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeFreeStringHandle(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PDDEFREESTRINGHANDLE16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEFREESTRINGHANDLE16), parg16);
+
+ ul = (ULONG)DdeFreeStringHandle(parg16->f1, parg16->f2);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeFreeStringHandle\n");
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeQueryString(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ LPSTR lpByte = NULL;
+ register PDDEQUERYSTRING16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEQUERYSTRING16), parg16);
+
+ GETMISCPTR(parg16->f3, lpByte);
+ ul = (ULONG)DdeQueryString(parg16->f1,
+ parg16->f2,
+ lpByte,
+ parg16->f4,
+ (int)UINT32(parg16->f5));
+ if (lpByte)
+ FREEMISCPTR(lpByte);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeQueryString\n");
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeKeepStringHandle(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PDDEKEEPSTRINGHANDLE16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEKEEPSTRINGHANDLE16), parg16);
+
+ ul = (ULONG)DdeKeepStringHandle(parg16->f1, parg16->f2);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeKeepStringHandle\n");
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeEnableCallback(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PDDEENABLECALLBACK16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDEENABLECALLBACK16), parg16);
+
+ ul = (ULONG)DdeEnableCallback(parg16->f1, parg16->f2, parg16->f3);
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeEnableCallBack\n");
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeNameService(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PDDENAMESERVICE16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDENAMESERVICE16), parg16);
+
+ ul = (ULONG)DdeNameService(parg16->f1, parg16->f2, parg16->f3, UINT32(parg16->f4));
+
+ WOW32SAFEASSERTWARN(ul, "WD32DdeNameService\n");
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeCmpStringHandles(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PDDECMPSTRINGHANDLES16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDECMPSTRINGHANDLES16), parg16);
+
+ ul = (ULONG)DdeCmpStringHandles(parg16->f1, parg16->f2);
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WD32DdeReconnect(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PDDERECONNECT16 parg16;
+
+ LOGDDEMLENTRY(pFrame);
+ GETARGPTR(pFrame, sizeof(DDERECONNECT16), parg16);
+
+ ul = (ULONG)DdeReconnect(parg16->f1);
+
+ FREEARGPTR(parg16);
+ LOGDDEMLRETURN(pFrame, ul);
+ RETURN(ul);
+}
+
+
+HDDEDATA W32DdemlCallBack(UINT type, UINT fmt, HCONV hconv, HSZ hsz1,
+ HSZ hsz2, HDDEDATA hData, DWORD dwData1,
+ DWORD dwData2)
+{
+ DWORD IdInst;
+ VPVOID vp, vpCC;
+ LONG lReturn;
+ PARM16 Parm16;
+ BOOL fSuccess;
+ HAND16 hCC16;
+
+ LOGDEBUG(ddeloglevel, ("Calling WIN16 DDEMLCALLBACK(%08lx, %08lx, %08lx, %08lx, %08lx, %08lx, %08lx, %08lx)\n",
+ type, fmt, hconv, hsz1, hsz2, hData, dwData1, dwData2));
+
+ IdInst = DdeGetCallbackInstance ();
+
+ vp = (VPVOID) WOWDdemlGetBind16 (IdInst, aCallBack);
+
+ Parm16.Ddeml.type = (WORD)type;
+ Parm16.Ddeml.fmt = (WORD)fmt;
+ Parm16.Ddeml.hconv = hconv;
+ Parm16.Ddeml.hsz1 = hsz1;
+ Parm16.Ddeml.hsz2 = hsz2;
+ Parm16.Ddeml.hData = hData;
+ if (type == XTYP_CONNECT || type == XTYP_WILDCONNECT) {
+ /*
+ * On XTYP_CONNECT and XTYP_WILDCONNECT transactions, dwData1 is a
+ * pointer to a CONVCONTEXT structure.
+ */
+ vpCC = GlobalAllocLock16(GHND, sizeof(CONVCONTEXT16), &hCC16);
+ // WARNING: 16-bit memory may move - invalidate any flat pointers now
+ Parm16.Ddeml.dwData1 = vpCC;
+ if (vpCC) {
+ W32PutConvContext(vpCC, (PCONVCONTEXT)dwData1);
+ }
+ } else {
+ Parm16.Ddeml.dwData1 = dwData1;
+ }
+ Parm16.Ddeml.dwData2 = dwData2;
+
+ fSuccess = CallBack16(RET_DDEMLCALLBACK, &Parm16, vp, (PVPVOID)&lReturn);
+ // WARNING: 16-bit memory may move - invalidate any flat pointers now
+
+ if (type == XTYP_CONNECT || type == XTYP_WILDCONNECT) {
+ GlobalUnlockFree16(vpCC);
+ }
+
+ if (!fSuccess) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::CallBack16 for DDEML failed.\n");
+ lReturn = 0;
+ }
+
+ LOGDEBUG(ddeloglevel, ("DDEMLCALLBACK:%08lx\n", lReturn));
+ return (lReturn);
+}
+
+
+VOID WOWDdemlBind (DWORD x16, DWORD x32, BIND1632 aBind[])
+{
+ int i;
+
+ for (i=0; i < MAX_CONVS; i++) {
+ if (aBind[i].x32 == 0) {
+ aBind[i].x32 = x32;
+ aBind[i].x16 = x16;
+ return;
+ }
+ }
+
+ LOGDEBUG(0,("WOW::WOWDdemlBind is all FULL!!!\n"));
+}
+
+VOID WOWDdemlUnBind (DWORD x32, BIND1632 aBind[])
+{
+ int i;
+
+ for (i=0; i < MAX_CONVS; i++) {
+ if (aBind[i].x32 == x32) {
+ aBind[i].x32 = 0;
+ aBind[i].x16 = 0;
+ return;
+ }
+ }
+
+ LOGDEBUG(0,("WOW::WOWDdemlUnBind can't find x32 !!!\n"));
+}
+
+DWORD WOWDdemlGetBind16 (DWORD x32, BIND1632 aBind[])
+{
+ int i;
+
+ for (i=0; i < MAX_CONVS; i++) {
+ if (aBind[i].x32 == x32) {
+ return(aBind[i].x16);
+ }
+ }
+
+ LOGDEBUG(0,("WOW::WOWDdemlGetBind16 can't find x16 !!!\n"));
+}
+
+
+DWORD WOWDdemlGetBind32 (DWORD x16, BIND1632 aBind[])
+{
+ int i;
+
+ for (i=0; i < MAX_CONVS; i++) {
+ if (aBind[i].x16 == x16) {
+ return(aBind[i].x32);
+ }
+ }
+
+ LOGDEBUG(0,("WOW::WOWDdemlGetBind32 can't find x16 !!!\n"));
+}
+
+
+BOOL DdeDataBuf16to32(
+ PVOID p16DdeData, // flat pointer to 16 bit DDE data buffer
+ LPBYTE *pp32DdeData, // we malloc_w this in this function if not pNULL - must be freed!
+ PDWORD pcbData, // IN:16 bit cbData OUT:32 bit cbData
+ PDWORD pcbOffset, // IN:16 bit cbOffset OUT:32 bit cbOffset
+ UINT format) // format of the data
+{
+ PHANDLE p;
+ HAND16 hMF16;
+ HANDLE hMF32;
+
+ switch (format) {
+ case CF_PALETTE:
+ /*
+ * GDI palette handle
+ */
+ if (*pcbOffset) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf16to32: PALETTE cbOffset is non NULL\n");
+ return(FALSE);
+ break;
+ }
+
+ if (*pcbData != sizeof(HAND16)) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf16to32: PALETTE cbData is wrong size\n");
+ return(FALSE);
+ }
+
+ if (*pp32DdeData == NULL) {
+ p = (PHANDLE)*pp32DdeData = malloc_w(sizeof(HANDLE));
+ } else {
+ p = (PHANDLE)*pp32DdeData;
+ }
+
+ *p = HPALETTE32(*(HAND16 *)p16DdeData);
+ *pcbData = sizeof(HANDLE);
+ break;
+
+ case CF_DSPBITMAP:
+ case CF_BITMAP:
+ /*
+ * GDI bitmap handle
+ */
+ if (*pcbOffset) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf16to32: BITMAP cbOffset is non NULL\n");
+ return(FALSE);
+ break;
+ }
+ if (*pcbData != sizeof(HAND16)) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf16to32: BITMAP cbData is wrong size\n");
+ return(FALSE);
+ }
+
+ /*
+ * Convert 16 bit handle to 32 bit bitmap handle and place into
+ * 32 bit buffer.
+ */
+ if (*pp32DdeData == NULL) {
+ p = (PHANDLE)*pp32DdeData = malloc_w(sizeof(HANDLE));
+ } else {
+ p = (PHANDLE)*pp32DdeData;
+ }
+ *p = HBITMAP32(*(HAND16 *)p16DdeData);
+ *pcbData = sizeof(HANDLE);
+ break;
+
+ case CF_DIB:
+ /*
+ * GlobalDataHandle to DIB Bits
+ */
+ if (*pcbOffset) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf16to32: DIB cbOffset is wrong\n");
+ return(FALSE);
+ }
+
+ if (*pcbData != sizeof(HAND16)) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf16to32: DIB cbData is wrong size\n");
+ return(FALSE);
+ }
+
+ if (*pp32DdeData == NULL) {
+ p = (PHANDLE)*pp32DdeData = malloc_w(sizeof(HANDLE));
+ } else {
+ p = (PHANDLE)*pp32DdeData;
+ }
+ if (p == NULL) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf16to32: DIB malloc failed.\n");
+ return(FALSE);
+ }
+ *p = ConvertDIB32(*(HAND16 *)p16DdeData);
+ if (*p == NULL) {
+ return(FALSE);
+ }
+ DDEAddhandle((HAND16)-1, (HAND16)-1, *(HAND16 *)p16DdeData, *p);
+ *pcbData = sizeof(HANDLE);
+ break;
+
+ case CF_DSPMETAFILEPICT:
+ case CF_METAFILEPICT:
+ /*
+ * GlobalDataHandle holding a METAFILEPICT struct which
+ * references a GDI metafile handle.
+ */
+
+ if (*pcbOffset) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf16to32: METAFILEPICT cbOffset is not 0\n");
+ return(FALSE);
+ }
+
+
+ if (*pcbData != sizeof(HAND16)) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf16to32: METAFILEPICT cbData is wrong size\n");
+ return(FALSE);
+ }
+
+ if (*pp32DdeData == NULL) {
+ p = (PHANDLE)*pp32DdeData = malloc_w(sizeof(HANDLE));
+ } else {
+ p = (PHANDLE)*pp32DdeData;
+ }
+ if (p == NULL) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf16to32: METAFILEPICT malloc failed.\n");
+ return(FALSE);
+ }
+ *p = ConvertMetaFile32(*(HAND16 *)p16DdeData, &hMF16, &hMF32);
+ if (*p == NULL) {
+ return(FALSE);
+ }
+ DDEAddhandle((HAND16)-1, (HAND16)-1, hMF16, hMF32);
+ DDEAddhandle((HAND16)-1, (HAND16)-1, *(HAND16 *)p16DdeData, *p);
+ *pcbData = sizeof(HANDLE);
+ break;
+
+ default:
+ if (*pp32DdeData == NULL) {
+ *pp32DdeData = malloc_w(*pcbData);
+ }
+ memcpy(*pp32DdeData, p16DdeData, *pcbData);
+ }
+ return(TRUE);
+}
+
+
+
+BOOL DdeDataBuf32to16(
+PVOID p16DdeData, // flat pointer to 16 bit app buffer for data
+PVOID p32DdeData, // source 32 bit buffer
+DWORD cbData, // IN:32 bit size
+DWORD cbOffset, // IN:32 bit offset
+UINT format) // format of data
+{
+ PHANDLE p;
+ HAND16 hMF16;
+ HANDLE hMF32;
+
+ switch (format) {
+ case CF_PALETTE:
+ /*
+ * GDI palette handle
+ */
+ if (cbOffset) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf32to16: PALETTE cbOffset is non NULL\n");
+ return(FALSE);
+ break;
+ }
+
+ if (cbData != sizeof(HANDLE)) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf32to16: PALETTE cbData is wrong size\n");
+ return(FALSE);
+ }
+
+ *(HAND16 *)p16DdeData = GETHPALETTE16(*(HANDLE *)p32DdeData);
+ break;
+
+ case CF_DSPBITMAP:
+ case CF_BITMAP:
+ /*
+ * GDI bitmap handle
+ */
+ if (cbOffset) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf32to16: BITMAP cbOffset is non NULL\n");
+ return(FALSE);
+ break;
+ }
+ if (cbData != sizeof(HANDLE)) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf32to16: BITMAP cbData is wrong size\n");
+ return(FALSE);
+ }
+
+ /*
+ * Convert 16 bit handle to 32 bit bitmap handle and place into
+ * 32 bit buffer.
+ */
+ *(HAND16 *)p16DdeData = GETHBITMAP16(*(HBITMAP *)p32DdeData);
+ break;
+
+ case CF_DIB:
+ /*
+ * GlobalDataHandle to DIB Bits
+ */
+ if (cbOffset) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf32to16: DIB cbOffset is wrong\n");
+ return(FALSE);
+ }
+
+ if (cbData != sizeof(HANDLE)) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf32to16: DIB cbData is wrong size\n");
+ return(FALSE);
+ }
+
+ *(HAND16 *)p16DdeData = ConvertDIB16(*(HANDLE *)p32DdeData);
+ if (*(HAND16 *)p16DdeData == NULL) {
+ return(FALSE);
+ }
+ DDEAddhandle((HAND16)-1, (HAND16)-1, *(HAND16 *)p16DdeData, *(HANDLE *)p32DdeData);
+ break;
+
+ case CF_DSPMETAFILEPICT:
+ case CF_METAFILEPICT:
+ /*
+ * GlobalDataHandle holding a METAFILEPICT struct which
+ * references a GDI metafile handle.
+ */
+
+ if (cbOffset) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf32to16: METAFILEPICT cbOffset is not 0\n");
+ return(FALSE);
+ }
+
+ if (cbData != sizeof(HANDLE)) {
+ WOW32SAFEASSERTWARN(NULL, "WOW::DdeDataBuf32to16: METAFILEPICT cbData is wrong size\n");
+ return(FALSE);
+ }
+
+ *(HAND16 *)p16DdeData = ConvertMetaFile16(*(HANDLE *)p32DdeData, &hMF16, &hMF32);
+ if (*(HAND16 *)p16DdeData == NULL) {
+ return(FALSE);
+ }
+ DDEAddhandle((HAND16)-1, (HAND16)-1, hMF16, hMF32);
+ DDEAddhandle((HAND16)-1, (HAND16)-1, *(HAND16 *)p16DdeData, *(HANDLE *)p32DdeData);
+ break;
+
+ default:
+ memcpy(p16DdeData, p32DdeData, cbData);
+ }
+ return(TRUE);
+}
+
+
+
+VOID DdeDataSize16to32(
+DWORD *pcbData,
+DWORD *pcbOff,
+UINT format)
+{
+ switch (format) {
+ case CF_DSPBITMAP:
+ case CF_BITMAP:
+ case CF_DIB:
+ case CF_PALETTE:
+ case CF_DSPMETAFILEPICT:
+ case CF_METAFILEPICT:
+ *pcbData = sizeof(HANDLE);
+ }
+}
+
+
+VOID DdeDataSize32to16(
+DWORD *pcbData,
+DWORD *pcbOff,
+UINT format)
+{
+ switch (format) {
+ case CF_DSPBITMAP:
+ case CF_BITMAP:
+ case CF_DIB:
+ case CF_PALETTE:
+ case CF_DSPMETAFILEPICT:
+ case CF_METAFILEPICT:
+ *pcbData = sizeof(HAND16);
+ }
+}
+
+
+VOID W32GetConvContext (VPVOID vp, PCONVCONTEXT pCC32)
+{
+ PCONVCONTEXT16 pCC16;
+
+ GETMISCPTR (vp, pCC16);
+
+ if (pCC16) {
+ WOW32SAFEASSERTWARN((pCC16->cb == sizeof(CONVCONTEXT16)),"WOW::W32GetConvContext: Bad value in cb\n");
+ pCC32->cb = sizeof(CONVCONTEXT);
+ pCC32->wFlags = pCC16->wFlags;
+ pCC32->wCountryID = pCC16->wCountryID;
+ pCC32->iCodePage = pCC16->iCodePage;
+ pCC32->dwLangID = pCC16->dwLangID;
+ pCC32->dwSecurity = pCC16->dwSecurity;
+ /*
+ * WOW apps don't know anything about NT security so just pass on the
+ * default QOS that the system grants to know-nothing apps.
+ */
+ pCC32->qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+ pCC32->qos.ImpersonationLevel = SecurityImpersonation;
+ pCC32->qos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
+ pCC32->qos.EffectiveOnly = TRUE;
+ }
+
+ FREEMISCPTR(pCC16);
+}
+
+VOID W32PutConvContext (VPVOID vp, PCONVCONTEXT pCC32)
+{
+ PCONVCONTEXT16 pCC16;
+
+ GETMISCPTR (vp, pCC16);
+
+ if (pCC16) {
+ WOW32SAFEASSERTWARN((pCC32->cb == sizeof(CONVCONTEXT)),"WOW::W32PutConvContext: Bad value in cb\n");
+ pCC16->cb = sizeof(CONVCONTEXT16);
+ pCC16->wFlags = pCC32->wFlags;
+ pCC16->wCountryID = pCC32->wCountryID;
+ pCC16->iCodePage = pCC32->iCodePage;
+ pCC16->dwLangID = pCC32->dwLangID;
+ pCC16->dwSecurity = pCC32->dwSecurity;
+ }
+
+ FREEMISCPTR(pCC16);
+}
diff --git a/private/mvdm/wow32/wddeml32.h b/private/mvdm/wow32/wddeml32.h
new file mode 100644
index 000000000..9c5f13b6f
--- /dev/null
+++ b/private/mvdm/wow32/wddeml32.h
@@ -0,0 +1,68 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WDDEML.H
+ * WOW32 16-bit DDEML API support
+ *
+ * History:
+ * Created Jan-23-1993 by Chandan Chauhan (ChandanC)
+--*/
+
+#define MAX_CONVS 3200
+
+typedef struct _BIND1632 {
+ DWORD x16;
+ DWORD x32;
+} BIND1632;
+
+ULONG FASTCALL WD32DdeInitialize(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeUninitialize(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeConnectList(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeQueryNextServer(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeDisconnectList(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeConnect(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeDisconnect(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeQueryConvInfo(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeSetUserHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeClientTransaction(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeAbandonTransaction(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdePostAdvise(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeCreateDataHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeAddData(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeGetData(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeAccessData(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeUnaccessData(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeFreeDataHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeGetLastError(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeCreateStringHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeFreeStringHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeQueryString(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeKeepStringHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeEnableCallback(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeNameService(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeCmpStringHandles(PVDMFRAME pFrame);
+ULONG FASTCALL WD32DdeReconnect(PVDMFRAME pFrame);
+HDDEDATA W32DdemlCallBack(UINT type, UINT fmt, HCONV hconv, HSZ hsz1,
+ HSZ hsz2, HDDEDATA hData, DWORD dwData1,
+ DWORD dwData2);
+VOID WOWDdemlBind (DWORD x16, DWORD x32, BIND1632 aBind[]);
+VOID WOWDdemlUnBind (DWORD x32, BIND1632 aBind[]);
+DWORD WOWDdemlGetBind16 (DWORD x32, BIND1632 aBind[]);
+DWORD WOWDdemlGetBind32 (DWORD x16, BIND1632 aBind[]);
+BOOL DdeDataBuf16to32(PVOID p16DdeData, LPBYTE *pp32DdeData, PDWORD pcbData,
+ PDWORD pcbOffset, UINT format);
+BOOL DdeDataBuf32to16(PVOID p16DdeData, PVOID p32DdeData, DWORD cbData,
+ DWORD cbOffset, UINT format);
+VOID DdeDataSize16to32(DWORD *pcbData, DWORD *pcbOff, UINT format);
+VOID DdeDataSize32to16(DWORD *pcbData, DWORD *pcbOff, UINT format);
+VOID W32GetConvContext (VPVOID vp, PCONVCONTEXT pCC32);
+VOID W32PutConvContext (VPVOID vp, PCONVCONTEXT pCC32);
+
+/*
+ * Imports from user32.dll - need to eventually be moved to winuserp.h
+ * or ddemlp.h
+ */
+BOOL DdeIsDataHandleInitialized(HDDEDATA hData);
diff --git a/private/mvdm/wow32/wddetbl2.h b/private/mvdm/wow32/wddetbl2.h
new file mode 100644
index 000000000..5d49ccb85
--- /dev/null
+++ b/private/mvdm/wow32/wddetbl2.h
@@ -0,0 +1,62 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WDDETBL2.h
+ * WOW32 16-bit DDEML API tables
+ *
+ * History:
+ * Created 26-Jan-1993 by Chandan Chauhan (ChandanC)
+--*/
+
+
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_DDEML, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(WD32DdeInitialize, "DDEINITIALIZE", MOD_DDEML, sizeof(DDEINITIALIZE16))},
+ {W32FUN(WD32DdeUninitialize, "DDEUNINITIALIZE", MOD_DDEML, sizeof(DDEUNINITIALIZE16))},
+ {W32FUN(WD32DdeConnectList, "DDECONNECTLIST", MOD_DDEML, sizeof(DDECONNECTLIST16))},
+ {W32FUN(WD32DdeQueryNextServer, "DDEQUERYNEXTSERVER", MOD_DDEML, sizeof(DDEQUERYNEXTSERVER16))},
+ {W32FUN(WD32DdeDisconnectList, "DDEDISCONNECTLIST", MOD_DDEML, sizeof(DDEDISCONNECTLIST16))},
+ {W32FUN(WD32DdeConnect, "DDECONNECT", MOD_DDEML, sizeof(DDECONNECT16))},
+ {W32FUN(WD32DdeDisconnect, "DDECONNECT", MOD_DDEML, sizeof(DDEDISCONNECT16))},
+ {W32FUN(WD32DdeQueryConvInfo, "DDEQUERYCONVINFO", MOD_DDEML, sizeof(DDEQUERYCONVINFO16))},
+ {W32FUN(WD32DdeSetUserHandle, "DDESETUSERHANDLE", MOD_DDEML, sizeof(DDESETUSERHANDLE16))},
+
+ /*** 0011 ***/
+ {W32FUN(WD32DdeClientTransaction, "DDECLIENTTRANSACTION", MOD_DDEML, sizeof(DDECLIENTTRANSACTION16))},
+ {W32FUN(WD32DdeAbandonTransaction, "DDEABANDONTRANSACTION", MOD_DDEML, sizeof(DDEABANDONTRANSACTION16))},
+ {W32FUN(WD32DdePostAdvise, "DDEPOSTADVISE", MOD_DDEML, sizeof(DDEPOSTADVISE16))},
+ {W32FUN(WD32DdeCreateDataHandle, "DDECREATEDATAHANDLE", MOD_DDEML, sizeof(DDECREATEDATAHANDLE16))},
+ {W32FUN(WD32DdeAddData, "DDEADDDATA", MOD_DDEML, sizeof(DDEADDDATA16))},
+ {W32FUN(WD32DdeGetData, "DDEGETDATA", MOD_DDEML, sizeof(DDEGETDATA16))},
+ {W32FUN(WD32DdeAccessData, "DDEACCESSDATA", MOD_DDEML, sizeof(DDEACCESSDATA16))},
+ {W32FUN(WD32DdeUnaccessData, "DDEUNACCESSDATA", MOD_DDEML, sizeof(DDEUNACCESSDATA16))},
+ {W32FUN(WD32DdeFreeDataHandle, "DDEFREEDATAHANDLE", MOD_DDEML, sizeof(DDEFREEDATAHANDLE16))},
+ {W32FUN(WD32DdeGetLastError, "DDEGETLASTERROR", MOD_DDEML, sizeof(DDEGETLASTERROR16))},
+
+ /*** 0021 ***/
+ {W32FUN(WD32DdeCreateStringHandle, "DDECREATESTRINGHANDLE", MOD_DDEML, sizeof(DDECREATESTRINGHANDLE16))},
+ {W32FUN(WD32DdeFreeStringHandle, "DDEFREESTRINGHANDLE", MOD_DDEML, sizeof(DDEFREESTRINGHANDLE16))},
+ {W32FUN(WD32DdeQueryString, "DDEQUERYSTRING", MOD_DDEML, sizeof(DDEQUERYSTRING16))},
+ {W32FUN(WD32DdeKeepStringHandle, "DDEKEEPSTRINGHANDLE", MOD_DDEML, sizeof(DDEKEEPSTRINGHANDLE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(WD32DdeEnableCallback, "DDEENABLECALLBACK", MOD_DDEML, sizeof(DDEENABLECALLBACK16))},
+ {W32FUN(WD32DdeNameService, "DDENAMESERVICE", MOD_DDEML, sizeof(DDENAMESERVICE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+
+ /*** 0031 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(WD32DdeCmpStringHandles, "DDECMPSTRINGHANDLES", MOD_DDEML, sizeof(DDECMPSTRINGHANDLES16))},
+ {W32FUN(WD32DdeReconnect, "DDERECONNECT", MOD_DDEML, sizeof(DDERECONNECT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_DDEML, 0)},
+
diff --git a/private/mvdm/wow32/wdib.c b/private/mvdm/wow32/wdib.c
new file mode 100644
index 000000000..6cdececf3
--- /dev/null
+++ b/private/mvdm/wow32/wdib.c
@@ -0,0 +1,859 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WDIB.C
+ * DIB.DRV support
+ *
+ * History:
+ * 28-Apr-1994 Sudeep Bharati
+ * Created.
+ *
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wowgdip.h"
+#include "wdib.h"
+#include "memapi.h"
+
+MODNAME(wdib.c);
+
+#define CJSCAN(width,planes,bits) ((((width)*(planes)*(bits)+31) & ~31) / 8)
+#define ABS(X) (((X) < 0 ) ? -(X) : (X))
+
+BOOL W32CheckDibColorIndices(LPBITMAPINFOHEADER lpbmi);
+
+// VGA colors
+RGBQUAD rgbVGA[] = {
+// Blue Green Red
+ 0x00, 0x00, 0x00, 0, // 0 ; black
+ 0x00, 0x00, 0x80, 0, // 1 ; dark red
+ 0x00, 0x80, 0x00, 0, // 2 ; dark green
+ 0x00, 0x80, 0x80, 0, // 3 ; mustard
+ 0x80, 0x00, 0x00, 0, // 4 ; dark blue
+ 0x80, 0x00, 0x80, 0, // 5 ; purple
+ 0x80, 0x80, 0x00, 0, // 6 ; dark turquoise
+ 0xc0, 0xc0, 0xc0, 0, // 7 ; gray
+ 0x80, 0x80, 0x80, 0, // 8 ; dark gray
+ 0x00, 0x00, 0xff, 0, // 9 ; red
+ 0x00, 0xff, 0x00, 0, // a ; green
+ 0x00, 0xff, 0xff, 0, // b ; yellow
+ 0xff, 0x00, 0x00, 0, // c ; blue
+ 0xff, 0x00, 0xff, 0, // d ; magenta
+ 0xff, 0xff, 0x00, 0, // e ; cyan
+ 0xff, 0xff, 0xff, 0 // f ; white
+};
+
+RGBQUAD rgb4[] = {
+ 0xc0, 0xdc, 0xc0, 0, // 8
+ 0xf0, 0xca, 0xa6, 0, // 9
+ 0xf0, 0xfb, 0xff, 0, // 246
+ 0xa4, 0xa0, 0xa0, 0 // 247
+};
+
+
+
+PDIBINFO pDibInfoHead = NULL;
+PDIBSECTIONINFO pDibSectionInfoHead = NULL;
+
+HDC W32HandleDibDrv (PVPVOID vpbmi16)
+{
+ HDC hdcMem = NULL;
+ HBITMAP hbm = NULL;
+ PVOID pvBits, pvIntelBits;
+ STACKBMI32 bmi32;
+ LPBITMAPINFO lpbmi32;
+ DWORD dwClrUsed,nSize,nAlignmentSpace;
+ PBITMAPINFOHEADER16 pbmi16;
+ INT nbmiSize,nBytesWritten;
+ HANDLE hfile=NULL,hsec=NULL;
+ ULONG RetVal,OriginalSelLimit,SelectorLimit,OriginalFlags;
+ PARM16 Parm16;
+ CHAR pchTempFile[MAX_PATH];
+ BOOL bRet = FALSE;
+ PVPVOID vpBase16 = (PVPVOID) ((ULONG) vpbmi16 & 0xffff0000);
+
+ if ((hdcMem = W32FindAndLockDibInfo((USHORT)HIWORD(vpbmi16))) != (HDC)NULL) {
+ return hdcMem;
+ }
+
+ // First create a memory device context compatible to
+ // the app's current screen
+ if ((hdcMem = CreateCompatibleDC (NULL)) == NULL) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateCompatibleDC failed\n"));
+ return NULL;
+ }
+
+ // Copy bmi16 to bmi32. DIB.DRV only supports DIB_RGB_COLORS
+ lpbmi32 = CopyBMI16ToBMI32(
+ vpbmi16,
+ (LPBITMAPINFO)&bmi32,
+ (WORD) DIB_RGB_COLORS);
+
+ // this hack for Director 4.0 does essentially what WFW does
+ // if this bitmap is 0 sized, just return an hDC for something simple
+ if(bmi32.bmiHeader.biSizeImage == 0 &&
+ (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_DIBDRVIMAGESIZEZERO)) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv:Zero biSizeImage, returning memory DC!\n"));
+ return hdcMem;
+ }
+
+ try {
+
+ // Copy the wholething into a temp file. First get a temp file name
+ if ((nSize = GetTempPath (MAX_PATH, pchTempFile)) == 0 ||
+ nSize >= MAX_PATH)
+ goto hdd_err;
+
+ if (GetTempFileName (pchTempFile,
+ "DIB",
+ 0,
+ pchTempFile) == 0)
+ goto hdd_err;
+
+ if ((hfile = CreateFile (pchTempFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ (FILE_ATTRIBUTE_NORMAL |
+ FILE_ATTRIBUTE_TEMPORARY |
+ FILE_FLAG_DELETE_ON_CLOSE),
+ NULL)) == INVALID_HANDLE_VALUE) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateFile failed\n"));
+ goto hdd_err;
+ }
+
+ // call back to get the size of the global object
+ // associated with vpbmi16
+ Parm16.WndProc.wParam = HIWORD(vpbmi16);
+
+ CallBack16(RET_GETDIBSIZE,
+ &Parm16,
+ 0,
+ (PVPVOID)&SelectorLimit);
+
+ Parm16.WndProc.wParam = HIWORD(vpbmi16);
+
+ if (SelectorLimit == 0xffffffff || SelectorLimit == 0) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv Invalid Selector %x\n",HIWORD(vpbmi16)));
+ goto hdd_err;
+ }
+
+ SelectorLimit++;
+
+ OriginalSelLimit = SelectorLimit;
+
+ CallBack16(RET_GETDIBFLAGS,
+ &Parm16,
+ 0,
+ (PVPVOID)&OriginalFlags);
+
+ if (OriginalFlags == 0x4) { //GA_DGROUP
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv GA_DGROUP Not Handled\n"));
+ goto hdd_err;
+ }
+
+ GETVDMPTR(vpBase16, SelectorLimit, pbmi16);
+
+ nbmiSize = GetBMI16Size(vpbmi16, (WORD) DIB_RGB_COLORS, &dwClrUsed);
+
+ // Under NT CreateDIBSection will fail if the offset to the bits
+ // is not dword aligned. So we may have to add some space at the top
+ // of the section to get the offset correctly aligned.
+
+ nAlignmentSpace = (nbmiSize+LOWORD(vpbmi16)) % 4;
+
+ if (nAlignmentSpace) {
+ if (WriteFile (hfile,
+ pbmi16,
+ nAlignmentSpace,
+ &nBytesWritten,
+ NULL) == FALSE ||
+ nBytesWritten != (INT) nAlignmentSpace)
+ goto hdd_err;
+ }
+
+ //
+ // detect a clinical case of bitedit screwing around dib.drv
+ //
+ // code below is using dib macros declared in wdib.h
+ // namely:
+ // DibNumColors - yields max number of colors in dib
+ // DibColors - yields pointer to a dib color table
+ //
+ // Function W32CheckDibColorIndices checks to see if DIB color
+ // table looks like a number (defined usually by biClrImportant)
+ // of WORD indices in a sequential order (0, 1, 2, ...)
+ // if this is the case, app is trying to use undocumented feature
+ // of DIB.DRV that turns color matching off in this case.
+ // Since we cannot enforce that rule, we approximate it by filling
+ // color table by a number of known (and always same) entries
+ // When blitting occurs, no color matching will be performed (when
+ // both target and destination are of this very nature).
+ // For no reason at all we fill color table with vga colors.
+ // Sequential indices could have worked just as well.
+ //
+ // Modifications are made to memory pointed to by lpbmi32
+
+ if (W32CheckDibColorIndices((LPBITMAPINFOHEADER)lpbmi32)) {
+ INT i, nColors;
+ LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER)lpbmi32;
+ LPRGBQUAD lprgbq = (LPRGBQUAD)DibColors(lpbmi);
+
+ nColors = DibNumColors(lpbmi);
+ lpbmi->biClrImportant = nColors;
+
+ switch (lpbmi->biBitCount) {
+ case 1:
+ lprgbq[0] = rgbVGA[0];
+ lprgbq[1] = rgbVGA[0x0f];
+ break;
+
+ case 4:
+ RtlCopyMemory(lprgbq, rgbVGA, sizeof(rgbVGA));
+ break;
+
+ case 8:
+ RtlCopyMemory(lprgbq, rgbVGA, 8*sizeof(RGBQUAD));
+ RtlCopyMemory(lprgbq+248, rgbVGA+8, 8*sizeof(RGBQUAD));
+ RtlCopyMemory(lprgbq+8, rgb4, 2*sizeof(RGBQUAD));
+ RtlCopyMemory(lprgbq+246, rgb4+2, 2*sizeof(RGBQUAD));
+ for (i = 10; i < 246; ++i) {
+ lprgbq[i].rgbBlue = i;
+ lprgbq[i].rgbGreen= 0;
+ lprgbq[i].rgbRed = 0;
+ lprgbq[i].rgbReserved = 0;
+ }
+ break;
+
+ default: // this should never happen
+ break;
+ }
+ }
+
+ if (WriteFile (hfile,
+ pbmi16,
+ SelectorLimit,
+ &nBytesWritten,
+ NULL) == FALSE || nBytesWritten != (INT) SelectorLimit)
+ goto hdd_err;
+
+ if (SelectorLimit < 64*1024) {
+ if (SetFilePointer (hfile,
+ 64*1024+nAlignmentSpace,
+ NULL,
+ FILE_BEGIN) == -1)
+ goto hdd_err;
+
+ if (SetEndOfFile (hfile) == FALSE)
+ goto hdd_err;
+
+ SelectorLimit = 64*1024;
+ }
+
+ if ((hsec = CreateFileMapping (hfile,
+ NULL,
+ PAGE_READWRITE | SEC_COMMIT,
+ 0,
+ SelectorLimit+nAlignmentSpace,
+ NULL)) == NULL) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateFileMapping Failed\n"));
+ goto hdd_err;
+ }
+
+ // Now create the DIB section
+ if ((hbm = CreateDIBSection (hdcMem,
+ lpbmi32,
+ DIB_RGB_COLORS,
+ &pvBits,
+ hsec,
+ nAlignmentSpace + LOWORD(vpbmi16) + nbmiSize
+ )) == NULL) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateDibSection Failed\n"));
+ goto hdd_err;
+ }
+
+ FREEVDMPTR(pbmi16);
+
+ if((pvBits = MapViewOfFile(hsec,
+ FILE_MAP_WRITE,
+ 0,
+ 0,
+ SelectorLimit+nAlignmentSpace)) == NULL) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv MapViewOfFile Failed\n"));
+ goto hdd_err;
+ }
+
+ pvBits = (PVOID) ((ULONG)pvBits + nAlignmentSpace);
+
+ SelectObject (hdcMem, hbm);
+
+ GdiSetBatchLimit(1);
+
+#ifndef i386
+ if (!NT_SUCCESS(VdmAddVirtualMemory((ULONG)pvBits,
+ (ULONG)SelectorLimit,
+ (PULONG)&pvIntelBits))) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv VdmAddVirtualMemory failed\n"));
+ goto hdd_err;
+ }
+
+ // On risc platforms, the intel base + the intel linear address
+ // of the DIB section is not equal to the DIB section's process
+ // address. This is because of the VdmAddVirtualMemory call
+ // above. So here we zap the correct address into the flataddress
+ // array.
+ if (!VdmAddDescriptorMapping(HIWORD(vpbmi16),
+ (USHORT) ((SelectorLimit+65535)/65536),
+ (ULONG) pvIntelBits,
+ (ULONG) pvBits)) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv VdmAddDescriptorMapping failed\n"));
+ goto hdd_err;
+ }
+
+#else
+ pvIntelBits = pvBits;
+#endif
+
+ // Finally set the selectors to the new DIB
+ Parm16.WndProc.wParam = HIWORD(vpbmi16);
+ Parm16.WndProc.lParam = (LONG)pvIntelBits;
+ Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT
+ Parm16.WndProc.hwnd = 1; // set so it's not randomly 0
+
+ CallBack16(RET_SETDIBSEL,
+ &Parm16,
+ 0,
+ (PVPVOID)&RetVal);
+
+ if (!RetVal) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv Callback set_sel_for_dib failed\n"));
+ goto hdd_err;
+ }
+
+
+ // Store all the relevant information so that DeleteDC could
+ // free all the resources later.
+ if (W32AddDibInfo(hdcMem,
+ hfile,
+ hsec,
+ nAlignmentSpace,
+ pvBits,
+ pvIntelBits,
+ hbm,
+ OriginalSelLimit,
+ (USHORT)OriginalFlags,
+ (USHORT)((HIWORD(vpbmi16)))) == FALSE)
+ goto hdd_err;
+
+
+ // Finally spit out the dump for debugging
+ LOGDEBUG(6,("\t\tWOW::W32HandleDibDrv hdc=%04x nAlignment=%04x\n\t\tNewDib=%x OldDib=%04x:%04x DibSize=%x DibFlags=%x\n",hdcMem,nAlignmentSpace,pvBits,HIWORD(vpbmi16),LOWORD(vpbmi16),OriginalSelLimit,(USHORT)OriginalFlags));
+
+ bRet = TRUE;
+hdd_err:;
+ }
+ finally {
+ if (!bRet) {
+
+ if (hdcMem) {
+ DeleteDC (hdcMem);
+ hdcMem = NULL;
+ }
+ if (hfile)
+ CloseHandle (hfile);
+
+ if (hsec)
+ CloseHandle (hsec);
+
+ if (hbm)
+ CloseHandle (hbm);
+ }
+ }
+ return hdcMem;
+}
+
+
+BOOL W32AddDibInfo (
+ HDC hdcMem,
+ HANDLE hfile,
+ HANDLE hsec,
+ ULONG nalignment,
+ PVOID newdib,
+ PVOID newIntelDib,
+ HBITMAP hbm,
+ ULONG dibsize,
+ USHORT originaldibflags,
+ USHORT originaldibsel
+ )
+{
+ PDIBINFO pdi;
+
+ if ((pdi = malloc_w (sizeof (DIBINFO))) == NULL)
+ return FALSE;
+
+ pdi->di_hdc = hdcMem;
+ pdi->di_hfile = hfile;
+ pdi->di_hsec = hsec;
+ pdi->di_nalignment = nalignment;
+ pdi->di_newdib = newdib;
+ pdi->di_newIntelDib = newIntelDib;
+ pdi->di_hbm = hbm;
+ pdi->di_dibsize = dibsize;
+ pdi->di_originaldibsel = originaldibsel;
+ pdi->di_originaldibflags = originaldibflags;
+ pdi->di_next = pDibInfoHead;
+ pdi->di_lockcount = 1;
+ pDibInfoHead = pdi;
+
+ return TRUE;
+}
+
+BOOL W32FreeDibInfoHandle(PDIBINFO pdi, PDIBINFO pdiLast)
+{
+ if (W32RestoreOldDib (pdi) == 0) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::W32RestoreDib failed\n"));
+ return FALSE;
+ }
+#ifndef i386
+ VdmRemoveVirtualMemory((ULONG)pdi->di_newIntelDib);
+#endif
+ UnmapViewOfFile ((LPVOID)((ULONG)pdi->di_newdib - pdi->di_nalignment));
+
+ DeleteObject (pdi->di_hbm);
+ CloseHandle (pdi->di_hsec);
+ CloseHandle (pdi->di_hfile);
+
+ DeleteDC(pdi->di_hdc);
+ W32FreeDibInfo (pdi, pdiLast);
+
+ return TRUE;
+}
+
+
+BOOL W32CheckAndFreeDibInfo (HDC hdc)
+{
+ PDIBINFO pdi = pDibInfoHead,pdiLast=NULL;
+
+ while (pdi) {
+ if (pdi->di_hdc == hdc){
+
+ if (--pdi->di_lockcount) {
+ //
+ // This must be a releasedc within a nested call to createdc.
+ // Just return, as this should be released again later.
+ //
+ LOGDEBUG(LOG_ALWAYS, ("\nW32CheckAndFreeDibInfo: lockcount!=0\n"));
+ return TRUE;
+ }
+
+ return W32FreeDibInfoHandle(pdi, pdiLast);
+ }
+ pdiLast = pdi;
+ pdi = pdi->di_next;
+ }
+
+ return FALSE;
+}
+
+VOID W32FreeDibInfo (PDIBINFO pdiCur, PDIBINFO pdiLast)
+{
+ if (pdiLast == NULL)
+ pDibInfoHead = pdiCur->di_next;
+ else
+ pdiLast->di_next = pdiCur->di_next;
+
+ free_w (pdiCur);
+}
+
+ULONG W32RestoreOldDib (PDIBINFO pdi)
+{
+ PARM16 Parm16;
+ ULONG retval;
+
+ // callback to allocate memory and copy the dib from dib section
+
+ Parm16.WndProc.wParam = pdi->di_originaldibsel;
+ Parm16.WndProc.lParam = (LONG) (pdi->di_newdib);
+ Parm16.WndProc.wMsg = pdi->di_originaldibflags;
+
+ CallBack16(RET_FREEDIBSEL,
+ &Parm16,
+ 0,
+ (PVPVOID)&retval);
+
+ return retval;
+}
+
+
+HDC W32FindAndLockDibInfo (USHORT sel)
+{
+ PDIBINFO pdi = pDibInfoHead;
+
+ while (pdi) {
+
+ if (pdi->di_originaldibsel == sel){
+ pdi->di_lockcount++;
+ return (pdi->di_hdc);
+
+ }
+ pdi = pdi->di_next;
+
+ }
+ return (HDC) NULL;
+}
+
+//
+// This function is called from krnl386 if GlobalReAlloc or GlobalFree is
+// trying to operate on memory which we suspect is dib-mapped. It finds
+// dib by original selector and restores it, thus allowing respective function
+// to succeede. Bitedit is the app that does globalrealloc before DeleteDC
+//
+//
+
+ULONG FASTCALL WK32FindAndReleaseDib(PVDMFRAME pvf)
+{
+ USHORT sel;
+ PFINDANDRELEASEDIB16 parg;
+ PDIBINFO pdi;
+ PDIBINFO pdiLast = NULL;
+
+ // get the argument pointer, see wowkrnl.h
+ GETARGPTR(pvf, sizeof(*parg), parg);
+
+ // get selector from the handle
+ sel = parg->hdib | (USHORT)0x01; // "convert to sel"
+
+ // find this said sel in the dibinfo
+ pdi = pDibInfoHead;
+ while (pdi) {
+ if (pdi->di_originaldibsel == sel) {
+
+ // found ! this is what we are releasing or reallocating
+ LOGDEBUG(LOG_ALWAYS, ("\nWOW: In FindAndReleaseDIB function %d\n", (DWORD)parg->wFunId));
+
+ // see if we need to nuke...
+ if (--pdi->di_lockcount) {
+ // the problem with lock count...
+ LOGDEBUG(LOG_ALWAYS, ("\nWOW: FindAndReleaseDib failed (lock count!)\n"));
+ return FALSE;
+ }
+
+ return W32FreeDibInfoHandle(pdi, pdiLast);
+ }
+
+ pdiLast = pdi;
+ pdi = pdi->di_next;
+ }
+
+ return FALSE;
+}
+
+
+BOOL W32CheckDibColorIndices(LPBITMAPINFOHEADER lpbmi)
+{
+ WORD i, nColors;
+ LPWORD lpw = (LPWORD)DibColors(lpbmi);
+
+ nColors = DibNumColors(lpbmi);
+ if (lpbmi->biClrImportant) {
+ nColors = min(nColors, (WORD)lpbmi->biClrImportant);
+ }
+
+ for (i = 0; i < nColors; ++i) {
+ if (*lpw++ != i) {
+ return FALSE;
+ }
+ }
+
+ LOGDEBUG(LOG_ALWAYS, ("\nUndocumented Dib.Drv behaviour used\n"));
+
+ return TRUE;
+}
+
+/******************************Public*Routine******************************\
+* DIBSection specific calls
+*
+* History:
+* 04-May-1994 -by- Eric Kutter [erick]
+* Wrote it.
+\**************************************************************************/
+
+ULONG cjBitmapBitsSize(CONST BITMAPINFO *pbmi)
+{
+// Check for PM-style DIB
+
+ if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
+ {
+ LPBITMAPCOREINFO pbmci;
+ pbmci = (LPBITMAPCOREINFO)pbmi;
+ return(CJSCAN(pbmci->bmciHeader.bcWidth,pbmci->bmciHeader.bcPlanes,
+ pbmci->bmciHeader.bcBitCount) *
+ pbmci->bmciHeader.bcHeight);
+ }
+
+// not a core header
+
+ if ((pbmi->bmiHeader.biCompression == BI_RGB) ||
+ (pbmi->bmiHeader.biCompression == BI_BITFIELDS))
+ {
+ return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes,
+ pbmi->bmiHeader.biBitCount) *
+ ABS(pbmi->bmiHeader.biHeight));
+ }
+ else
+ {
+ return(pbmi->bmiHeader.biSizeImage);
+ }
+}
+
+ULONG FASTCALL WG32CreateDIBSection(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ STACKBMI32 bmi32;
+ LPBITMAPINFO lpbmi32;
+ HBITMAP hbm32;
+ PVOID pv16, pvBits, pvIntelBits;
+ PVPVOID vpbmi16;
+ PVOID pvBits32;
+ DWORD dwArg16;
+
+ register PCREATEDIBSECTION16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEDIBSECTION16), parg16);
+
+ // this is performance hack so we don't generate extra code
+ dwArg16 = FETCHDWORD(parg16->f4); // do it once here
+ pv16 = (PVOID)GetPModeVDMPointer(dwArg16, sizeof(DWORD)); // aligned here!
+
+ WOW32ASSERTMSG(((parg16->f5 == 0) && (parg16->f6 == 0)),
+ ("WOW:WG32CreateDIBSection, hSection/dwOffset non-null\n"));
+
+ vpbmi16 = (PVPVOID)FETCHDWORD(parg16->f2);
+ lpbmi32 = CopyBMI16ToBMI32(vpbmi16,
+ (LPBITMAPINFO)&bmi32,
+ FETCHWORD(parg16->f3));
+
+ hbm32 = CreateDIBSection(HDC32(parg16->f1),
+ lpbmi32,
+ WORD32(parg16->f3),
+ &pvBits,
+ NULL,
+ 0);
+
+ if (hbm32 != 0)
+ {
+ PARM16 Parm16;
+ PDIBSECTIONINFO pdi;
+ ULONG SelectorLimit;
+
+ SelectorLimit = (ULONG)cjBitmapBitsSize(lpbmi32);
+#ifndef i386
+ if (!NT_SUCCESS(VdmAddVirtualMemory((ULONG)pvBits,
+ SelectorLimit,
+ (PULONG)&pvIntelBits))) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection VdmAddVirtualMemory failed\n"));
+ goto cds_err;
+ }
+
+#else
+ pvIntelBits = pvBits;
+#endif
+
+ // Create a selector array for the bits backed by pvIntelBits
+
+ Parm16.WndProc.wParam = (WORD)-1; // -1 => allocate selectors
+ Parm16.WndProc.lParam = (LONG) pvIntelBits; // backing pointer
+ Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT
+ Parm16.WndProc.hwnd = (WORD)((SelectorLimit+65535)/65536);// selector count
+
+ CallBack16(RET_SETDIBSEL,
+ &Parm16,
+ 0,
+ (PVPVOID)&pvBits32);
+
+ // 16:16 pointer is still valid as call above makes no difference
+ if (pv16 != NULL) {
+ *(UNALIGNED PVOID*)pv16 = pvBits32;
+ }
+
+ if (pvBits32 == NULL) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection, Callback set_sel_for_dib failed\n"));
+ goto cds_err;
+ }
+
+#ifndef i386
+ // okay, that was successful - map the descriptors properly
+
+ if (!VdmAddDescriptorMapping(HIWORD(pvBits32),
+ (USHORT) ((SelectorLimit+65535)/65536),
+ (ULONG) pvIntelBits,
+ (ULONG) pvBits)) {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection VdmAddDescriptorMapping failed\n"));
+ goto cds_err;
+ }
+#endif
+
+ LOGDEBUG(LOG_ALWAYS, ("\nWOW:CreateDIBSection: [16:16 %x] [Intel %x] [Flat %x]\n",
+ pvBits32, pvIntelBits, pvBits));
+
+ ul = GETHBITMAP16(hbm32);
+
+ // Add it to the list used for cleanup at DeleteObject time.
+
+ if ((pdi = malloc_w (sizeof (DIBSECTIONINFO))) != NULL) {
+ pdi->di_hbm = (HBITMAP)(HAND16)hbm32;
+ pdi->di_pv16 = pvBits32;
+#ifndef i386
+ pdi->di_newIntelDib = pvIntelBits;
+#endif
+ pdi->di_next = pDibSectionInfoHead;
+ pDibSectionInfoHead = pdi;
+
+ // need to turn batching off since a DIBSECTION means the app can
+ // also draw on the bitmap and we need synchronization.
+
+ GdiSetBatchLimit(1);
+
+ goto cds_ok;
+ }
+ else {
+ // Failure, free the selector array
+
+ Parm16.WndProc.wParam = (WORD)-1; // -1 => allocate/free
+ Parm16.WndProc.lParam = (LONG) pvBits32; // pointer
+ Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT
+ Parm16.WndProc.hwnd = 0; // 0 => free
+
+ CallBack16(RET_SETDIBSEL,
+ &Parm16,
+ 0,
+ (PVPVOID)&ul);
+#ifndef i386
+ VdmRemoveVirtualMemory((ULONG)pvIntelBits);
+#endif
+
+ }
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection, CreateDibSection Failed\n"));
+ }
+
+cds_err:
+
+ if (hbm32 != 0) {
+ DeleteObject(hbm32);
+ }
+ LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection returning failure\n"));
+ ul = 0;
+
+cds_ok:
+ WOW32APIWARN(ul, "CreateDIBSection");
+
+ FREEMISCPTR(pv16);
+ FREEARGPTR(parg16);
+
+ return(ul);
+}
+
+ULONG FASTCALL WG32GetDIBColorTable(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ RGBQUAD * prgb;
+
+ register PGETDIBCOLORTABLE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETDIBCOLORTABLE16), parg16);
+ GETMISCPTR(parg16->f4,prgb);
+
+ ul = (ULONG)GetDIBColorTable(HDC32(parg16->f1),
+ parg16->f2,
+ parg16->f3,
+ prgb);
+
+ WOW32APIWARN(ul, "GetDIBColorTable");
+
+ if (ul)
+ FLUSHVDMPTR(parg16->f4,sizeof(RGBQUAD) * ul,prgb);
+
+ FREEMISCPTR(prgb);
+ FREEARGPTR(parg16);
+
+ return(ul);
+}
+
+ULONG FASTCALL WG32SetDIBColorTable(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ RGBQUAD * prgb;
+
+ register PSETDIBCOLORTABLE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETDIBCOLORTABLE16), parg16);
+ GETMISCPTR(parg16->f4,prgb);
+
+ ul = (ULONG)SetDIBColorTable(HDC32(parg16->f1),
+ parg16->f2,
+ parg16->f3,
+ prgb);
+
+ WOW32APIWARN(ul, "SetDIBColorTable");
+
+ FREEMISCPTR(prgb);
+ FREEARGPTR(parg16);
+
+ return(ul);
+}
+
+
+// DIBSection routines
+
+BOOL W32CheckAndFreeDibSectionInfo (HBITMAP hbm)
+{
+ PDIBSECTIONINFO pdi = pDibSectionInfoHead,pdiLast=NULL;
+
+ while (pdi) {
+ if (pdi->di_hbm == hbm){
+
+ PARM16 Parm16;
+ ULONG ulRet;
+
+ // need to free the selector array for the memory
+
+ Parm16.WndProc.wParam = (WORD)-1; // selector, -1 == allocate/free
+ Parm16.WndProc.lParam = (LONG) pdi->di_pv16; // pointer
+ Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT
+ Parm16.WndProc.hwnd = 0; // selector count, 0 == free
+
+ CallBack16(RET_SETDIBSEL,
+ &Parm16,
+ 0,
+ (PVPVOID)&ulRet);
+#ifndef i386
+ VdmRemoveVirtualMemory((ULONG)pdi->di_newIntelDib);
+#endif
+
+ if (pdiLast == NULL)
+ pDibSectionInfoHead = pdi->di_next;
+ else
+ pdiLast->di_next = pdi->di_next;
+
+ // now delete the object
+
+ DeleteObject (pdi->di_hbm);
+
+ free_w(pdi);
+
+ return TRUE;
+ }
+ pdiLast = pdi;
+ pdi = pdi->di_next;
+ }
+ return FALSE;
+}
+
diff --git a/private/mvdm/wow32/wdib.h b/private/mvdm/wow32/wdib.h
new file mode 100644
index 000000000..7c8dccd3e
--- /dev/null
+++ b/private/mvdm/wow32/wdib.h
@@ -0,0 +1,86 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGDI.H
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+typedef struct _DIBINFO {
+ HDC di_hdc;
+ HANDLE di_hfile;
+ HANDLE di_hsec;
+ ULONG di_nalignment;
+ PVOID di_newdib;
+ PVOID di_newIntelDib;
+ HBITMAP di_hbm;
+ ULONG di_dibsize;
+ USHORT di_originaldibsel;
+ USHORT di_originaldibflags;
+ ULONG di_lockcount;
+ struct _DIBINFO *di_next;
+} DIBINFO, *PDIBINFO;
+
+
+HDC W32HandleDibDrv (PVPVOID vpbmi16);
+BOOL W32AddDibInfo ( HDC hdcMem,
+ HANDLE hfile,
+ HANDLE hsec,
+ ULONG nalignment,
+ PVOID newdib,
+ PVOID newIntelDib,
+ HBITMAP hbm,
+ ULONG dibsize,
+ USHORT OriginalFlags,
+ USHORT OriginalSel);
+
+BOOL W32CheckAndFreeDibInfo (HDC hdc);
+VOID W32FreeDibInfo (PDIBINFO pdiCur, PDIBINFO pdiLast);
+ULONG W32RestoreOldDib (PDIBINFO pdi);
+HDC W32FindAndLockDibInfo (USHORT sel);
+
+BOOL W32CheckDibDrvColorIndices(HDC16 hdcDest, HDC16 hdcSrc);
+VOID W32DibDrvColorIndicesRestore(void);
+
+typedef struct _DIBSECTIONINFO {
+ HBITMAP di_hbm;
+ PVOID di_pv16;
+ PVOID di_newIntelDib;
+ struct _DIBSECTIONINFO *di_next;
+} DIBSECTIONINFO, *PDIBSECTIONINFO;
+
+BOOL W32CheckAndFreeDibSectionInfo (HBITMAP hbm);
+ULONG cjBitmapBitsSize(CONST BITMAPINFO *pbmi);
+
+extern PDIBSECTIONINFO pDibSectionInfoHead;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// DIB Macros
+//
+///////////////////////////////////////////////////////////////////////////////
+//
+// These are commonly used macros for dib fields access
+//
+//
+
+#define __abs(a) ((a) >= 0 ? (a) : -(a))
+
+#define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
+#define DibWidthBytes(lpbi) (UINT)WIDTHBYTES((UINT)(lpbi)->biWidth * (UINT)((lpbi)->biBitCount))
+
+#define DibSizeImage(lpbi) ((DWORD)(UINT)DibWidthBytes(lpbi) * (DWORD)(UINT)(__abs((lpbi)->biHeight)))
+#define DibSize(lpbi) ((lpbi)->biSize + (lpbi)->biSizeImage + (int)(lpbi)->biClrUsed * sizeof(RGBQUAD))
+
+#define DibPtr(lpbi) (LPVOID)(DibColors(lpbi) + (UINT)(lpbi)->biClrUsed)
+#define DibColors(lpbi) ((LPRGBQUAD)((LPBYTE)(lpbi) + (int)(lpbi)->biSize))
+
+#define DibNumColors(lpbi) ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \
+ ? (int)(1 << (int)(lpbi)->biBitCount) \
+ : (int)(lpbi)->biClrUsed)
+
diff --git a/private/mvdm/wow32/wdos.c b/private/mvdm/wow32/wdos.c
new file mode 100644
index 000000000..d2946ca43
--- /dev/null
+++ b/private/mvdm/wow32/wdos.c
@@ -0,0 +1,823 @@
+/* wdos.c - DOS realted functions for WOW
+ *
+ * Modification History
+ *
+ * Sudeepb 23-Aug-1991 Created
+ */
+
+#include "precomp.h"
+#pragma hdrstop
+#include "curdir.h"
+
+
+MODNAME(wdos.c);
+
+ULONG demClientErrorEx (HANDLE hFile, CHAR chDrive, BOOL bSetRegs);
+
+extern DOSWOWDATA DosWowData;
+extern PWORD16 pCurTDB, pCurDirOwner;
+
+//
+// This is our local array of current directory strings. A particular entry
+// is only used if the directory becomes longer than the old MS-DOS limit
+// of 67 characters.
+//
+#define MAX_DOS_DRIVES 26
+LPSTR CurDirs[MAX_DOS_DRIVES] = {NULL};
+
+
+/* GetCurrentDir - Updatess current dir in CDS structure
+ *
+ * Entry - pcds = pointer to CDS
+ * chDrive = Physical Drive in question (0, 1 ...)
+ *
+ * Exit
+ * SUCCESS - returns TRUE
+ *
+ * FAILURE - returns FALSE
+ */
+BOOL GetCurrentDir (PCDS pcds, UCHAR Drive)
+{
+ static CHAR EnvVar[] = "=?:";
+ DWORD EnvVarLen;
+ BOOL bStatus = TRUE;
+ UCHAR FixedCount;
+ int i;
+ PCDS pcdstemp;
+
+ FixedCount = *(PUCHAR) DosWowData.lpCDSCount;
+ //
+ // from Macro.Asm in DOS:
+ // ; Sudeepb 20-Dec-1991 ; Added for redirected drives
+ // ; We always sync the redirected drives. Local drives are sync
+ // ; as per the curdir_tosync flag and SCS_ToSync
+ //
+
+ if (*(PUCHAR)DosWowData.lpSCS_ToSync) {
+
+ pcdstemp = (PCDS) DosWowData.lpCDSFixedTable;
+ for (i=0;i < (int)FixedCount; i++, pcdstemp++)
+ pcdstemp->CurDir_Flags |= CURDIR_TOSYNC;
+
+ // Mark tosync in network drive as well
+ pcdstemp = (PCDS)DosWowData.lpCDSBuffer;
+ pcdstemp->CurDir_Flags |= CURDIR_TOSYNC;
+
+ *(PUCHAR)DosWowData.lpSCS_ToSync = 0;
+ }
+
+ // If CDS needs to be synched or if the requested drive is different
+ // then the the drive being used by NetCDS go refresh the CDS.
+ if ((pcds->CurDir_Flags & CURDIR_TOSYNC) ||
+ ((Drive >= FixedCount) && (pcds->CurDir_Text[0] != (Drive + 'A') &&
+ pcds->CurDir_Text[0] != (Drive + 'a')))) {
+ // validate media
+ EnvVar[1] = Drive + 'A';
+ if((EnvVarLen = GetEnvironmentVariableOem (EnvVar, (LPSTR)pcds,
+ MAXIMUM_VDM_CURRENT_DIR+3)) == 0){
+
+ // if its not in env then and drive exist then we have'nt
+ // yet touched it.
+
+ pcds->CurDir_Text[0] = EnvVar[1];
+ pcds->CurDir_Text[1] = ':';
+ pcds->CurDir_Text[2] = '\\';
+ pcds->CurDir_Text[3] = 0;
+ SetEnvironmentVariableOem ((LPSTR)EnvVar,(LPSTR)pcds);
+ }
+
+ if (EnvVarLen > MAXIMUM_VDM_CURRENT_DIR+3) {
+ //
+ // The current directory on this drive is too long to fit in the
+ // cds. That's ok for a win16 app in general, since it won't be
+ // using the cds in this case. But just to be more robust, put
+ // a valid directory in the cds instead of just truncating it on
+ // the off chance that it gets used.
+ //
+ pcds->CurDir_Text[0] = EnvVar[1];
+ pcds->CurDir_Text[1] = ':';
+ pcds->CurDir_Text[2] = '\\';
+ pcds->CurDir_Text[3] = 0;
+ }
+
+ pcds->CurDir_Flags &= 0xFFFF - CURDIR_TOSYNC;
+ pcds->CurDir_End = 2;
+
+ }
+
+ if (!bStatus) {
+
+ *(PUCHAR)DosWowData.lpDrvErr = ERROR_INVALID_DRIVE;
+ }
+
+ return (bStatus);
+
+}
+
+/* SetCurrentDir - Set the current directory
+ *
+ *
+ * Entry - lpBuf = pointer to string specifying new directory
+ * chDrive = Physical Drive in question (0, 1 ...)
+ *
+ * Exit
+ * SUCCESS returns TRUE
+ * FAILURE returns FALSE
+ *
+ */
+
+BOOL SetCurrentDir (LPSTR lpBuf, UCHAR Drive)
+{
+ static CHAR EnvVar[] = "=?:";
+ CHAR chDrive = Drive + 'A';
+ BOOL bRet = FALSE;
+
+ if (SetCurrentDirectoryOem (lpBuf) == FALSE){
+ demClientErrorEx(INVALID_HANDLE_VALUE, chDrive, FALSE);
+ } else {
+
+ EnvVar[1] = chDrive;
+ if (SetEnvironmentVariableOem ((LPSTR)EnvVar,lpBuf) == TRUE) {
+ bRet = TRUE;
+ }
+ }
+
+ return (bRet);
+}
+
+
+/* QueryCurrentDir - Verifies current dir provided in CDS structure
+ * for $CURRENT_DIR
+ *
+ * First Validates Media, if invalid -> i24 error
+ * Next Validates Path, if invalid set path to root (not an error)
+ *
+ * Entry - Client (DS:SI) Buffer to CDS path to verify
+ * Client (AL) Physical Drive in question (A=0, B=1, ...)
+ *
+ * Exit
+ * SUCCESS
+ * Client (CY) = 0
+ *
+ * FAILURE
+ * Client (CY) = 1 , I24 drive invalid
+ */
+BOOL QueryCurrentDir (PCDS pcds, UCHAR Drive)
+{
+ DWORD dw;
+ CHAR chDrive;
+ static CHAR pPath[]="?:\\";
+ static CHAR EnvVar[] = "=?:";
+
+ // validate media
+ chDrive = Drive + 'A';
+ pPath[0] = chDrive;
+ dw = GetFileAttributesOem(pPath);
+ if (dw == 0xFFFFFFFF || !(dw & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ demClientErrorEx(INVALID_HANDLE_VALUE, chDrive, FALSE);
+ return (FALSE);
+ }
+
+ // if invalid path, set path to the root
+ // reset CDS, and win32 env for win32
+ dw = GetFileAttributesOem(pcds->CurDir_Text);
+ if (dw == 0xFFFFFFFF || !(dw & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ strcpy(pcds->CurDir_Text, pPath);
+ pcds->CurDir_End = 2;
+ EnvVar[1] = chDrive;
+ SetEnvironmentVariableOem(EnvVar,pPath);
+ }
+
+ return (TRUE);
+}
+
+
+/* strcpyCDS - copies CDS paths
+ *
+ * This routine emulates how DOS was coping the directory path. It is
+ * unclear if it is still necessary to do it this way.
+ *
+ * Entry -
+ *
+ * Exit
+ * SUCCESS
+ *
+ * FAILURE
+ */
+VOID strcpyCDS (PCDS source, LPSTR dest)
+{
+ char ch;
+ int index;
+
+ index = source->CurDir_End;
+
+ if (source->CurDir_Text[index]=='\\')
+ index++;
+
+ while (ch = source->CurDir_Text[index]) {
+
+ if ((ch == 0x05) && (source->CurDir_Text[index-1] == '\\')) {
+ ch = (CHAR) 0xE5;
+ }
+
+ *dest++ = toupper(ch);
+ index++;
+ }
+
+ *dest = ch; // trailing zero
+
+}
+
+
+/* GetCDSFromDrv - Updates current dir in CDS structure
+ *
+ * Entry - Drive = Physical Drive in question (0, 1 ...)
+ *
+ * Exit
+ * SUCCESS - returns v86 pointer to CDS structure in DOS
+ *
+ * FAILURE - returns 0
+ */
+
+PCDS GetCDSFromDrv (UCHAR Drive)
+{
+ PCDS pCDS = NULL;
+ static CHAR pPath[]="?:\\";
+ CHAR chDrive;
+ //
+ // Is Drive valid?
+ //
+
+ if (Drive >= *(PUCHAR)DosWowData.lpCDSCount) {
+
+ if (Drive <= 25) {
+
+ chDrive = Drive + 'A';
+ pPath[0] = chDrive;
+
+ //
+ // test to see if non-fixed/floppy drive exists
+ //
+
+ if ((*(PUCHAR)DosWowData.lpCurDrv == Drive) ||
+ (GetDriveType(pPath) > 1)) {
+
+ //
+ // Network drive
+ //
+
+ pCDS = (PCDS) DosWowData.lpCDSBuffer;
+ }
+
+ }
+
+ } else {
+
+ chDrive = Drive + 'A';
+ pPath[0] = chDrive;
+ if ((Drive != 1) || (DRIVE_REMOVABLE == GetDriveType(pPath))) {
+
+ //
+ // Drive defined in fixed table
+ //
+
+ pCDS = (PCDS) DosWowData.lpCDSFixedTable;
+ pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS)));
+ }
+
+ }
+
+ return (pCDS);
+}
+
+
+/* DosWowSetDefaultDrive - Emulate DOS set default drive call
+ *
+ * Entry -
+ * BYTE DriveNum; = drive number to switch to
+ *
+ * Exit
+ * returns client AX
+ *
+ */
+
+ULONG DosWowSetDefaultDrive(UCHAR Drive)
+{
+ PCDS pCDS;
+
+ if (NULL != (pCDS = GetCDSFromDrv (Drive))) {
+
+ if (GetCurrentDir (pCDS, Drive)) {
+
+ if (*(PUCHAR)DosWowData.lpCurDrv != Drive) {
+
+ // The upper bit in the TDB_Drive byte is used to indicate
+ // that the current drive and directory information in the
+ // TDB is stale. Turn it off here.
+ PTDB pTDB;
+ if (*pCurTDB) {
+ pTDB = (PTDB)SEGPTR(*pCurTDB,0);
+ if (TDB_SIGNATURE == pTDB->TDB_sig) {
+ pTDB->TDB_Drive &= ~TDB_DIR_VALID;
+ }
+ }
+
+ *(PUCHAR)DosWowData.lpCurDrv = Drive;
+ }
+
+ }
+ }
+
+ return (*(PUCHAR)DosWowData.lpCurDrv);
+
+}
+
+
+/* DosWowGetCurrentDirectory - Emulate DOS Get current Directory call
+ *
+ *
+ * Entry -
+ * Drive - Drive number for directory request
+ * pszDir- pointer to receive directory (MUST BE OF SIZE MAX_PATH)
+ *
+ * Exit
+ * SUCCESS
+ * 0
+ *
+ * FAILURE
+ * system status code
+ *
+ */
+ULONG DosWowGetCurrentDirectory(UCHAR Drive, LPSTR pszDir)
+{
+ PCDS pCDS;
+ DWORD dwRet = 0xFFFF000F; // assume error
+
+ //
+ // Handle default drive value of 0
+ //
+
+ if (Drive == 0) {
+ Drive = *(PUCHAR)DosWowData.lpCurDrv;
+ } else {
+ Drive--;
+ }
+
+ //
+ // If the path has grown larger than the old MS-DOS path size, then
+ // get the directory from our own private array.
+ //
+ if ((Drive<MAX_DOS_DRIVES) && CurDirs[Drive]) {
+ strcpy(pszDir, CurDirs[Drive]);
+ return 0;
+ }
+
+ if (NULL != (pCDS = GetCDSFromDrv (Drive))) {
+
+ if (GetCurrentDir (pCDS, Drive)) {
+ // for removable media we need to check that media is present.
+ // fixed disks, network drives and CDROM drives are fixed drives in
+ // DOS. sudeepb 30-Dec-1993
+ if (!(pCDS->CurDir_Flags & CURDIR_NT_FIX)) {
+ if(QueryCurrentDir (pCDS, Drive) == FALSE)
+ return (dwRet); // fail
+ }
+ strcpyCDS(pCDS, pszDir);
+ dwRet = 0;
+ }
+ }
+
+ return (dwRet);
+
+}
+
+/* DosWowSetCurrentDirectory - Emulate DOS Set current Directory call
+ *
+ *
+ * Entry -
+ * lpDosDirectory - pointer to new DOS directory
+ *
+ * Exit
+ * SUCCESS
+ * 0
+ *
+ * FAILURE
+ * system status code
+ *
+ */
+ULONG DosWowSetCurrentDirectory(LPSTR pszDir)
+{
+ PCDS pCDS;
+ UCHAR Drive;
+ LPTSTR pLast;
+ PSTR lpDirName;
+ UCHAR szPath[MAX_PATH];
+ DWORD dwRet = 0xFFFF0003; // assume error
+ static CHAR EnvVar[] = "=?:";
+ BOOL ItsANamedPipe = FALSE;
+
+ if (':' == pszDir[1]) {
+ Drive = toupper(pszDir[0]) - 'A';
+ } else {
+ if (IS_ASCII_PATH_SEPARATOR(pszDir[0]) &&
+ IS_ASCII_PATH_SEPARATOR(pszDir[1])) {
+ return dwRet; // can't update dos curdir with UNC
+ }
+ Drive = *(PUCHAR)DosWowData.lpCurDrv;
+ }
+
+
+ if (NULL != (pCDS = GetCDSFromDrv (Drive))) {
+
+ lpDirName = NormalizeDosPath(pszDir, Drive, &ItsANamedPipe);
+
+ GetFullPathNameOem(lpDirName, MAX_PATH, szPath, &pLast);
+
+ if (SetCurrentDir(szPath, Drive)) {
+ PTDB pTDB;
+
+ //
+ // If the directory is growing larger than the old MS-DOS max,
+ // then remember the path in our own array. If it is shrinking,
+ // then free up the string we allocated earlier.
+ //
+ if (strlen(szPath) > MAXIMUM_VDM_CURRENT_DIR+3) {
+ if ((!CurDirs[Drive]) &&
+ (NULL == (CurDirs[Drive] = malloc_w(MAX_PATH)))) {
+ return dwRet;
+ }
+ strcpy(CurDirs[Drive], &szPath[3]);
+ // put a valid directory in cds just for robustness' sake
+ strncpy(&pCDS->CurDir_Text[0], szPath, 3);
+ pCDS->CurDir_Text[3] = 0;
+ } else {
+ if (CurDirs[Drive]) {
+ free_w(CurDirs[Drive]);
+ CurDirs[Drive] = NULL;
+ }
+ strcpy(&pCDS->CurDir_Text[0], szPath);
+ }
+
+ dwRet = 0;
+
+ //
+ // Update kernel16's "directory owner" with the current TDB.
+ // Also, if we are changing to a directory that is different than
+ // what is currently in the TDB, then mark it as invalid.
+ //
+ if (*pCurTDB) {
+ pTDB = (PTDB)SEGPTR(*pCurTDB,0);
+ if (TDB_SIGNATURE == pTDB->TDB_sig) {
+ *pCurDirOwner = *pCurTDB;
+ if ((pTDB->TDB_Drive&TDB_DIR_VALID) &&
+ (*(PUCHAR)DosWowData.lpCurDrv == Drive) &&
+ ((Drive != (pTDB->TDB_Drive & ~TDB_DIR_VALID)) ||
+ (strcmp(&szPath[2], pTDB->TDB_LFNDirectory)))) {
+ pTDB->TDB_Drive &= ~TDB_DIR_VALID;
+ }
+ }
+ }
+ }
+
+ }
+
+ return (dwRet);
+}
+
+
+//*****************************************************************************
+// UpdateDosCurrentDirectory -
+//
+// Entry -
+// fDir - specifies which directory should be updated
+//
+// Exit -
+// TRUE if the update was successful, FALSE otherwise
+//
+// Notes:
+//
+// There are actually three different current directories:
+// - The WIN32 current directory (this is really the one that counts)
+// - The DOS current directory, kept on a per drive basis
+// - The TASK current directory, kept in the TDB of a win16 task
+//
+// It is the responsibility of this routine to effectively copy the contents
+// of one of these directories into another. From where to where is determined
+// by the passed parameter, so it is the caller's responsibility to be sure
+// what exactly needs to be sync'd up with what.
+//
+//*****************************************************************************
+
+BOOL UpdateDosCurrentDirectory(UDCDFUNC fDir)
+{
+ LONG lReturn = (LONG)FALSE;
+
+ switch(fDir) {
+
+ case DIR_DOS_TO_NT: {
+
+ UCHAR szPath[MAX_PATH] = "?:\\";
+ PTDB pTDB;
+
+ WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
+
+ if ((*pCurTDB) && (*pCurDirOwner != *pCurTDB)) {
+
+ pTDB = (PTDB)SEGPTR(*pCurTDB,0);
+
+ if ((TDB_SIGNATURE == pTDB->TDB_sig) &&
+ (pTDB->TDB_Drive & TDB_DIR_VALID)) {
+
+ szPath[0] = 'A' + (pTDB->TDB_Drive & ~TDB_DIR_VALID);
+ strcpy(&szPath[2], pTDB->TDB_LFNDirectory);
+
+ SetCurrentDirectoryOem(szPath);
+ break; // EXIT case
+ }
+ }
+
+
+ szPath[0] = *(PUCHAR)DosWowData.lpCurDrv + 'A';
+
+ if (CurDirs[*(PUCHAR)DosWowData.lpCurDrv]) {
+ SetCurrentDirectoryOem(CurDirs[*(PUCHAR)DosWowData.lpCurDrv]);
+ lReturn = TRUE;
+ break;
+ }
+
+ if (DosWowGetCurrentDirectory(0, &szPath[3])) {
+ LOGDEBUG(LOG_ERROR, ("DowWowGetCurrentDirectory failed\n"));
+ } else {
+ SetCurrentDirectoryOem(szPath);
+ lReturn = TRUE;
+ }
+ break;
+ }
+
+ case DIR_NT_TO_DOS: {
+
+ UCHAR szPath[MAX_PATH];
+
+ if (!GetCurrentDirectoryOem(MAX_PATH, szPath)) {
+
+ LOGDEBUG(LOG_ERROR, ("DowWowSetCurrentDirectory failed\n"));
+
+ } else {
+
+ LOGDEBUG(LOG_WARNING, ("UpdateDosCurrentDirectory: %s\n", &szPath[0]));
+ if (szPath[1] == ':') {
+ DosWowSetDefaultDrive((UCHAR) (szPath[0] - 'A'));
+ DosWowSetCurrentDirectory(szPath);
+ lReturn = TRUE;
+ }
+
+ }
+ break;
+ }
+
+ }
+ return (BOOL)lReturn;
+}
+
+/***************************************************************************
+
+ Stub entry points (called by KRNL386, 286 via thunks)
+
+ ***************************************************************************/
+
+
+/* WK32SetDefaultDrive - Emulate DOS set default drive call
+ *
+ * Entry -
+ * BYTE DriveNum; = drive number to switch to
+ *
+ * Exit
+ * returns client AX
+ *
+ */
+
+ULONG FASTCALL WK32SetDefaultDrive(PVDMFRAME pFrame)
+{
+ PWOWSETDEFAULTDRIVE16 parg16;
+ UCHAR Drive;
+
+ GETARGPTR(pFrame, sizeof(WOWSETDEFAULTDRIVE16), parg16);
+
+ Drive = (UCHAR) parg16->wDriveNum;
+
+ FREEARGPTR(parg16);
+
+ return (DosWowSetDefaultDrive (Drive));
+
+}
+
+
+/* WK32SetCurrentDirectory - Emulate DOS set current Directory call
+ *
+ * Entry -
+ * DWORD lpDosData = pointer to DosWowData structure in DOS
+ * parg16->lpDosDirectory - pointer to real mode DOS pdb variable
+ * parg16->wNewDirectory - 16-bit pmode selector for new Directory
+ *
+ * Exit
+ * SUCCESS
+ * 0
+ *
+ * FAILURE
+ * system status code
+ *
+ */
+ULONG FASTCALL WK32SetCurrentDirectory(PVDMFRAME pFrame)
+{
+
+ PWOWSETCURRENTDIRECTORY16 parg16;
+ LPSTR pszDir;
+ ULONG dwRet;
+
+ GETARGPTR(pFrame, sizeof(WOWSETCURRENTDIRECTORY16), parg16);
+ GETVDMPTR(parg16->lpCurDir, 4, pszDir);
+ FREEARGPTR(parg16);
+
+ dwRet = DosWowSetCurrentDirectory (pszDir);
+
+ FREEVDMPTR(pszDir);
+ return(dwRet);
+
+}
+
+
+/* WK32GetCurrentDirectory - Emulate DOS Get current Directory call
+ *
+ *
+ * Entry -
+ * DWORD lpDosData = pointer to DosWowData structure in DOS
+ * parg16->lpCurDir - pointer to buffer to receive directory
+ * parg16->wDriveNum - Drive number requested
+ * Upper bit (0x80) is set if the caller wants long path
+ *
+ * Exit
+ * SUCCESS
+ * 0
+ *
+ * FAILURE
+ * DOS error code (000f)
+ *
+ */
+ULONG FASTCALL WK32GetCurrentDirectory(PVDMFRAME pFrame)
+{
+ PWOWGETCURRENTDIRECTORY16 parg16;
+ LPSTR pszDir;
+ UCHAR Drive;
+ ULONG dwRet;
+
+ GETARGPTR(pFrame, sizeof(WOWGETCURRENTDIRECTORY16), parg16);
+ GETVDMPTR(parg16->lpCurDir, 4, pszDir);
+ Drive = (UCHAR) parg16->wDriveNum;
+ FREEARGPTR(parg16);
+
+ if (Drive<0x80) {
+ UCHAR ChkDrive;
+
+ //
+ // Normal GetCurrentDirectory call.
+ // If the path has grown larger than the old MS-DOS path size, then
+ // return error, just like on win95.
+ //
+
+ if (Drive == 0) {
+ ChkDrive = *(PUCHAR)DosWowData.lpCurDrv;
+ } else {
+ ChkDrive = Drive-1;
+ }
+ if ((Drive<MAX_DOS_DRIVES) && CurDirs[ChkDrive]) {
+ return 0xFFFF000F;
+ }
+
+ } else {
+
+ //
+ // the caller wants the long path path
+ //
+
+ Drive &= 0x7f;
+ }
+
+ dwRet = DosWowGetCurrentDirectory (Drive, pszDir);
+
+ FREEVDMPTR(pszDir);
+ return(dwRet);
+
+}
+
+/* WK32GetCurrentDate - Emulate DOS Get current Date call
+ *
+ *
+ * Entry -
+ *
+ * Exit
+ * return value is packed with date information
+ *
+ */
+ULONG FASTCALL WK32GetCurrentDate(PVDMFRAME pFrame)
+{
+ SYSTEMTIME systemtime;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ GetLocalTime(&systemtime);
+
+ return ((DWORD) (systemtime.wYear << 16 |
+ systemtime.wDay << 8 |
+ systemtime.wMonth << 4 |
+ systemtime.wDayOfWeek
+ ));
+
+}
+
+
+#if 0
+/* The following routine will probably never be used because we allow
+ WOW apps to set a local time within the WOW. So we really want apps
+ that read the time with int21 to go down to DOS where this local time
+ is kept. But if we ever want to return the win32 time, then this
+ routine will do it. */
+/* WK32GetCurrentTime - Emulate DOS Get current Time call
+ *
+ *
+ * Entry -
+ *
+ * Exit
+ * return value is packed with time information
+ *
+ */
+ULONG FASTCALL WK32GetCurrentTime(PVDMFRAME pFrame)
+{
+ SYSTEMTIME systemtime;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ GetLocalTime(&systemtime);
+
+ return ((DWORD) (systemtime.wHour << 24 |
+ systemtime.wMinute << 16 |
+ systemtime.wSecond << 8 |
+ systemtime.wMilliseconds/10
+ ));
+
+}
+#endif
+
+/* WK32DeviceIOCTL - Emulate misc. DOS IOCTLs
+ *
+ * Entry -
+ * BYTE DriveNum; = drive number
+ *
+ * Exit
+ * returns client AX
+ *
+ */
+
+ULONG FASTCALL WK32DeviceIOCTL(PVDMFRAME pFrame)
+{
+ PWOWDEVICEIOCTL16 parg16;
+ UCHAR Drive;
+ UCHAR Cmd;
+ DWORD dwReturn = 0xFFFF0001; // error invalid function
+ UINT uiDriveStatus;
+ static CHAR pPath[]="?:\\";
+
+ GETARGPTR(pFrame, sizeof(WOWDEVICEIOCTL16), parg16);
+
+ Cmd = (UCHAR) parg16->wCmd;
+ Drive = (UCHAR) parg16->wDriveNum;
+
+ FREEARGPTR(parg16);
+
+ if (Cmd != 8) { // Does Device Use Removeable Media
+ return (dwReturn);
+ }
+
+ if (Drive == 0) {
+ Drive = *(PUCHAR)DosWowData.lpCurDrv;
+ } else {
+ Drive--;
+ }
+
+ pPath[0] = Drive + 'A';
+ uiDriveStatus = GetDriveType(pPath);
+
+ if ((uiDriveStatus == 0) || (uiDriveStatus == 1)) {
+ return (0xFFFF000F); // error invalid drive
+ }
+
+ if (uiDriveStatus == DRIVE_REMOVABLE) {
+ dwReturn = 0;
+ } else {
+ dwReturn = 1;
+ }
+
+ return (dwReturn);
+
+}
diff --git a/private/mvdm/wow32/wdos.h b/private/mvdm/wow32/wdos.h
new file mode 100644
index 000000000..a8a6c4fc1
--- /dev/null
+++ b/private/mvdm/wow32/wdos.h
@@ -0,0 +1,24 @@
+/* wdos.h - DOS Defines for WOW
+ *
+ * Modification History
+ *
+ * Sudeepb 23-Aug-1991 Created
+ */
+
+ULONG FASTCALL WK32SetDefaultDrive(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetCurrentDirectory(PVDMFRAME pFrame);
+ULONG FASTCALL WK32SetCurrentDirectory(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetCurrentDate(PVDMFRAME pFrame);
+ULONG FASTCALL WK32DeviceIOCTL(PVDMFRAME pFrame);
+ULONG FASTCALL W32GetFlatAddressArray(PVDMFRAME pFrame);
+
+ULONG DosWowSetDefaultDrive (UCHAR);
+ULONG DosWowGetCurrentDirectory (UCHAR, LPSTR);
+ULONG DosWowSetCurrentDirectory (LPSTR);
+
+typedef enum {
+ DIR_NT_TO_DOS,
+ DIR_DOS_TO_NT,
+} UDCDFUNC;
+
+BOOL UpdateDosCurrentDirectory(UDCDFUNC fDir);
diff --git a/private/mvdm/wow32/wgdi.c b/private/mvdm/wow32/wgdi.c
new file mode 100644
index 000000000..fbe346901
--- /dev/null
+++ b/private/mvdm/wow32/wgdi.c
@@ -0,0 +1,4496 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGDI.C
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * 07-Mar-1991 Jeff Parsons (jeffpar)
+ * Created.
+ *
+ * 09-Apr-1991 NigelT
+ * Various defines are used here to remove calls to Win32
+ * features which don't work yet.
+ *
+ * 06-June-1992 Chandan Chauhan (ChandanC)
+ * Fixed BITMAP and DeviceIndependentBitmap (DIB) issues
+ *
+ * 22-May-1995 Craig Jones (a-craigj)
+ * METAFILE NOTE: several 32-bit API's will return TRUE when GDI is in
+ * "metafile" mode -- however, the POINT struct does not get
+ * updated by GDI32 even if the API returns successfully so
+ * we just return TRUE or FALSE as the point coors like W3.1.
+ *
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wowgdip.h"
+#include "wdib.h"
+
+#include "stddef.h" // these three are needed to include the
+#include "wingdip.h"
+ // definition of EXTTEXTMETRICS in wingdip.h
+ // [bodind]
+
+
+#define SETGDIXFORM 4113
+#define RESETPAGE 4114
+
+
+// This must be removed from POSTBETA for sure. ChandanC 3/22/94.
+
+#define IGNORESTARTPGAE 0x7FFFFFFF
+#define ADD_MSTT 0x7FFFFFFD
+
+
+MODNAME(wgdi.c);
+
+INT WINAPI SetRelAbs(HDC,INT); /* definition not in gdi.h */
+INT WINAPI GetRelAbs(HDC,INT); /* definition not in gdi.h */
+
+LPDEVMODE GetDefaultDevMode32(LPSTR szDriver); // Implemented in wspool.c
+
+// Hack for apps which try to be their own printer driver & send form feeds to
+// the printer in Escape(PassThrough) calls. This mechanism prevents an
+// additional page being spit out of the printer when the app calls EndDoc()
+// because GDI32 EndDoc() does an implicit form feed.
+typedef struct _FormFeedHack {
+ struct _FormFeedHack UNALIGNED *next;
+ HAND16 hTask16;
+ HDC hdc;
+ LPBYTE lpBytes;
+ int cbBytes;
+} FORMFEEDHACK;
+typedef FORMFEEDHACK UNALIGNED *PFORMFEEDHACK;
+
+PFORMFEEDHACK gpFormFeedHackList = NULL; // start of global formfeed Hack list
+
+LONG HandleFormFeedHack(HDC hdc, LPBYTE lpdata, int cb);
+LPBYTE SendFrontEndOfDataStream(HDC hdc, LPBYTE lpData, int *cb, LONG *ul);
+void FreeFormFeedHackNode(PFORMFEEDHACK pNode);
+void FreeTaskFormFeedHacks(HAND16 hTask16);
+void SendFormFeedHack(HDC hdc);
+PFORMFEEDHACK FindFormFeedHackNode(HDC hdc);
+PFORMFEEDHACK CreateFormFeedHackNode(HDC hdc, int cb, LPBYTE lpData);
+void RemoveFormFeedHack(HDC hdc);
+
+
+
+ULONG FASTCALL WG32Arc(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PARC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ARC16), parg16);
+
+ ul = GETBOOL16(Arc(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ INT32(parg16->f6),
+ INT32(parg16->f7),
+ INT32(parg16->f8),
+ INT32(parg16->f9)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32BitBlt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PBITBLT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(BITBLT16), parg16);
+
+
+ ul = GETBOOL16(BitBlt(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ HDC32(parg16->f6),
+ INT32(parg16->f7),
+ INT32(parg16->f8),
+ DWORD32(parg16->f9)));
+
+ WOW32APIWARN (ul, "BitBlt");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetRelAbs(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETRELABS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETRELABS16), parg16);
+
+ ul = GETINT16(GetRelAbs(HDC32(parg16->f1), 0));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+ULONG FASTCALL WG32SetRelAbs(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETRELABS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETRELABS16), parg16);
+
+ ul = GETINT16(SetRelAbs(HDC32(parg16->f1), INT32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32Chord(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCHORD16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CHORD16), parg16);
+
+ ul = GETBOOL16(Chord(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ INT32(parg16->f6),
+ INT32(parg16->f7),
+ INT32(parg16->f8),
+ INT32(parg16->f9)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CombineRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCOMBINERGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(COMBINERGN16), parg16);
+
+ ul = GETINT16(CombineRgn(HRGN32(parg16->f1),
+ HRGN32(parg16->f2),
+ HRGN32(parg16->f3),
+ INT32(parg16->f4)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateBitmap(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATEBITMAP16 parg16;
+ LPBYTE lpBitsOriginal;
+
+ GETARGPTR(pFrame, sizeof(CREATEBITMAP16), parg16);
+ GETOPTPTR(parg16->f5, 0, lpBitsOriginal);
+
+ ul = GETHBITMAP16(CreateBitmap(INT32(parg16->f1),
+ INT32(parg16->f2),
+ LOBYTE(parg16->f3),
+ LOBYTE(parg16->f4),
+ lpBitsOriginal));
+
+ WOW32APIWARN(ul, "CreateBitmap");
+
+ FREEOPTPTR(lpBitsOriginal);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateBitmapIndirect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATEBITMAPINDIRECT16 parg16;
+
+ PBITMAP16 pbm16;
+ BITMAP bm;
+ LPBYTE lp = NULL;
+
+ GETARGPTR(pFrame, sizeof(CREATEBITMAPINDIRECT16), parg16);
+
+ GETVDMPTR(parg16->f1, sizeof(BITMAP16), pbm16);
+ GETOPTPTR(pbm16->bmBits, 0, lp);
+
+ bm.bmType = (LONG) FETCHSHORT(pbm16->bmType);
+ bm.bmWidth = (LONG) FETCHSHORT(pbm16->bmWidth);
+ bm.bmHeight = (LONG) FETCHSHORT(pbm16->bmHeight);
+ bm.bmWidthBytes = (LONG) FETCHSHORT(pbm16->bmWidthBytes);
+ bm.bmPlanes = (WORD) pbm16->bmPlanes;
+ bm.bmBitsPixel = (WORD) pbm16->bmBitsPixel;
+ bm.bmBits = lp;
+
+ ul = GETHBITMAP16(CreateBitmapIndirect(&bm));
+
+ WOW32APIWARN(ul, "CreateBitmapIndirect");
+
+ FREEOPTPTR(lp);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WG32CreateBrushIndirect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LOGBRUSH t1;
+ HAND16 hMem16;
+ HANDLE hMem32 = NULL;
+ LPBYTE lpMem16, lpMem32;
+ INT cb;
+ VPVOID vp;
+ register PCREATEBRUSHINDIRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEBRUSHINDIRECT16), parg16);
+ GETLOGBRUSH16(parg16->f1, &t1);
+
+ // some apps don't properly set the style. Make sure it is a valid w3.1 style
+
+ if (t1.lbStyle > BS_DIBPATTERN)
+ t1.lbStyle = BS_SOLID;
+
+ if (t1.lbStyle == BS_PATTERN) {
+ t1.lbStyle = BS_PATTERN8X8;
+ }
+ else if (t1.lbStyle == BS_DIBPATTERN) {
+ hMem16 = (WORD) t1.lbHatch;
+ if (hMem16) {
+ vp = RealLockResource16(hMem16, &cb);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ hMem32 = GlobalAlloc(GMEM_MOVEABLE, cb);
+ WOW32ASSERT(hMem32);
+ if (hMem32) {
+ lpMem32 = GlobalLock(hMem32);
+ RtlCopyMemory(lpMem32, lpMem16, cb);
+ GlobalUnlock(hMem32);
+ }
+ GlobalUnlock16(hMem16);
+ FREEMISCPTR(lpMem16);
+ }
+ }
+ t1.lbHatch = (LONG)hMem32;
+ }
+ else if (t1.lbStyle == BS_SOLID)
+ {
+ if (((ULONG)t1.lbColor & 0xff000000) > 0x02000000)
+ t1.lbColor &= 0xffffff;
+ }
+
+ ul = GETHBRUSH16(CreateBrushIndirect(&t1));
+
+ if (hMem32)
+ {
+ GlobalFree(hMem32);
+ }
+
+ WOW32APIWARN(ul, "CreateBrushIndirect");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateCompatibleBitmap(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATECOMPATIBLEBITMAP16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATECOMPATIBLEBITMAP16), parg16);
+
+ ul = GETHBITMAP16(CreateCompatibleBitmap(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3)));
+
+ WOW32APIWARN(ul, "CreateCompatibleBitmap");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateCompatibleDC(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ HDC hdc;
+ register PCREATECOMPATIBLEDC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATECOMPATIBLEDC16), parg16);
+
+ if ( parg16->f1 ) {
+ hdc = HDC32(parg16->f1);
+ if ( hdc == NULL ) {
+ FREEARGPTR(parg16);
+ return(0);
+ }
+ } else {
+ hdc = NULL;
+ }
+ ul = GETHDC16(CreateCompatibleDC(hdc));
+//
+// Some apps such as MSWORKS and MS PUBLISHER use some wizard code that accepts
+// a hDC or a hWnd as a parameter and attempt to figure out what type of handle
+// it is by using the IsWindow() call. Since both handles come from different
+// handle spaces they may end up the same value and this wizard code will end
+// up writing to the DC for a random window. By ORing in a 1 we ensure that the
+// handle types will never share the same value since all hWnds are even. Note
+// that this hack is also made in WU32GetDC().
+//
+// Note that there are some apps that use the lower 2 bits of the hDC for their
+// own purposes.
+ if (ul && CURRENTPTD()->dwWOWCompatFlags & WOWCF_UNIQUEHDCHWND) {
+ ul = ul | 1;
+ }
+
+ WOW32APIWARN(ul, "CreateCompatibleDC");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateDC(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz;
+ PSZ psz1 = NULL;
+ PSZ psz2 = NULL;
+ PSZ psz3 = NULL;
+ PSZ pszDib;
+ LPDEVMODE t4 = NULL;
+ register PCREATEDC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEDC16), parg16);
+
+ GETPSZPTR(parg16->f1, psz);
+ if(psz) {
+ psz1 = malloc_w(lstrlen(psz)+1);
+ if(psz1) {
+ lstrcpy(psz1, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ GETPSZPTR(parg16->f2, psz);
+ if(psz) {
+ psz2 = malloc_w(lstrlen(psz)+1);
+ if(psz2) {
+ lstrcpy(psz2, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ GETPSZPTR(parg16->f3, psz);
+ if(psz) {
+ psz3 = malloc_w(lstrlen(psz)+1);
+ if(psz3) {
+ lstrcpy(psz3, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ // Note: parg16->f4 will usually be a lpDevMode, but it is documented
+ // that it can also be a lpBitMapInfo if the driver name is "dib.drv"
+
+ // test for "dib.drv". Director 4.0 uses "dirdib.drv"
+ if ((pszDib = strstr (psz1, "DIB")) ||
+ (pszDib = strstr (psz1, "dib"))) {
+ if (_stricmp (pszDib, "DIB") == 0 ||
+ _stricmp (pszDib, "DIB.DRV") == 0) {
+ ul = GETHDC16(W32HandleDibDrv ((PVPVOID)parg16->f4));
+ // Note: flat 16:16 ptrs should be considered invalid after this call
+ }
+ }
+
+ // handle normal non-dib.drv case
+ else {
+ if (FETCHDWORD(parg16->f4) == 0L) {
+ t4 = GetDefaultDevMode32(psz2);
+ }
+ else {
+ t4 = ThunkDevMode16to32(parg16->f4);
+ }
+
+ // this can callback into a 16-bit fax driver!
+ ul = GETHDC16(CreateDC(psz1, psz2, psz3, t4));
+ // Note: flat 16:16 ptrs should be considered invalid after this call
+ }
+
+ WOW32APIWARN(ul, "CreateDC");
+
+ FREEDEVMODE32(t4);
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateDIBPatternBrush(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ LPBYTE lpb16;
+ LOGBRUSH logbr;
+ register PCREATEDIBPATTERNBRUSH16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEDIBPATTERNBRUSH16), parg16);
+ GETMISCPTR(parg16->f1, lpb16);
+ logbr.lbStyle = BS_DIBPATTERN8X8;
+ logbr.lbColor = WORD32(parg16->f2);
+ logbr.lbHatch = (LONG) lpb16;
+
+ ul = GETHBRUSH16(CreateBrushIndirect(&logbr));
+ WOW32APIWARN(ul, "CreateDIBPatternBrush");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateDIBitmap(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ LPBYTE lpib4;
+ BITMAPINFOHEADER bmxh2;
+ STACKBMI32 bmi32;
+ LPBITMAPINFOHEADER lpbmih32;
+ LPBITMAPINFO lpbmi32;
+
+
+ register PCREATEDIBITMAP16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEDIBITMAP16), parg16);
+ GETMISCPTR(parg16->f4, lpib4);
+
+ lpbmih32 = CopyBMIH16ToBMIH32((PVPVOID) FETCHDWORD(parg16->f2), &bmxh2);
+
+ lpbmi32 = CopyBMI16ToBMI32((PVPVOID)FETCHDWORD(parg16->f5),
+ (LPBITMAPINFO)&bmi32,
+ FETCHWORD(parg16->f6));
+
+ // Code below fixes problems in Sounditoutland with rle-encoded
+ // bitmaps which have biSizeImage == 0. On Win 3.1 they work since
+ // gdi is happy with decoding some piece of memory. NT GDI however
+ // needs to know the size of bits passed. We remedy this by calculating
+ // size using RET_GETDIBSIZE (GetSelectorLimit). GDI won't copy the
+ // memory, it will just use size as indication of accessibility
+ // Application: "Sound It Out Land",
+
+ if (lpbmi32 && (lpbmi32->bmiHeader.biCompression == BI_RLE4 ||
+ lpbmi32->bmiHeader.biCompression == BI_RLE8) &&
+ lpbmi32->bmiHeader.biSizeImage == 0 &&
+ lpib4 != NULL &&
+ DWORD32(parg16->f3) == CBM_INIT) {
+
+ // we have to determine what the size is
+
+ PARM16 Parm16; // prepare to callback
+ ULONG SelectorLimit;
+ LONG lSize;
+ LPBITMAPINFOHEADER lpbmi = &lpbmi32->bmiHeader;
+
+ // now what is this 16:16 ?
+
+ Parm16.WndProc.wParam = HIWORD((LPVOID)parg16->f4);
+ CallBack16(RET_GETDIBSIZE,
+ &Parm16,
+ 0,
+ (PVPVOID)&SelectorLimit);
+ if (SelectorLimit != 0 && SelectorLimit != 0xffffffff) {
+ // so sel is valid
+ // now see how much room we have in there
+ lSize = (LONG)SelectorLimit - LOWORD((LPVOID)parg16->f4);
+ // now we have size
+ if (lSize > 0) {
+ lpbmi->biSizeImage = lSize;
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS, ("CreateDIBitmap: Bad size of the bits ptr\n"));
+ }
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS, ("CreateDIBitmap: Selector [ptr:%x] is invalid\n", (DWORD)parg16->f4));
+ }
+ }
+
+ ul = GETHBITMAP16(CreateDIBitmap(HDC32(parg16->f1),
+ lpbmih32,
+ DWORD32(parg16->f3),
+ lpib4,
+ lpbmi32,
+ WORD32(parg16->f6) ));
+
+ WOW32APIWARN(ul, "CreateDIBitmap");
+
+ FREEMISCPTR(lpib4);
+ FREEARGPTR(parg16);
+
+ return(ul);
+}
+
+ULONG FASTCALL WG32CreateDiscardableBitmap(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATEDISCARDABLEBITMAP16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEDISCARDABLEBITMAP16), parg16);
+
+ ul = GETHBITMAP16(CreateDiscardableBitmap(HDC32(parg16->hdc),
+ INT32(parg16->width),
+ INT32(parg16->height)));
+
+ WOW32APIWARN(ul, "CreateDiscardableBitmap");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateEllipticRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATEELLIPTICRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEELLIPTICRGN16), parg16);
+
+ ul = GETHRGN16(CreateEllipticRgn(INT32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4)));
+
+ WOW32APIWARN(ul, "CreateEllipticRgn");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateEllipticRgnIndirect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t1;
+ register PCREATEELLIPTICRGNINDIRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEELLIPTICRGNINDIRECT16), parg16);
+ WOW32VERIFY(GETRECT16(parg16->f1, &t1));
+
+ ul = GETHRGN16(CreateEllipticRgnIndirect(&t1));
+
+ WOW32APIWARN(ul, "CreateEllipticRgnIndirect");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateHatchBrush(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATEHATCHBRUSH16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEHATCHBRUSH16), parg16);
+
+ ul = GETHBRUSH16(CreateHatchBrush(INT32(parg16->f1), DWORD32(parg16->f2)));
+
+ WOW32APIWARN(ul, "CreateHatchBrush");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WG32CreateIC(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz;
+ PSZ psz1 = NULL;
+ PSZ psz2 = NULL, psz2t;
+ PSZ psz3 = NULL;
+ LPDEVMODE t4;
+ register PCREATEIC16 parg16;
+ INT len;
+ PCHAR pch;
+
+ GETARGPTR(pFrame, sizeof(CREATEIC16), parg16);
+
+ GETPSZPTR(parg16->f1, psz);
+ if(psz) {
+ psz1 = malloc_w(lstrlen(psz)+1);
+ if(psz1) {
+ lstrcpy(psz1, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ GETPSZPTR(parg16->f2, psz);
+ if(psz) {
+ psz2 = malloc_w(lstrlen(psz)+1);
+ if(psz2) {
+ lstrcpy(psz2, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ GETPSZPTR(parg16->f3, psz);
+ if(psz) {
+ psz3 = malloc_w(lstrlen(psz)+1);
+ if(psz3) {
+ lstrcpy(psz3, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ if (FETCHDWORD(parg16->f4) != 0L) {
+ t4 = ThunkDevMode16to32(parg16->f4);
+ }
+ else {
+ t4 = GetDefaultDevMode32(psz2);
+ }
+
+ // invalidate all flat ptrs to 16:16 memory now!
+ FREEARGPTR(parg16);
+
+ psz2t = psz2;
+
+ //
+ // HACK Alert!
+ //
+ // NBI's Legacy comes with a pscript.drv that resides in [AppPath]\cbt
+ // they call CreateIC() specifying the the path to this file as the driver.
+ // the app GP faults if the CreateIC returns 0. once they've loaded this
+ // printer driver, on successive calls to CreateIC() they simply use
+ // "PSCRIPT" as the driver name and use "PostScript Printer", "FILE:" as
+ // the other parms.
+ // let's recognize these driver names and try to replace it with the
+ // system default printer. if there's no printer installed, a GP fault
+ // is unavoidable. the app appears to use this pscript.drv only during
+ // the tutorial, so we're not providing life-support for an app that's
+ // clinically dead.
+ //
+
+ //
+ // check for a driver name that ends with "PSCRIPT" and if so,
+ // check that the device name is "PostScript Printer".
+ // on NT the driver name should always be "winspool", although it's
+ // completely ignored.
+ //
+ // PageMaker 5.0a calls this with ("pscript","Postscript printer","LPT1:",0)
+ // when opening calibrat.pt5
+
+ len = psz1 ? strlen(psz1) : 0;
+ if (len >= 7) {
+#if 0
+ static CHAR achPS[] = "PostScript Printer";
+#endif
+
+ if (!_stricmp(psz1+len-7, "pscript")
+#if 0
+ // let's see who else thinks they're using a pscript driver
+ //
+ && (RtlCompareMemory(achPS, psz2, sizeof(achPS)) == sizeof(achPS))
+#endif
+ ) {
+
+ DWORD dw;
+ CHAR achDevice[256];
+
+ LOGDEBUG(LOG_ALWAYS,("WOW32: CreateIC - detected request for Pscript driver\n"));
+ dw = GetProfileString("windows", "device", "", achDevice,
+ sizeof(achDevice));
+ if (dw) {
+ psz2t = achDevice;
+ pch = strchr(achDevice, ',');
+ if (pch) {
+ *pch = '\0';
+ }
+ }
+ }
+ }
+
+ // this can callback into a 16-bit fax driver!
+ ul = GETHDC16(CreateIC(psz1, psz2t, psz3, t4));
+
+ WOW32APIWARN(ul, "CreateIC");
+
+ FREEDEVMODE32(t4);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreatePatternBrush(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LOGBRUSH logbr;
+ register PCREATEPATTERNBRUSH16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEPATTERNBRUSH16), parg16);
+
+ logbr.lbStyle = BS_PATTERN8X8;
+ logbr.lbColor = 0;
+ logbr.lbHatch = (LONG)HBITMAP32(parg16->f1);
+
+ ul = GETHBRUSH16(CreateBrushIndirect(&logbr));
+
+ WOW32APIWARN(ul, "CreatePatternBrush");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreatePen(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATEPEN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEPEN16), parg16);
+
+ ul = GETHPEN16(CreatePen(INT32(parg16->f1),
+ INT32(parg16->f2),
+ DWORD32(parg16->f3)));
+
+ WOW32APIWARN(ul, "CreatePen");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreatePenIndirect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LOGPEN t1;
+ register PCREATEPENINDIRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEPENINDIRECT16), parg16);
+ GETLOGPEN16(parg16->f1, &t1);
+
+ ul = GETHPEN16(CreatePenIndirect(&t1));
+
+ WOW32APIWARN(ul, "CreatePenIndirect");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreatePolyPolygonRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPPOINT pPoints;
+ PINT pPolyCnt;
+ UINT cpts = 0;
+ INT ii;
+ register PCREATEPOLYPOLYGONRGN16 parg16;
+ INT cInt16;
+ INT BufferT[256]; // comfortably large array
+
+ GETARGPTR(pFrame, sizeof(CREATEPOLYPOLYGONRGN16), parg16);
+ cInt16 = INT32(parg16->f3);
+ pPolyCnt = STACKORHEAPALLOC(cInt16 * sizeof(INT), sizeof(BufferT), BufferT);
+ if (!pPolyCnt) {
+ FREEARGPTR(parg16);
+ RETURN(0);
+ }
+
+ getintarray16(parg16->f2, cInt16, pPolyCnt);
+ for (ii=0; ii < cInt16; ii++)
+ cpts += pPolyCnt[ii];
+
+ pPoints = STACKORHEAPALLOC(cpts * sizeof(POINT),
+ sizeof(BufferT) - cInt16 * sizeof(INT),
+ BufferT + cInt16);
+ getpoint16(parg16->f1, cpts, pPoints);
+
+ ul = GETHRGN16(CreatePolyPolygonRgn(pPoints,
+ pPolyCnt,
+ INT32(parg16->f3),
+ INT32(parg16->f4)));
+
+ WOW32APIWARN(ul, "CreatePolyPolygonRgn");
+
+ STACKORHEAPFREE(pPoints, BufferT + cInt16);
+ STACKORHEAPFREE(pPolyCnt, BufferT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreatePolygonRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPPOINT t1;
+ register PCREATEPOLYGONRGN16 parg16;
+ POINT BufferT[128];
+
+ GETARGPTR(pFrame, sizeof(CREATEPOLYGONRGN16), parg16);
+ t1 = STACKORHEAPALLOC(parg16->f2 * sizeof(POINT), sizeof(BufferT), BufferT);
+ getpoint16(parg16->f1, parg16->f2, t1);
+
+ ul = GETHRGN16(CreatePolygonRgn(t1, INT32(parg16->f2), INT32(parg16->f3)));
+
+ WOW32APIWARN(ul, "CreatePolygonRgn");
+
+ STACKORHEAPFREE(t1, BufferT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateRectRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATERECTRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATERECTRGN16), parg16);
+
+ ul = GETHRGN16(CreateRectRgn(INT32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4)));
+
+ WOW32APIWARN(ul, "CreateRectRgn");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateRectRgnIndirect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t1;
+ register PCREATERECTRGNINDIRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATERECTRGNINDIRECT16), parg16);
+ WOW32VERIFY(GETRECT16(parg16->f1, &t1));
+
+ ul = GETHRGN16(CreateRectRgnIndirect(&t1));
+
+ WOW32APIWARN(ul, "CreateRectRgnIndirect");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateRoundRectRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATEROUNDRECTRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEROUNDRECTRGN16), parg16);
+
+ ul = GETHRGN16(CreateRoundRectRgn(INT32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ INT32(parg16->f6)));
+
+ WOW32APIWARN(ul, "CreateRoundRectRgn");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateSolidBrush(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATESOLIDBRUSH16 parg16;
+ DWORD dwColor;
+
+ GETARGPTR(pFrame, sizeof(CREATESOLIDBRUSH16), parg16);
+
+ dwColor = DWORD32(parg16->f1);
+
+ if (((ULONG)dwColor & 0xff000000) > 0x02000000)
+ dwColor &= 0xffffff;
+
+ ul = GETHBRUSH16(CreateSolidBrush(dwColor));
+ WOW32APIWARN(ul, "CreateSolidBrush");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32DPtoLP(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPPOINT t2;
+ register PDPTOLP16 parg16;
+ POINT BufferT[128];
+
+ GETARGPTR(pFrame, sizeof(DPTOLP16), parg16);
+ t2 = STACKORHEAPALLOC(parg16->f3 * sizeof(POINT), sizeof(BufferT), BufferT);
+ getpoint16(parg16->f2, parg16->f3, t2);
+
+ ul = GETBOOL16(DPtoLP(HDC32(parg16->f1), t2, INT32(parg16->f3)));
+
+ PUTPOINTARRAY16(parg16->f2, parg16->f3, t2);
+ STACKORHEAPFREE(t2, BufferT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32DeleteDC(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDELETEDC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DELETEDC16), parg16);
+
+ if ((ul = W32CheckAndFreeDibInfo (HDC32(parg16->f1))) == FALSE) {
+ ul = GETBOOL16(DeleteDC(HDC32(parg16->f1)));
+
+ // Free 16-bit handle alias if 32-bit handle successfully deleted
+ if (ul) {
+ FREEHOBJ16(parg16->f1);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32DeleteObject(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDELETEOBJECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DELETEOBJECT16), parg16);
+
+ if ((pDibSectionInfoHead == NULL) ||
+ (ul = W32CheckAndFreeDibSectionInfo (HBITMAP32(parg16->f1))) == FALSE) {
+
+ ul = GETBOOL16(DeleteObject(HOBJ32(parg16->f1)));
+
+ // Free 16-bit handle alias if 32-bit handle successfully deleted
+ if (ul) {
+ FREEHOBJ16(parg16->f1);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32Ellipse(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PELLIPSE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ELLIPSE16), parg16);
+
+ ul = GETBOOL16(Ellipse(HDC32(parg16->hdc),
+ INT32(parg16->x1),
+ INT32(parg16->y1),
+ INT32(parg16->x2),
+ INT32(parg16->y2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+// WARNING: This function may cause 16-bit memory movement
+INT W32EnumObjFunc(LPSTR lpLogObject, PENUMOBJDATA pEnumObjData)
+{
+ PARM16 Parm16;
+ INT iReturn;
+
+ WOW32ASSERT(pEnumObjData);
+
+ switch (pEnumObjData->ObjType) {
+ case OBJ_BRUSH:
+ PUTLOGBRUSH16(pEnumObjData->vpObjData, sizeof(LOGBRUSH), (LPLOGBRUSH)lpLogObject);
+ break;
+ case OBJ_PEN:
+ PUTLOGPEN16(pEnumObjData->vpObjData, sizeof(LOGPEN), (LPLOGPEN)lpLogObject);
+ break;
+ default:
+ LOGDEBUG(LOG_ALWAYS,("WOW32 ERROR -- Illegal type %d passes to EnumObj\n",pEnumObjData->ObjType));
+ return 0;
+ } // end switch
+
+ STOREDWORD(Parm16.EnumObjProc.vpLogObject, pEnumObjData->vpObjData);
+ STOREDWORD(Parm16.EnumObjProc.vpData, pEnumObjData->dwUserParam);
+ CallBack16(RET_ENUMOBJPROC, &Parm16, pEnumObjData->vpfnEnumObjProc, (PVPVOID)&iReturn);
+
+ return (SHORT)iReturn;
+
+
+}
+
+
+ULONG FASTCALL WG32EnumObjects(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PENUMOBJECTS16 parg16;
+ ENUMOBJDATA EnumObjData;
+
+ GETARGPTR(pFrame, sizeof(ENUMOBJECTS16), parg16);
+
+ EnumObjData.ObjType = INT32(parg16->f2);
+
+ switch(EnumObjData.ObjType) {
+ case OBJ_BRUSH:
+ EnumObjData.vpObjData = malloc16(sizeof(LOGBRUSH16));
+ break;
+ case OBJ_PEN:
+ EnumObjData.vpObjData = malloc16(sizeof(LOGPEN16));
+ break;
+ default:
+ LOGDEBUG(LOG_ALWAYS,("WOW32 ERROR -- Illegal type %d passes to EnumObj\n",EnumObjData.ObjType));
+ EnumObjData.vpObjData = (VPVOID)0;
+ }
+ // malloc16 may have caused 16-bit memory movement - invalidate flat ptrs
+ FREEVDMPTR(pFrame);
+ FREEARGPTR(parg16);
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(ENUMOBJECTS16), parg16);
+
+ if( EnumObjData.vpObjData ) {
+ EnumObjData.vpfnEnumObjProc = DWORD32(parg16->f3);
+ EnumObjData.dwUserParam = DWORD32(parg16->f4);
+
+ ul = (ULONG)(GETINT16(EnumObjects(HDC32(parg16->f1),
+ (int)INT32(parg16->f2),
+ (GOBJENUMPROC)W32EnumObjFunc,
+ (LPARAM)&EnumObjData)));
+ // 16-bit memory may have moved - invalidate flat pointers
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ free16(EnumObjData.vpObjData);
+
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32EqualRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PEQUALRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(EQUALRGN16), parg16);
+
+ ul = GETBOOL16(EqualRgn(HRGN32(parg16->f1), HRGN32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**************************************************************************\
+*
+\**************************************************************************/
+
+typedef struct _ESCKERNPAIR {
+ union
+ {
+ BYTE each[2];
+ WORD both;
+ } kpPair;
+ SHORT KernAmount;
+} ESCKERNPAIR;
+
+/******************************Public*Routine******************************\
+* iGetKerningPairsEsc32
+*
+* History:
+* Tue 16-Mar-1993 11:08:36 by Kirk Olynyk [kirko]
+* Wrote it.
+\**************************************************************************/
+
+int
+iGetKerningPairsEsc32(
+ HDC hdc,
+ ESCKERNPAIR *pekp
+ )
+{
+ int i,j;
+ int n;
+ HGLOBAL hglblMem = NULL;
+
+ ESCKERNPAIR *pekpT, *pekpTOut;
+ KERNINGPAIR *pkpT;
+
+ KERNINGPAIR *pkp = (KERNINGPAIR*) NULL;
+
+ if
+ (
+ (n = GetKerningPairs(hdc,0,NULL)) &&
+ (hglblMem = GlobalAlloc(GMEM_FIXED, n * sizeof(KERNINGPAIR))) &&
+ (pkp = (KERNINGPAIR*) GlobalLock(hglblMem)) &&
+ (n = (int) GetKerningPairs(hdc, n, pkp))
+ )
+ {
+ n = min(n,512);
+
+ //
+ // load the low byte of each word, Win 3.1 doesn't seem to care about
+ // the high byte
+ //
+ pekpT = pekp;
+ pekpTOut = pekp + n;
+ pkpT = pkp;
+
+ while (pekpT < pekpTOut)
+ {
+ pekpT->kpPair.each[0] = (BYTE) pkpT->wFirst;
+ pekpT->kpPair.each[1] = (BYTE) pkpT->wSecond;
+ pekpT->KernAmount = (SHORT) pkpT->iKernAmount;
+
+ pekpT += 1;
+ pkpT += 1;
+ }
+
+ //
+ // bubble sort word formed by byte pair
+ //
+ for (i = 0; i < n - 1; i++)
+ {
+ for (j = n-1; j > i; --j)
+ {
+ if (pekp[j-1].kpPair.both > pekp[j].kpPair.both)
+ {
+ ESCKERNPAIR ekp;
+
+ ekp = pekp[j];
+ pekp[j] = pekp[j-1];
+ pekp[j] = ekp;
+ }
+ }
+ }
+ }
+
+ if (hglblMem != NULL)
+ {
+ GlobalUnlock(hglblMem);
+ GlobalFree(hglblMem);
+ }
+
+ return(n);
+}
+
+ULONG FASTCALL WG32Escape(PVDMFRAME pFrame)
+{
+ ULONG ul=0;
+ register PESCAPE16 parg16;
+ PVOID pin;
+ int iMapMode;
+ CHAR buf[32];
+
+ GETARGPTR(pFrame, sizeof(ESCAPE16), parg16);
+ GETOPTPTR(parg16->f4, 0, pin);
+
+
+ switch (INT32(parg16->f2)) {
+ case GETPHYSPAGESIZE:
+ case GETPRINTINGOFFSET:
+ case GETSCALINGFACTOR:
+ { POINT pt;
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ pin,
+ (LPSTR)&pt));
+
+ if (!ul)
+ {
+ // if these fail, they are almost certainly doing it on a display dc.
+ // We will fill the return value in with reasonable values for those
+ // apps (micrographx draw) that ignore our return values.
+ // we still return failure.
+
+ switch (INT32(parg16->f2))
+ {
+ case GETPHYSPAGESIZE:
+ pt.x = GetDeviceCaps(HDC32(parg16->f1),HORZRES);
+ pt.y = GetDeviceCaps(HDC32(parg16->f1),VERTRES);
+ break;
+
+ case GETPRINTINGOFFSET:
+ pt.x = 0;
+ pt.y = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ PUTPOINT16(parg16->f5, &pt);
+ }
+ break;
+
+ case GETCOLORTABLE:
+ {
+ PDWORD pdw;
+ DWORD dw;
+ INT i;
+
+ if (pin) {
+ i = (INT) FETCHSHORT(*(PSHORT)pin);
+ } else {
+ ul = (ULONG)-1;
+ break;
+ }
+
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ sizeof(INT),
+ (LPCSTR)&i,
+ &dw));
+
+ GETVDMPTR(parg16->f5, sizeof(DWORD), pdw);
+ STOREDWORD ((*pdw), dw);
+ FREEVDMPTR(pdw);
+ }
+ break;
+
+ case NEXTBAND:
+ { RECT rt;
+
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ pin,
+ (LPSTR)&rt));
+
+ PUTRECT16(parg16->f5, &rt);
+ }
+ break;
+
+ case QUERYESCSUPPORT:
+ {
+ INT i;
+
+ i = (INT) FETCHWORD((*(PWORD)pin));
+
+ switch (i) {
+
+ // For Escapes return FALSE for MGX Draw and TRUE for all other apps.
+ // ChandanC, 27/5/93.
+ //
+ case OPENCHANNEL: // 4110
+ case DOWNLOADHEADER: // 4111
+ case CLOSECHANNEL: // 4112
+ case SETGDIXFORM: // 4113
+ case RESETPAGE: // 4114
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ }
+ else {
+ ul = 1;
+ }
+ break;
+
+
+ case POSTSCRIPT_PASSTHROUGH: // 4115
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ }
+ else {
+ LOGDEBUG(3,("Querying support for escape %x\n",i));
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ sizeof(int),
+ (PVOID)&i,
+ NULL));
+ }
+ break;
+
+
+ case ENCAPSULATED_POSTSCRIPT: // 4116
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ }
+ else {
+ LOGDEBUG(3,("Querying support for escape %x\n",i));
+ ul = GETINT16(DrawEscape (HDC32(parg16->f1),
+ INT32(parg16->f2),
+ sizeof(int),
+ (PVOID)&i));
+ }
+ break;
+
+ case GETEXTENDEDTEXTMETRICS:
+ case GETPAIRKERNTABLE:
+ case FLUSHOUTPUT:
+ ul = 1;
+ break;
+
+
+ case SETCOPYCOUNT:
+ case GETCOLORTABLE:
+ case GETPHYSPAGESIZE:
+ case GETPRINTINGOFFSET:
+ case GETSCALINGFACTOR:
+ case NEXTBAND:
+ case SETABORTPROC:
+ case BEGIN_PATH:
+ case END_PATH:
+ case CLIP_TO_PATH:
+ LOGDEBUG(3,("Querying support for escape %x\n",i));
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ sizeof(int),
+ (PVOID)&i,
+ NULL));
+ break;
+
+
+
+ case POSTSCRIPT_DATA:
+ case POSTSCRIPT_IGNORE:
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ }
+ else {
+ LOGDEBUG(3,("Querying support for escape %x\n",i));
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ sizeof(int),
+ (PVOID)&i,
+ NULL));
+ }
+ break;
+
+ case GETTECHNOLOGY:
+ case PASSTHROUGH:
+ case DOWNLOADFACE:
+ case GETFACENAME:
+ case GETDEVICEUNITS:
+ case EPSPRINTING:
+ LOGDEBUG(3,("Querying support for escape %x\n",i));
+ ul = GETINT16(ExtEscape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ sizeof(int),
+ (PVOID)&i,
+ 0,
+ NULL));
+ break;
+
+ default:
+ LOGDEBUG(3,("Querying support for escape %x\n",i));
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ sizeof(int),
+ (PVOID)&i,
+ NULL));
+ break;
+ }
+
+ }
+ break;
+
+
+ case SETABORTPROC:
+ ((PTDB)SEGPTR(pFrame->wTDB, 0))->TDB_vpfnAbortProc =
+ FETCHDWORD(parg16->f4);
+
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ 0,
+ (LPCSTR)W32AbortProc,
+ NULL));
+
+ break;
+
+
+ case GETDEVICEUNITS:
+ {
+ PVOID pout;
+ LONG out[4];
+
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ 0,
+ NULL,
+ (LPSTR)out));
+
+ if (ul == 1) {
+ GETOPTPTR(parg16->f5, 0, pout);
+ RtlCopyMemory(pout, out, sizeof(out));
+ FREEOPTPTR(pout);
+ }
+
+ }
+ break;
+
+
+ case GETPAIRKERNTABLE:
+ {
+ PVOID pout;
+ GETOPTPTR(parg16->f5, 0, pout);
+
+ ul = GETINT16(iGetKerningPairsEsc32(
+ HDC32(parg16->f1),
+ (ESCKERNPAIR*) pout));
+
+ FREEOPTPTR(pout);
+ }
+ break;
+
+ case GETEXTENDEDTEXTMETRICS:
+ {
+ PVOID pout;
+ EXTTEXTMETRIC etm;
+
+ if ( (ul = GETINT16(GetETM(HDC32(parg16->f1),
+ &etm))) != 0 )
+ {
+ GETOPTPTR(parg16->f5, 0, pout);
+ RtlCopyMemory(pout, &etm, sizeof(EXTTEXTMETRIC));
+ FREEOPTPTR(pout);
+ }
+ }
+ break;
+
+ case OPENCHANNEL: // 4110
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+
+ ul = 0;
+
+ } else {
+
+ DOCINFO16 *pout;
+ DOCINFO DocInfo;
+
+ DocInfo.cbSize = sizeof(DocInfo);
+ DocInfo.lpszDatatype = "RAW";
+ DocInfo.fwType = 0;
+
+
+ GETOPTPTR(parg16->f5, 0, pout);
+
+ if (pout) {
+
+ GETOPTPTR(pout->lpszDocName, 0, DocInfo.lpszDocName);
+ GETOPTPTR(pout->lpszOutput, 0, DocInfo.lpszOutput);
+
+ ul = StartDoc(HDC32(parg16->f1), &DocInfo);
+
+ FREEOPTPTR(DocInfo.lpszDocName);
+ FREEOPTPTR(DocInfo.lpszOutput);
+
+ } else {
+
+ //
+ // Fifth parameter null, use old (startdoc) format
+ //
+
+ GETOPTPTR(parg16->f4, 0, DocInfo.lpszDocName);
+ DocInfo.lpszOutput = NULL;
+
+ ul = StartDoc(HDC32(parg16->f1), &DocInfo);
+
+ FREEOPTPTR(DocInfo.lpszDocName);
+
+ }
+
+ FREEOPTPTR(pout);
+ }
+ break;
+
+
+ case DOWNLOADHEADER: // 4111
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ }
+ else {
+ PBYTE pout;
+ char ach[64];
+
+ GETOPTPTR(parg16->f5, 0, pout);
+
+ if (pout) {
+ ul = GETINT16(ExtEscape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ 0,
+ NULL,
+ sizeof(ach),
+ ach));
+
+ strcpy (pout, ach);
+ }
+ else {
+ ul = GETINT16(ExtEscape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ 0,
+ NULL,
+ 0,
+ NULL));
+
+ }
+
+
+ FREEOPTPTR(pout);
+ }
+ break;
+
+
+ case CLOSECHANNEL: // 4112
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ }
+ else {
+
+ // send any buffered data streams to the printer before EndDoc
+ if(CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_FORMFEEDHACK) {
+ SendFormFeedHack(HDC32(parg16->f1));
+ }
+
+ ul = EndDoc(HDC32(parg16->f1));
+ }
+ break;
+
+
+
+ // This Escape is defined for PageMaker. It is SETGDIXFORM.
+ // ChandanC, 24/5/93.
+ //
+ case SETGDIXFORM: // 4113
+ case RESETPAGE: // 4114
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ }
+ else {
+ ul = 1;
+ }
+ break;
+
+
+ case POSTSCRIPT_PASSTHROUGH: // 4115
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ }
+ else {
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ (FETCHWORD(*(PWORD)pin) + 2),
+ (LPCSTR)pin,
+ NULL));
+ }
+ break;
+
+
+ case ENCAPSULATED_POSTSCRIPT: // 4116
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ }
+ else {
+ DWORD cb;
+ PVOID lpInData32 = NULL;
+
+ lpInData32 = pin;
+ cb = FETCHDWORD (*(PDWORD) pin);
+
+ if ((DWORD) pin & 3) {
+ if (lpInData32 = (PVOID) malloc_w (cb)) {
+ RtlCopyMemory(lpInData32, pin, cb);
+ }
+ else {
+ ul = 0;
+ break;
+ }
+ }
+
+ ul = GETINT16(DrawEscape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ cb,
+ lpInData32));
+
+ if (((DWORD) pin & 3) && (lpInData32)) {
+ free_w (lpInData32);
+ }
+
+ }
+ break;
+
+
+ case POSTSCRIPT_DATA:
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ LOGDEBUG (LOG_ALWAYS, ("MicroGraphax app using POSTSCRIPT_DATA, contact PingW/ChandanC\n"));
+ WOW32ASSERT(FALSE);
+ }
+ else {
+ //
+ // XPress needs IGNORESTARTPAGE escape.
+ // PingW, ChandanC 3/22/94
+ //
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_NEEDIGNORESTARTPAGE) {
+ int l;
+ char szBuf[40];
+
+ if ((l = ExtEscape(HDC32(parg16->f1),
+ GETTECHNOLOGY,
+ 0,
+ NULL,
+ sizeof(szBuf),
+ szBuf)) > 0) {
+
+ if (!_stricmp(szBuf, szPostscript)) {
+ l = ExtEscape(HDC32(parg16->f1),
+ IGNORESTARTPGAE,
+ 0,
+ NULL,
+ 0,
+ NULL);
+ }
+ }
+ }
+
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ (FETCHWORD(*(PWORD)pin) + 2),
+ (LPCSTR)pin,
+ NULL));
+ }
+ break;
+
+ case POSTSCRIPT_IGNORE:
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_MGX_ESCAPES) {
+ ul = 0;
+ LOGDEBUG (LOG_ALWAYS, ("MicroGraphax app using POSTSCRIPT_IGNORE, contact PingW/ChandanC\n"));
+ WOW32ASSERT(FALSE);
+ }
+ else {
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ (LPCSTR)pin,
+ NULL));
+ }
+ break;
+
+ case BEGIN_PATH:
+ // Some apps set the empty clip region before doing the path escapes,
+ // We need to undo that so the drawing APIs between begin and endpath
+ // go through to drivers.
+
+ SelectClipRgn(HDC32(parg16->f1),NULL);
+
+ case END_PATH:
+ case CLIP_TO_PATH:
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ (LPCSTR)pin,
+ NULL));
+ break;
+
+ case PASSTHROUGH:
+
+ // if this is a form feed hack app...
+ if(CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_FORMFEEDHACK) {
+
+ ul = HandleFormFeedHack(HDC32(parg16->f1),
+ pin,
+ FETCHWORD(*(PWORD)pin)); // cb only
+ }
+
+ else {
+
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ (FETCHWORD(*(PWORD)pin) + 2),
+ (LPCSTR)pin,
+ NULL));
+ }
+ break;
+
+
+ case FLUSHOUTPUT:
+ ul = TRUE;
+ break;
+
+
+ case DOWNLOADFACE:
+ {
+ WORD InData;
+ PWORD lpInData = NULL;
+
+ // PM5 forgot to set there map mode so we do it.
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_FORCETWIPSESCAPE)
+ iMapMode = SetMapMode(HDC32(parg16->f1),MM_TWIPS);
+
+ if (pin) {
+ InData = FETCHWORD(*(PWORD)pin);
+ lpInData = &InData;
+ }
+
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ sizeof(USHORT),
+ (LPCSTR)lpInData,
+ NULL));
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_FORCETWIPSESCAPE)
+ SetMapMode(HDC32(parg16->f1),iMapMode);
+ }
+ break;
+
+ case GETFACENAME:
+ {
+ PSZ pout;
+ CHAR ach[60];
+
+ // PM5 forgot to set there map mode so we do it.
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_FORCETWIPSESCAPE)
+ iMapMode = SetMapMode(HDC32(parg16->f1),MM_TWIPS);
+
+ GETOPTPTR(parg16->f5, 0, pout);
+
+
+ // This HACK is for FH4.0 only. If you have any questions
+ // talk to PingW or ChandanC.
+ // July 21st 1994.
+ //
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_ADD_MSTT) {
+
+ ExtEscape(HDC32(parg16->f1),
+ ADD_MSTT,
+ 0,
+ NULL,
+ 60,
+ ach);
+ }
+
+ // pass in 60 as a magic number. Just copy out the valid string.
+
+ ul = GETINT16(ExtEscape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ pin,
+ 60,
+ ach));
+
+ strcpy (pout, ach);
+
+ FREEOPTPTR(pout);
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_FORCETWIPSESCAPE)
+ SetMapMode(HDC32(parg16->f1),iMapMode);
+ }
+ break;
+
+ case EPSPRINTING:
+ {
+ WORD InData;
+ PWORD lpInData = NULL;
+
+ if (pin)
+ {
+ InData = FETCHWORD(*(PWORD)pin);
+ lpInData = &InData;
+ }
+
+ ul = GETINT16(ExtEscape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ sizeof(BOOL),
+ (LPCSTR)lpInData,
+ 0,
+ NULL));
+ }
+ break;
+
+ case GETTECHNOLOGY:
+ {
+ PVOID pout;
+
+ buf[0] = '\0';
+
+ GETOPTPTR(parg16->f5, 0, pout);
+
+ if (!(CURRENTPTD()->dwWOWCompatFlags & WOWCF_FORCENOPOSTSCRIPT))
+ {
+ ul = GETINT16(ExtEscape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ pin,
+ sizeof(buf),
+ buf));
+ }
+
+ if (pout)
+ strcpy (pout, buf);
+
+ FREEOPTPTR(pout);
+ }
+ break;
+
+ case SETCOPYCOUNT:
+ {
+ int cCopiesOut, cCopiesIn=1;
+
+ if (pin)
+ cCopiesIn = *(UNALIGNED SHORT *)pin;
+
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ pin ? sizeof(cCopiesIn) : 0,
+ pin ? &cCopiesIn : pin,
+ parg16->f5 ? &cCopiesOut : NULL));
+
+ if ( parg16->f5 ) {
+ if ( (INT)ul > 0 ) {
+ PUTINT16(parg16->f5, cCopiesOut);
+ } else {
+ // Pagemaker v4 needs the output value
+ PUTINT16(parg16->f5, 1);
+ }
+ }
+ }
+ break;
+
+ case STARTDOC:
+ {
+ PVOID pout;
+
+ GETOPTPTR(parg16->f5, 0, pout);
+
+ //
+ // Win32 StartDoc depends on having the correct current directory
+ // when printing to FILE: (which pops up for a filename).
+ //
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ pin,
+ pout));
+
+ //
+ // PhotoShop needs a StartPage when it does StartDoc Escape.
+ // PingW, ChandanC 3/22/94
+ //
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_NEEDSTARTPAGE) {
+ int l;
+ char szBuf[80];
+
+ //
+ // It should be done ONLY for POSTSCRIPT drivers
+ //
+ if ((l = ExtEscape(HDC32(parg16->f1),
+ GETTECHNOLOGY,
+ 0,
+ NULL,
+ sizeof(szBuf),
+ szBuf)) > 0) {
+
+ if (!_stricmp(szBuf, szPostscript)) {
+ l = StartPage(HDC32(parg16->f1));
+ }
+ }
+ }
+
+ FREEOPTPTR(pout);
+ }
+ break;
+
+
+ default:
+ {
+ PVOID pout;
+
+ GETOPTPTR(parg16->f5, 0, pout);
+
+ ul = GETINT16(Escape(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ pin,
+ pout));
+
+ FREEOPTPTR(pout);
+ }
+ break;
+
+ } // end switch
+
+ FREEOPTPTR(pin);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+ULONG FASTCALL WG32ExcludeClipRect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PEXCLUDECLIPRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(EXCLUDECLIPRECT16), parg16);
+
+ ul = GETINT16(ExcludeClipRect(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32ExtFloodFill(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PEXTFLOODFILL16 parg16;
+
+ GETARGPTR(pFrame, sizeof(EXTFLOODFILL16), parg16);
+
+ ul = GETBOOL16(ExtFloodFill(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ DWORD32(parg16->f4),
+ WORD32(parg16->f5)));
+
+ WOW32APIWARN (ul, "ExtFloodFill");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32FillRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PFILLRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(FILLRGN16), parg16);
+
+ ul = GETBOOL16(FillRgn(HDC32(parg16->f1),
+ HRGN32(parg16->f2),
+ HBRUSH32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32FloodFill(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PFLOODFILL16 parg16;
+
+ GETARGPTR(pFrame, sizeof(FLOODFILL16), parg16);
+
+ ul = GETBOOL16(FloodFill(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ DWORD32(parg16->f4)));
+
+ WOW32APIWARN (ul, "FloodFill");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32FrameRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PFRAMERGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(FRAMERGN16), parg16);
+
+ ul = GETBOOL16(FrameRgn(HDC32(parg16->f1),
+ HRGN32(parg16->f2),
+ HBRUSH32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+#if 0
+// there's no thunk for this routine
+ULONG FASTCALL WG32GdiFlush(PVDMFRAME pFrame)
+{
+ GdiFlush();
+
+ RETURN(0);
+
+ pFrame;
+}
+#endif
+
+ULONG FASTCALL WG32GetBitmapBits(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PBYTE pb3;
+ register PGETBITMAPBITS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETBITMAPBITS16), parg16);
+
+ ALLOCVDMPTR(parg16->f3, (INT)parg16->f2, pb3);
+
+ ul = GETLONG16(GetBitmapBits(HBITMAP32(parg16->f1),
+ LONG32(parg16->f2),
+ pb3));
+
+ WOW32APIWARN (ul, "GetBitmapBits");
+
+ FLUSHVDMPTR(parg16->f3, (INT)parg16->f2, pb3);
+ FREEVDMPTR(pb3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetBitmapDimension(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE size2;
+ register PGETBITMAPDIMENSION16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETBITMAPDIMENSION16), parg16);
+
+ ul = 0;
+ if (GetBitmapDimensionEx(HBITMAP32(parg16->f1), &size2)) {
+ ul = (WORD)size2.cx | (size2.cy << 16);
+ }
+ else {
+ WOW32APIWARN (ul, "GetBitmapBits");
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetBkColor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETBKCOLOR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETBKCOLOR16), parg16);
+
+ ul = GETDWORD16(GetBkColor(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetBkMode(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETBKMODE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETBKMODE16), parg16);
+
+ ul = GETINT16(GetBkMode(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetBrushOrg(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ POINT pt2;
+ register PGETBRUSHORG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETBRUSHORG16), parg16);
+
+// for windows compatability, we must first add the DCorg
+// since windows brushorg is relative to the screen where as NT
+// is relative to the window. In the future, this should call
+// a private gdi entry point to avoid an extra c/s hit. (erick)
+
+ ul = 0;
+ if (GetDCOrgEx(HDC32(parg16->f1),&pt))
+ {
+ if (GetBrushOrgEx(HDC32(parg16->f1), &pt2)) {
+ ul = (WORD)(pt2.x + pt.x) | ((pt2.y + pt.y) << 16);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetClipBox(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t2;
+ register PGETCLIPBOX16 parg16;
+ HDC hdc;
+
+ GETARGPTR(pFrame, sizeof(GETCLIPBOX16), parg16);
+
+ hdc = HDC32(parg16->f1);
+
+ ul = GETINT16(GetClipBox(hdc,&t2));
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_SIMPLEREGION)
+ ul = SIMPLEREGION;
+
+ PUTRECT16(parg16->f2, &t2);
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetCurrentPosition(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ register PGETCURRENTPOSITION16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCURRENTPOSITION16), parg16);
+
+ ul = 0;
+ if (GetCurrentPositionEx(HDC32(parg16->f1), &pt)) {
+ ul = (WORD)pt.x | (pt.y << 16);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetDCOrg(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ register PGETDCORG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETDCORG16), parg16);
+
+ ul = 0;
+ if ( GetDCOrgEx(HDC32(parg16->f1),&pt) ) {
+ ul = (WORD)pt.x | (pt.y << 16);
+ }
+
+ LOGDEBUG(6,("GetDCOrg for hdc %x returns %lx\n",parg16->f1,ul));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+// PowerPoint 2&3 call this 2 times for each slide in the slide previewer
+// the lpvBits == NULL on the first call (presumably to find the size to
+// allocate) -- in which case Win3.x returns 1
+ULONG FASTCALL WG32GetDIBits(PVDMFRAME pFrame)
+{
+ INT nbmiSize;
+ ULONG ul = 0L;
+ PBYTE pb5;
+ PBYTE pb6;
+ STACKBMI32 bmi32;
+ LPBITMAPINFO lpbmi32;
+ register PGETDIBITS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETDIBITS16), parg16);
+ GETMISCPTR(parg16->f5, pb5);
+ GETMISCPTR(parg16->f6, pb6);
+
+ // copy just the BITMAPINFOHEADER portion of the BITMAPINFO struct
+ if(lpbmi32=(LPBITMAPINFO)CopyBMIH16ToBMIH32((PVPVOID)FETCHDWORD(parg16->f6),
+ (LPBITMAPINFOHEADER)&bmi32)) {
+
+ // gdi32 will adjust key fields of the BITMAPINFOHEADER & copy the
+ // color table into the 32-bit BITMAPINFO struct
+ if( ul = GETINT16(GetDIBits(HDC32(parg16->f1),
+ HBITMAP32(parg16->f2),
+ WORD32(parg16->f3),
+ WORD32(parg16->f4),
+ pb5,
+ lpbmi32,
+ WORD32(parg16->f7))) ) {
+
+ // if lpvBits, then they want the bits of the bitmap too
+ if(pb5) {
+ ul = WORD32(parg16->f4); // return # scanlines requested
+ FLUSHVDMPTR(parg16->f5, SIZE_BOGUS, pb5);
+ }
+ // else tell app that BITMAPINFO structure filled in only
+ else {
+ ul = 1L;
+ }
+
+ // copy the updated BITMAPINFO struct back into the 16-bit version
+ nbmiSize = GetBMI32Size(lpbmi32, WORD32(parg16->f7));
+ RtlCopyMemory(pb6, lpbmi32, nbmiSize);
+
+ FLUSHVDMPTR(parg16->f6, nbmiSize, pb6);
+ }
+ }
+
+ FREEMISCPTR(pb5);
+ FREEMISCPTR(pb6);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WG32GetDeviceCaps(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETDEVICECAPS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETDEVICECAPS16), parg16);
+
+ if (INT32(parg16->f2) == COLORRES) {
+ ul = 18;
+ }
+ else {
+ ul = GetDeviceCaps(HDC32(parg16->f1), INT32(parg16->f2));
+
+ if (ul == (ULONG)-1) {
+ switch (parg16->f2) {
+ case NUMBRUSHES:
+ case NUMPENS:
+ case NUMCOLORS:
+ ul = 2048;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // if the 4plane conversion flag is set, tell them we are 4 planes 1bpp
+ // instead of 1plane 4bpp.
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_4PLANECONVERSION) {
+ if (INT32(parg16->f2) == BITSPIXEL) {
+ if ((ul == 4) && (GetDeviceCaps(HDC32(parg16->f1),PLANES) == 1))
+ ul = 1;
+ }
+ else if (INT32(parg16->f2) == PLANES) {
+ if ((ul == 1) && (GetDeviceCaps(HDC32(parg16->f1),BITSPIXEL) == 4))
+ ul = 4;
+ }
+ }
+ if ( (POLYGONALCAPS == parg16->f2) && (CURRENTPTD()->dwWOWCompatFlags & WOWCF_NOPC_RECTANGLE)) {
+ ul &= !PC_RECTANGLE; // Quattro Pro 1.0 for Windows doesn't handle this bit well.
+ }
+ }
+
+ ul = GETINT16(ul);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetEnvironment(PVDMFRAME pFrame)
+{
+ // not a Win32 function
+
+ //
+ // if lpEnviron==NULL then the user is querying the size of device
+ // data. WinProj doesn't check the return value, calling the driver
+ // with an undersized buffer, trashing the global heap.
+ // WinFax passes a hard coded 0xA9 == 0x44+0x69 == sizeof(win3.0 DevMode) +
+ // known WinFax.DRV->dmDriverExtra. Beware also that WinFax calls this
+ // whenever an app calls any API that requires a DevMode.
+
+
+ ULONG ul=0;
+ register PGETENVIRONMENT16 parg16;
+ PSZ psz;
+ PSZ psz1 = NULL;
+ VPDEVMODE31 vpdm2;
+ CHAR szDriver[40];
+ UINT cbT = 0;
+ WORD nMaxBytes;
+
+ GETARGPTR(pFrame, sizeof(GETENVIRONMENT16), parg16);
+
+ // save off the 16-bit params now since this could callback into a 16-bit
+ // fax driver & cause 16-bit memory to move.
+ GETPSZPTR(parg16->f1, psz);
+ if(psz) {
+ psz1 = malloc_w(lstrlen(psz)+1);
+ if(psz1) {
+ lstrcpy(psz1, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+ vpdm2 = FETCHDWORD(parg16->f2);
+
+ nMaxBytes = FETCHWORD(parg16->f3);
+
+ FREEARGPTR(parg16);
+ // invalidate all flat ptrs to 16:16 memory now
+
+ if (!(*spoolerapis[WOW_EXTDEVICEMODE].lpfn)) {
+ if (!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
+ return (0);
+ }
+ }
+
+ // get required size for output buffer
+ // When WinFax calls this api, calls to GetDriverName for szDriver ==
+ // "FaxModem" seem to fail -- this is a good thing if the app called
+ // ExtDeviceMode() because we would get into an infinite loop here. WinFax
+ // just fills in a DevMode with default values if this api fails.
+ if (GetDriverName(psz1, szDriver)) {
+ ul = (*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(NULL,
+ NULL,
+ NULL,
+ szDriver,
+ psz1,
+ NULL,
+ NULL,
+ 0);
+ LOGDEBUG(6,("WOW::GetEnvironment returning ul = %d, for Device = %s, Port = %s \n", ul, szDriver, psz1));
+
+ // adjust the size for our DEVMODE handling (see note in wstruc.c)
+ // (it won't hurt to allocate too much)
+ if(ul) {
+ ul += sizeof(WOWDM31);
+ cbT = (UINT)ul;
+ }
+
+ // if they also want us to fill in their environment structure...
+ if ((vpdm2 != 0) && (ul != 0)) {
+ LPDEVMODE lpdmOutput;
+
+ if (lpdmOutput = malloc_w(ul)) {
+
+ // this might be calling into a 16-bit fax driver!!
+ ul = (*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(NULL,
+ NULL,
+ lpdmOutput,
+ szDriver,
+ psz1,
+ NULL,
+ NULL,
+ DM_OUT_BUFFER);
+
+ // if a WinFax call to GetDriverName() succeeds & gets to here
+ // we may need to hack on the lpdmOutput->dmSize==0x40
+ // (Win3.0 size) to account for the hard coded buffer size of
+ // 0xa9 the app passes. So far I haven't seen WinFax get past
+ // GetDriverName() call & it still seems to work OK.
+ if (ul > 0L) {
+ // Use the min of nMaxBytes & what we calculated
+ ThunkDevMode32to16(vpdm2, lpdmOutput, min(nMaxBytes, cbT));
+ }
+
+ free_w(lpdmOutput);
+
+ LOGDEBUG(6,("WOW::GetEnvironment getting DEVMODE structure, ul = %d, for Device = %s, Port = %s \n", ul, szDriver, psz1));
+ }
+ }
+ }
+
+ free_w(psz1);
+
+ RETURN(ul);
+
+}
+
+
+
+ULONG FASTCALL WG32GetMapMode(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETMAPMODE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETMAPMODE16), parg16);
+
+ ul = GETINT16(GetMapMode(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetNearestColor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETNEARESTCOLOR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETNEARESTCOLOR16), parg16);
+
+ ul = GETDWORD16(GetNearestColor(HDC32(parg16->f1), DWORD32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetObject(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ HANDLE hgdi;
+ register PGETOBJECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETOBJECT16), parg16);
+
+ hgdi = HOBJ32(parg16->f1);
+
+ switch (GetObjectType(hgdi)) {
+ case OBJ_BITMAP:
+ {
+ BITMAP bm;
+ ul = GETINT16(GetObject(hgdi, sizeof(BITMAP), (LPSTR)&bm));
+ if (ul) {
+ PUTBITMAP16(parg16->f3, parg16->f2, &bm);
+ if ( ul > sizeof(BITMAP16) ) {
+ ul = sizeof(BITMAP16);
+ }
+ }
+ }
+ break;
+
+ case OBJ_BRUSH:
+ {
+ LOGBRUSH lb;
+ ul = GETINT16(GetObject(hgdi, sizeof(LOGBRUSH), (LPSTR)&lb));
+ if (ul) {
+ PUTLOGBRUSH16(parg16->f3, parg16->f2, &lb);
+ if (ul > sizeof(LOGBRUSH16)) {
+ ul = sizeof(LOGBRUSH16);
+ }
+ }
+ }
+ break;
+
+ case OBJ_PEN:
+ {
+ LOGPEN lp;
+ ul = GETINT16(GetObject(hgdi, sizeof(LOGPEN), (LPSTR)&lp));
+ if (ul) {
+ PUTLOGPEN16(parg16->f3, parg16->f2, &lp);
+ if (ul > sizeof(LOGPEN16)) {
+ ul = sizeof(LOGPEN16);
+ }
+ }
+ }
+ break;
+
+ case OBJ_FONT:
+ {
+ LOGFONT lf;
+ ul = GETINT16(GetObject(hgdi, sizeof(LOGFONT), (LPSTR)&lf));
+ if (ul) {
+ PUTLOGFONT16(parg16->f3, parg16->f2, &lf);
+ if (ul > sizeof(LOGFONT16)) {
+ ul = sizeof(LOGFONT16);
+ }
+ }
+ }
+ break;
+
+ case OBJ_PAL:
+ {
+ PSHORT16 lpT;
+ SHORT sT;
+
+ ul = GETINT16(GetObject(hgdi, sizeof(SHORT), (LPSTR)&sT));
+ if (ul && (FETCHWORD(parg16->f2) >= sizeof(WORD))) {
+ GETVDMPTR(FETCHDWORD(parg16->f3), sizeof(WORD), lpT);
+ if (lpT) {
+ STOREWORD(lpT[0], sT);
+ }
+ FREEVDMPTR(lpT);
+ }
+ }
+ break;
+
+
+ default:
+ {
+ PBYTE pb3;
+
+ LOGDEBUG(LOG_ALWAYS,(" HACK: GetObject handle unknown, contact ChandanC\n"));
+
+ GETVDMPTR(parg16->f3, parg16->f2, pb3);
+
+ ul = GETINT16(GetObject(hgdi, INT32(parg16->f2), pb3));
+
+ FLUSHVDMPTR(parg16->f3, parg16->f2, pb3);
+ FREEVDMPTR(pb3);
+ }
+
+ } // switch
+
+ WOW32APIWARN(ul, "GetObject");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetPixel(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETPIXEL16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETPIXEL16), parg16);
+
+ ul = GETDWORD16(GetPixel(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3)));
+
+ if (ul == CLR_INVALID) {
+ LOGDEBUG(6,("GetPixel : Pixel outside of clipping region\n"));
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetPolyFillMode(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETPOLYFILLMODE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETPOLYFILLMODE16), parg16);
+
+ ul = GETINT16(GetPolyFillMode(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetROP2(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETROP216 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETROP216), parg16);
+
+ ul = GETINT16(GetROP2(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetRgnBox(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t2;
+ register PGETRGNBOX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETRGNBOX16), parg16);
+
+ ul = GETINT16(GetRgnBox(HRGN32(parg16->f1), &t2));
+
+ PUTRECT16(parg16->f2, &t2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetStockObject(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETSTOCKOBJECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETSTOCKOBJECT16), parg16);
+
+ ul = GETHOBJ16(GetStockObject(INT32(parg16->f1)));
+
+ WOW32APIWARN(ul, "GetStockObject");
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetStretchBltMode(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETSTRETCHBLTMODE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETSTRETCHBLTMODE16), parg16);
+
+ ul = GETINT16(GetStretchBltMode(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetViewportExt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE size;
+ register PGETVIEWPORTEXT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETVIEWPORTEXT16), parg16);
+
+ ul = 0;
+ if (GetViewportExtEx(HDC32(parg16->f1), &size)) {
+
+ //
+ // win31 returns 1 rather than 0 unless there was an error
+ //
+
+ if (!(ul = (WORD)size.cx | (size.cy << 16)))
+ ul = 1;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetViewportOrg(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ register PGETVIEWPORTORG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETVIEWPORTORG16), parg16);
+
+ ul = 0;
+ if (GetViewportOrgEx(HDC32(parg16->f1), &pt)) {
+ ul = (WORD)pt.x | (pt.y << 16);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetWindowExt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE size;
+ register PGETWINDOWEXT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWEXT16), parg16);
+
+ ul = 0;
+ if (GetWindowExtEx(HDC32(parg16->f1), &size)) {
+ if (!(ul = (WORD)size.cx | (size.cy << 16))) // see above
+ ul = 1;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetWindowOrg(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ register PGETWINDOWORG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWORG16), parg16);
+
+ ul = 0;
+ if (GetWindowOrgEx(HDC32(parg16->f1), &pt)) {
+ ul = (WORD)pt.x | (pt.y << 16);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32IntersectClipRect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PINTERSECTCLIPRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(INTERSECTCLIPRECT16), parg16);
+
+ ul = GETINT16(IntersectClipRect(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32InvertRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PINVERTRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(INVERTRGN16), parg16);
+
+ ul = GETBOOL16(InvertRgn(HDC32(parg16->f1), HRGN32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32LPtoDP(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPPOINT t2;
+ register PLPTODP16 parg16;
+ POINT BufferT[128];
+
+ GETARGPTR(pFrame, sizeof(LPTODP16), parg16);
+ t2 = STACKORHEAPALLOC(parg16->f3 * sizeof(POINT), sizeof(BufferT), BufferT);
+ getpoint16(parg16->f2, parg16->f3, t2);
+
+ ul = GETBOOL16(LPtoDP(HDC32(parg16->f1), t2, INT32(parg16->f3)));
+
+ PUTPOINTARRAY16(parg16->f2, parg16->f3, t2);
+
+ STACKORHEAPFREE(t2, BufferT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+void W32LineDDAFunc(int x, int y, PLINEDDADATA pDDAData)
+{
+ PARM16 Parm16;
+
+ WOW32ASSERT(pDDAData);
+ Parm16.LineDDAProc.vpData = (VPVOID)pDDAData->dwUserDDAParam;
+ Parm16.LineDDAProc.x = (SHORT)x;
+ Parm16.LineDDAProc.y = (SHORT)y;
+ Parm16.LineDDAProc.vpData = (VPVOID)pDDAData->dwUserDDAParam;
+ CallBack16(RET_LINEDDAPROC, &Parm16, pDDAData->vpfnLineDDAProc, NULL);
+
+ return;
+}
+
+ULONG FASTCALL WG32LineDDA(PVDMFRAME pFrame)
+{
+ LINEDDADATA DDAData;
+ register PLINEDDA16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LINEDDA16), parg16);
+
+ DDAData.vpfnLineDDAProc = DWORD32(parg16->f5);
+ DDAData.dwUserDDAParam = DWORD32(parg16->f6);
+
+ LineDDA(INT32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ (LINEDDAPROC)W32LineDDAFunc,
+ (LPARAM)&DDAData);
+ // 16-bit memory may have moved - invalidate flat pointers now
+ FREEVDMPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ RETURN(1L);
+}
+
+
+ULONG FASTCALL WG32LineTo(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLINETO16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LINETO16), parg16);
+
+ ul = GETBOOL16(LineTo(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32MoveTo(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ register PMOVETO16 parg16;
+
+ GETARGPTR(pFrame, sizeof(MOVETO16), parg16);
+
+ ul = 0;
+ pt.x = 1L; // see "METAFILE NOTE"
+ pt.y = 0L;
+ if (MoveToEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ &pt)) {
+
+ ul = (WORD)pt.x | (pt.y << 16);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32MulDiv(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PMULDIV16 parg16;
+
+ GETARGPTR(pFrame, sizeof(MULDIV16), parg16);
+
+ ul = GETINT16(MulDiv(INT32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32OffsetClipRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register POFFSETCLIPRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OFFSETCLIPRGN16), parg16);
+
+ ul = GETINT16(OffsetClipRgn(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32OffsetRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register POFFSETRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OFFSETRGN16), parg16);
+
+ ul = GETINT16(OffsetRgn(HRGN32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32OffsetViewportOrg(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ register POFFSETVIEWPORTORG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OFFSETVIEWPORTORG16), parg16);
+
+ ul = 0;
+ pt.x = 1L; // see "METAFILE NOTE"
+ pt.y = 0L;
+ if (OffsetViewportOrgEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ &pt)) {
+
+ ul = (WORD)pt.x | (pt.y << 16);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32OffsetWindowOrg(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ register POFFSETWINDOWORG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OFFSETWINDOWORG16), parg16);
+
+ ul = 0;
+ pt.x = 1L; // see "METAFILE NOTE"
+ pt.y = 0L;
+ if (OffsetWindowOrgEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ &pt)) {
+
+ ul = (WORD)pt.x | (pt.y << 16);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32PaintRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PPAINTRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(PAINTRGN16), parg16);
+
+ ul = GETBOOL16(PaintRgn(HDC32(parg16->f1), HRGN32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32PatBlt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PPATBLT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(PATBLT16), parg16);
+
+ ul = GETBOOL16(PatBlt(HDC32(parg16->hdc),
+ INT32(parg16->x),
+ INT32(parg16->y),
+ INT32(parg16->nWidth),
+ INT32(parg16->nHeight),
+ DWORD32(parg16->dwRop)));
+
+ WOW32APIWARN(ul, "PatBlt");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32Pie(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PPIE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(PIE16), parg16);
+
+ ul = GETBOOL16(Pie(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ INT32(parg16->f6),
+ INT32(parg16->f7),
+ INT32(parg16->f8),
+ INT32(parg16->f9)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32PolyPolygon(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPPOINT pPoints;
+ PINT pPolyCnt;
+ UINT cpts = 0;
+ INT ii;
+ register PPOLYPOLYGON16 parg16;
+ INT cInt16;
+ INT BufferT[256]; // comfortably large array
+
+
+ GETARGPTR(pFrame, sizeof(POLYPOLYGON16), parg16);
+
+ cInt16 = INT32(parg16->f4);
+ pPolyCnt = STACKORHEAPALLOC(cInt16 * sizeof(INT), sizeof(BufferT), BufferT);
+ if (!pPolyCnt) {
+ FREEARGPTR(parg16);
+ RETURN(0);
+ }
+
+ getintarray16(parg16->f3, cInt16, pPolyCnt);
+
+ for (ii=0; ii < cInt16; ii++)
+ cpts += pPolyCnt[ii];
+
+ pPoints = STACKORHEAPALLOC(cpts * sizeof(POINT),
+ sizeof(BufferT) - cInt16 * sizeof(INT),
+ BufferT + cInt16);
+ getpoint16(parg16->f2, cpts, pPoints);
+
+ ul = GETBOOL16(PolyPolygon(HDC32(parg16->f1),
+ pPoints,
+ pPolyCnt,
+ INT32(parg16->f4)));
+
+ STACKORHEAPFREE(pPoints, BufferT + cInt16);
+ STACKORHEAPFREE(pPolyCnt, BufferT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+ULONG FASTCALL WG32PolyPolylineWOW(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PPOLYPOLYLINEWOW16 parg16;
+ LPPOINT pptArray;
+ LPDWORD pcntArray;
+ DWORD cnt;
+
+ GETARGPTR(pFrame, sizeof(POLYPOLYLINEWOW16), parg16);
+
+ cnt = FETCHDWORD(parg16->f4);
+
+ GETVDMPTR(parg16->f2, sizeof(POINT)*cnt, pptArray);
+ GETVDMPTR(parg16->f3, sizeof(DWORD)*cnt, pcntArray);
+
+ ul = GETBOOL16(PolyPolyline(HDC32(parg16->f1),
+ pptArray,
+ pcntArray,
+ cnt));
+ FREEVDMPTR(pptArray);
+ FREEVDMPTR(pcntArray);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32Polygon(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPPOINT p2;
+ register PPOLYGON16 parg16;
+ POINT BufferT[128];
+
+ GETARGPTR(pFrame, sizeof(POLYGON16), parg16);
+ p2 = STACKORHEAPALLOC(parg16->f3 * sizeof(POINT), sizeof(BufferT), BufferT);
+ getpoint16(parg16->f2, parg16->f3, p2);
+
+ ul = GETBOOL16(Polygon(HDC32(parg16->f1), p2, INT32(parg16->f3)));
+
+ STACKORHEAPFREE(p2, BufferT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32Polyline(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PPOINT t2;
+ register PPOLYLINE16 parg16;
+ POINT BufferT[128];
+
+ GETARGPTR(pFrame, sizeof(POLYLINE16), parg16);
+ t2 = STACKORHEAPALLOC(parg16->f3 * sizeof(POINT), sizeof(BufferT), BufferT);
+ getpoint16(parg16->f2, parg16->f3, t2);
+
+ ul = GETBOOL16(Polyline(HDC32(parg16->f1), t2, INT32(parg16->f3)));
+
+ STACKORHEAPFREE(t2, BufferT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32PtInRegion(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PPTINREGION16 parg16;
+
+ GETARGPTR(pFrame, sizeof(PTINREGION16), parg16);
+
+ ul = GETBOOL16(PtInRegion(HRGN32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32PtVisible(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PPTVISIBLE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(PTVISIBLE16), parg16);
+
+ ul = GETBOOL16(PtVisible(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WG32RectInRegion(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t2;
+ register PRECTINREGION16 parg16;
+
+ GETARGPTR(pFrame, sizeof(RECTINREGION16), parg16);
+ WOW32VERIFY(GETRECT16(parg16->f2, &t2));
+
+ ul = GETBOOL16(RectInRegion(HRGN32(parg16->f1), &t2));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32RectVisible(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t2;
+ register PRECTVISIBLE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(RECTVISIBLE16), parg16);
+ WOW32VERIFY(GETRECT16(parg16->f2, &t2));
+
+ ul = GETBOOL16(RectVisible(HDC32(parg16->f1), &t2));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32Rectangle(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PRECTANGLE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(RECTANGLE16), parg16);
+
+ ul = GETBOOL16(Rectangle(HDC32(parg16->hdc),
+ INT32(parg16->x1),
+ INT32(parg16->y1),
+ INT32(parg16->x2),
+ INT32(parg16->y2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32RestoreDC(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PRESTOREDC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(RESTOREDC16), parg16);
+
+ ul = GETBOOL16(RestoreDC(HDC32(parg16->f1), INT32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32RoundRect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PROUNDRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ROUNDRECT16), parg16);
+
+ ul = GETBOOL16(RoundRect(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ INT32(parg16->f6),
+ INT32(parg16->f7)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SaveDC(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSAVEDC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SAVEDC16), parg16);
+
+ ul = GETINT16(SaveDC(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32ScaleViewportExt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE size;
+ register PSCALEVIEWPORTEXT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SCALEVIEWPORTEXT16), parg16);
+
+ ul = 0;
+ if (ScaleViewportExtEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ &size)) {
+
+ if (!(ul = (WORD)size.cx | (size.cy << 16))) // see above
+ ul = 1;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32ScaleWindowExt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE size;
+ register PSCALEWINDOWEXT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SCALEWINDOWEXT16), parg16);
+
+ ul = 0;
+ if (ScaleWindowExtEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ &size)) {
+
+ if (!(ul = (WORD)size.cx | (size.cy << 16))) // see above
+ ul = 1;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SelectClipRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSELECTCLIPRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SELECTCLIPRGN16), parg16);
+
+ ul = GETINT16(SelectClipRgn(HDC32(parg16->f1), HRGN32(parg16->f2)));
+
+ WOW32APIWARN(ul, "SelectClipRgn");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SelectObject(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSELECTOBJECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SELECTOBJECT16), parg16);
+
+ ul = GETHOBJ16(SelectObject(HDC32(parg16->f1), HOBJ32(parg16->f2)));
+
+ WOW32APIWARN(ul, "SelectObject");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/******************************Public*Routine******************************\
+* PBYTE pjCvtPlaneToPacked4
+*
+* Convert a 4plane, 1bpp bitmap into a 1plane, 4bpp bitmap.
+* This functions returns a pointer that must later be freed with LocalFree().
+*
+* This has been added for PhotoShop 16 color vga compatability.
+*
+* History:
+* 28-May-1993 -by- Eric Kutter [erick]
+* Wrote it.
+\**************************************************************************/
+
+PBYTE pjCvtPlaneToPacked4(
+ BITMAP *pbm,
+ PBYTE pjSrc,
+ DWORD *pcjSrc)
+{
+ PBYTE pjDstRet;
+ PBYTE pjDst;
+ PBYTE pjPlane[4]; // pointer to first byte of current scan for each plane
+ DWORD cjWidth; // width of the destination in bytes
+ DWORD cjSrcWidth; // width of the source scan in bytes inc. all planes
+ DWORD cy; // number of scans
+ BYTE shift; // shift value,
+ DWORD i,x,y;
+
+// just grab the width of the dest out of the BITMAP
+
+ cjWidth = pbm->bmWidthBytes;
+
+// the src should be word aligned for each plane with 4 planes
+
+ cjSrcWidth = ((pbm->bmWidth + 15) & ~15) / 8 * 4;
+
+// compute the height, the smaller of the bm height and the source height
+
+ cy = min((DWORD)pbm->bmHeight,(DWORD)(*pcjSrc / cjSrcWidth));
+
+// allocate the new chunk of memory
+
+ *pcjSrc = cy * cjWidth;
+
+ pjDst = LocalAlloc(LMEM_FIXED,*pcjSrc);
+
+ if (pjDst == NULL)
+ return(NULL);
+
+ pjDstRet = pjDst;
+
+// intialize the beginings of the planes
+
+ for (i = 0; i < 4; ++i)
+ pjPlane[i] = pjSrc + (cjSrcWidth / 4) * i;
+
+// loop through the scans
+
+ for (y = 0; y < cy; ++y)
+ {
+ shift = 7;
+
+ // loop through the bytes within a scan
+
+ for (x = 0; x < cjWidth; ++x)
+ {
+
+ // bit 7 -> nibble 1
+ // bit 6 -> nibble 0
+ // bit 5 -> nibble 3
+ // bit 4 -> nibble 2
+ // . . .
+
+ *pjDst = (((pjPlane[0][x/4] >> (shift-1)) & 1) << 0 ) | // 0x01
+ (((pjPlane[1][x/4] >> (shift-1)) & 1) << 1 ) | // 0x02
+ (((pjPlane[2][x/4] >> (shift-1)) & 1) << 2 ) | // 0x04
+ (((pjPlane[3][x/4] >> (shift-1)) & 1) << 3 ) | // 0x08
+
+ (((pjPlane[0][x/4] >> (shift-0)) & 1) << 4 ) | // 0x10
+ (((pjPlane[1][x/4] >> (shift-0)) & 1) << 5 ) | // 0x20
+ (((pjPlane[2][x/4] >> (shift-0)) & 1) << 6 ) | // 0x40
+ (((pjPlane[3][x/4] >> (shift-0)) & 1) << 7 ); // 0x80
+
+ pjDst++;
+ shift = (shift - 2) & 7;
+ }
+
+ pjPlane[0] += cjSrcWidth;
+ pjPlane[1] += cjSrcWidth;
+ pjPlane[2] += cjSrcWidth;
+ pjPlane[3] += cjSrcWidth;
+ }
+
+ return(pjDstRet);
+}
+
+ULONG FASTCALL WG32SetBitmapBits(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PBYTE pb3;
+ register PSETBITMAPBITS16 parg16;
+ HBITMAP hbm;
+ DWORD cj;
+ BITMAP bm;
+ BOOL fValidObj;
+
+ GETARGPTR(pFrame, sizeof(SETBITMAPBITS16), parg16);
+ GETOPTPTR(parg16->f3, 0, pb3);
+
+ hbm = HBITMAP32(parg16->f1);
+ cj = DWORD32(parg16->f2);
+
+ fValidObj = (GetObject(hbm,sizeof(BITMAP),&bm) == sizeof(BITMAP));
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_4PLANECONVERSION) {
+
+ // Get the size of the destination bitmap
+
+ if (fValidObj &&
+ (bm.bmPlanes == 1) &&
+ (bm.bmBitsPixel == 4))
+ {
+ PBYTE pjCvt = pjCvtPlaneToPacked4(&bm,pb3,&cj);
+
+ if (pjCvt)
+ ul = SetBitmapBits(hbm,cj,pjCvt);
+ else
+ ul = 0;
+
+ LocalFree(pjCvt);
+ hbm = 0;
+ }
+ }
+ else {
+ cj = min(cj, (DWORD)(bm.bmWidthBytes * bm.bmHeight));
+ }
+
+
+ if (hbm != 0)
+ ul = GETLONG16(SetBitmapBits(hbm,cj,pb3));
+
+ WOW32APIWARN (ul, "SetBitmapBits");
+
+ FREEMISCPTR(pb3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetBitmapDimension(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE size4;
+ register PSETBITMAPDIMENSION16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETBITMAPDIMENSION16), parg16);
+
+ ul = 0;
+ if (SetBitmapDimensionEx(HBITMAP32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ &size4)) {
+
+ ul = (WORD)size4.cx | (size4.cy << 16);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetBkColor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETBKCOLOR16 parg16;
+ COLORREF color;
+
+ GETARGPTR(pFrame, sizeof(SETBKCOLOR16), parg16);
+
+ color = DWORD32(parg16->f2);
+
+ if (((ULONG)color >= 0x03000000) &&
+ (HIWORD(color) != 0x10ff))
+ {
+ color &= 0xffffff;
+ }
+
+ ul = GETDWORD16(SetBkColor(HDC32(parg16->f1), color));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetBkMode(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETBKMODE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETBKMODE16), parg16);
+
+ ul = GETINT16(SetBkMode(HDC32(parg16->f1), INT32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetBrushOrg(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ POINT pt;
+ POINT pt2;
+ register PSETBRUSHORG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETBRUSHORG16), parg16);
+
+// for windows compatability, we must first subtract off the DCorg
+// since windows brushorg is relative to the screen where as NT
+// is relative to the window. In the future, this should call
+// a private gdi entry point to avoid an extra c/s hit. (erick)
+
+ if (GetDCOrgEx(HDC32(parg16->f1),&pt))
+ {
+ ul = 0;
+ pt2.x = 1L; // see "METAFILE NOTE"
+ pt2.y = 0L;
+ if (SetBrushOrgEx(HDC32(parg16->f1),
+ INT32(parg16->f2) - pt.x,
+ INT32(parg16->f3) - pt.y,
+ &pt2)) {
+
+// add the origin back on so the app gets a consistent return value.
+// view...all from micrografx designer doesn't work unless this returns
+// the right thing.
+
+ ul = (WORD)(pt2.x + pt.x) | ((pt2.y + pt.y) << 16);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetDIBits(PVDMFRAME pFrame)
+{
+ ULONG ul = 0L;
+ PBYTE pb5;
+ STACKBMI32 bmi32;
+ LPBITMAPINFO lpbmi32;
+ register PSETDIBITS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETDIBITS16), parg16);
+ GETMISCPTR(parg16->f5, pb5);
+
+ lpbmi32 = CopyBMI16ToBMI32((PVPVOID)FETCHDWORD(parg16->f6),
+ (LPBITMAPINFO)&bmi32,
+ FETCHWORD(parg16->f7));
+
+ ul = GETINT16(SetDIBits(HDC32(parg16->f1),
+ HBITMAP32(parg16->f2),
+ WORD32(parg16->f3),
+ WORD32(parg16->f4),
+ pb5,
+ lpbmi32,
+ WORD32(parg16->f7)));
+
+ WOW32APIWARN (ul, "WG32SetDIBits\n");
+
+ FREEMISCPTR(pb5);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetDIBitsToDevice(PVDMFRAME pFrame)
+{
+ ULONG ul = 0L;
+ PSZ p10;
+ STACKBMI32 bmi32;
+ LPBITMAPINFO lpbmi32;
+ register PSETDIBITSTODEVICE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETDIBITSTODEVICE16), parg16);
+ GETMISCPTR(parg16->f10, p10);
+
+ lpbmi32 = CopyBMI16ToBMI32((PVPVOID)FETCHDWORD(parg16->f11),
+ (LPBITMAPINFO)&bmi32,
+ FETCHWORD(parg16->f12));
+
+ // these are doc'd as WORD in Win3.0, doc'd as INT in Win3.1
+ WOW32ASSERTMSG(((INT)parg16->f4 >= 0),("WOW:signed val - a-craigj\n"));
+ WOW32ASSERTMSG(((INT)parg16->f5 >= 0),("WOW:signed val - a-craigj\n"));
+ WOW32ASSERTMSG(((INT)parg16->f8 >= 0),("WOW:signed val - a-craigj\n"));
+ WOW32ASSERTMSG(((INT)parg16->f9 >= 0),("WOW:signed val - a-craigj\n"));
+
+ ul = GETINT16(SetDIBitsToDevice(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ WORD32(parg16->f4),
+ WORD32(parg16->f5),
+ INT32(parg16->f6),
+ INT32(parg16->f7),
+ WORD32(parg16->f8),
+ WORD32(parg16->f9),
+ p10,
+ lpbmi32,
+ WORD32(parg16->f12)));
+
+ WOW32APIWARN (ul, "WG32SetDIBitsToDevice\n");
+
+ FREEMISCPTR(p10);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetMapMode(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETMAPMODE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETMAPMODE16), parg16);
+
+ ul = GETINT16(SetMapMode(HDC32(parg16->f1), INT32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetMapperFlags(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETMAPPERFLAGS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETMAPPERFLAGS16), parg16);
+
+ ul = GETDWORD16(SetMapperFlags(HDC32(parg16->f1), DWORD32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetPixel(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETPIXEL16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETPIXEL16), parg16);
+
+ ul = GETDWORD16(SetPixel(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ DWORD32(parg16->f4)));
+
+ if (ul == CLR_INVALID) {
+ LOGDEBUG(6,("SetPixel : Pixel outside of clipping region\n"));
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetPolyFillMode(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETPOLYFILLMODE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETPOLYFILLMODE16), parg16);
+
+ ul = GETINT16(SetPolyFillMode(HDC32(parg16->f1), INT32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetROP2(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETROP216 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETROP216), parg16);
+
+ ul = GETINT16(SetROP2(HDC32(parg16->f1), INT32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetRectRgn(PVDMFRAME pFrame)
+{
+ register PSETRECTRGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETRECTRGN16), parg16);
+
+ SetRectRgn(HRGN32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5));
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+ULONG FASTCALL WG32SetStretchBltMode(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETSTRETCHBLTMODE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETSTRETCHBLTMODE16), parg16);
+
+ ul = GETINT16(SetStretchBltMode(HDC32(parg16->f1), INT32(parg16->f2)));
+
+ WOW32APIWARN (ul, "SetStretchBltMode");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetViewportExt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE size;
+ register PSETVIEWPORTEXT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETVIEWPORTEXT16), parg16);
+
+ ul = 0;
+ if (SetViewportExtEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ &size)) {
+
+ if (!(ul = (WORD)size.cx | (size.cy << 16))) // see above
+ ul = 1;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetViewportOrg(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ register PSETVIEWPORTORG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETVIEWPORTORG16), parg16);
+
+ ul = 0;
+ pt.x = 1L; // see "METAFILE NOTE"
+ pt.y = 0L;
+ if (SetViewportOrgEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ &pt)) {
+
+ ul = (WORD)pt.x | (pt.y << 16);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetWindowExt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE size;
+ register PSETWINDOWEXT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWEXT16), parg16);
+
+ ul = 0;
+ if (SetWindowExtEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ &size)) {
+ if (!(ul = (WORD)size.cx | (size.cy << 16))) // see above
+ ul = 1;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetWindowOrg(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ register PSETWINDOWORG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWORG16), parg16);
+
+ ul = 0;
+ pt.x = 1L; // see "METAFILE NOTE"
+ pt.y = 0L;
+ if (SetWindowOrgEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ &pt)) {
+ ul = (WORD)pt.x | (pt.y << 16);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32StretchBlt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSTRETCHBLT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(STRETCHBLT16), parg16);
+
+ ul = GETBOOL16(StretchBlt(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ HDC32(parg16->f6),
+ INT32(parg16->f7),
+ INT32(parg16->f8),
+ INT32(parg16->f9),
+ INT32(parg16->f10),
+ DWORD32(parg16->f11)));
+
+ WOW32APIWARN (ul, "StretchBlt");
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32StretchDIBits(PVDMFRAME pFrame)
+{
+ ULONG ul = 0L;
+ PBYTE pb10;
+ STACKBMI32 bmi32;
+ LPBITMAPINFO lpbmi32;
+ register PSTRETCHDIBITS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(STRETCHDIBITS16), parg16);
+ GETMISCPTR(parg16->f10, pb10);
+
+ lpbmi32 = CopyBMI16ToBMI32((PVPVOID)FETCHDWORD(parg16->f11),
+ (LPBITMAPINFO)&bmi32,
+ FETCHWORD(parg16->f12));
+
+ // some apps (QuarkXPress) don't fill in the size image for RLE's
+ // if it is 4bpp RLE with 0 size, fill in the size.
+
+ if ((lpbmi32->bmiHeader.biCompression == 2) &&
+ (lpbmi32->bmiHeader.biSizeImage == 0) &&
+ (pb10 != NULL))
+ {
+ int cj = 0;
+ PBYTE pj = pb10;
+ BOOL bDone = FALSE;
+
+ while (!bDone)
+ {
+ if (*pj == 0)
+ {
+ // absolute mode
+
+ switch (pj[1])
+ {
+ case 0: // end of line
+ pj += 2;
+ break;
+
+ case 1: // end of bitmap
+ pj += 2;
+ bDone = TRUE;
+ break;
+
+ case 2: // offset
+ pj += 4;
+ break;
+
+ default:
+ pj += (2 + ((pj[1] + 3) / 2) & ~1); // align nibles to word boundry
+ break;
+ }
+ }
+ else
+ {
+ // encoded mode
+
+ pj += 2;
+
+ }
+ }
+
+ lpbmi32->bmiHeader.biSizeImage = pj - pb10;
+ }
+
+
+
+ ul = GETINT16(StretchDIBits(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ INT32(parg16->f6),
+ INT32(parg16->f7),
+ INT32(parg16->f8),
+ INT32(parg16->f9),
+ pb10,
+ lpbmi32,
+ (DWORD)FETCHWORD(parg16->f12),
+ DWORD32(parg16->f13)));
+
+ WOW32APIWARN (ul, "WG32StretchDIBits\n");
+
+ FREEMISCPTR(pb10);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32UnrealizeObject(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PUNREALIZEOBJECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(UNREALIZEOBJECT16), parg16);
+
+ ul = GETBOOL16(UnrealizeObject(HOBJ32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+// *** New Private APIs ***
+
+#if 0
+// no thunk for this routine!
+ULONG FASTCALL WG32GetObjectType( PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PGETOBJECTTYPE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETOBJECTTYPE16), parg16);
+
+ ul = GetObjectType(HOBJ32(parg16->f1));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+#endif
+
+
+
+ULONG FASTCALL WG32GetCurrentObject( PVDMFRAME pFrame)
+{
+ ULONG ul;
+ HANDLE h;
+ PGETCURRENTOBJECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCURRENTOBJECT16), parg16);
+
+ h = GetCurrentObject(HDC32(parg16->f1), (ULONG)(parg16->f2));
+
+ ul = HGDI16(h);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+ULONG FASTCALL WG32GetRegionData( PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PBYTE pb3;
+ PGETREGIONDATA16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETREGIONDATA16), parg16);
+ ALLOCVDMPTR(parg16->f3, (INT)parg16->f2, pb3);
+
+ ul = GetRegionData(HRGN32(parg16->f1), (ULONG)(parg16->f2), (LPRGNDATA)pb3);
+
+ FLUSHVDMPTR(parg16->f3, (INT)parg16->f2, pb3);
+ FREEVDMPTR(pb3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetObjectOwner( PVDMFRAME pFrame)
+{
+ ULONG ul = 1;
+
+ LOGDEBUG(6,("WOW32::WG32SetObjectOwner: was called \n"));
+
+ RETURN(ul);
+}
+
+
+//
+// This routine calls back the apps SetAbortProc routine.
+//
+
+LONG W32AbortProc(HDC hPr, int code)
+{
+ LONG lReturn;
+ PARM16 Parm16;
+ register PTD ptd;
+ DWORD AbortProcT;
+
+
+ ptd = CURRENTPTD();
+
+ WOW32ASSERT(ptd->htask16);
+
+ AbortProcT = ((PTDB)SEGPTR(ptd->htask16, 0))->TDB_vpfnAbortProc;
+ if (AbortProcT) {
+
+ Parm16.SetAbortProc.hPr = GETHDC16(hPr);
+ Parm16.SetAbortProc.code = (SHORT) code;
+
+ CallBack16(RET_SETABORTPROC,
+ &Parm16,
+ AbortProcT,
+ (PVPVOID)&lReturn);
+
+ lReturn = (LONG)LOWORD(lReturn); // Returns a BOOL
+ }
+ else {
+ lReturn = (LONG)TRUE;
+ }
+
+ return (lReturn);
+}
+
+
+
+
+
+
+// note: cb is the number of data bytes in lpData NOT including the USHORT byte
+// count at the start of the data stream. In other words, lpData contains
+// cb + sizeof(USHORT) bytes.
+LONG HandleFormFeedHack(HDC hdc, LPBYTE lpdata, int cb)
+{
+ int cbBytes;
+ LONG ul;
+ PFORMFEEDHACK pCur;
+
+ // look for a node with a pointer to a data stream buffer from the previous
+ // call to Escape(,,PASSTHROUGH,,)...
+ pCur = FindFormFeedHackNode(hdc);
+
+ // if we found one, it's time to send the data stream to the printer...
+ if(pCur) {
+
+ // ...time to send it to the printer
+ ul = GETINT16(Escape(hdc,
+ PASSTHROUGH,
+ pCur->cbBytes + sizeof(USHORT),
+ pCur->lpBytes,
+ NULL));
+
+ // free the current node
+ FreeFormFeedHackNode(pCur);
+
+ // if there was a problem we're done
+ if(ul <= 0) {
+ return(ul);
+ }
+ }
+
+ // send everything up to the last form feed in the new data stream
+ cbBytes = cb;
+ lpdata = SendFrontEndOfDataStream(hdc, lpdata, &cbBytes, &ul);
+
+ // if there was a problem
+ // OR if the entire data stream got sent since it didn't contain a formfeed
+ // -- we're done
+ if(lpdata == NULL) {
+ return(ul); // this will contain error code OR number of bytes sent
+ }
+
+ // else create a node for this data stream
+ else {
+
+ pCur = CreateFormFeedHackNode(hdc, cbBytes, lpdata);
+
+ // if we can't allocate a new node...
+ if(pCur == NULL) {
+
+ // Things are in pretty bad shape if we get to here...
+ // We need to write the byte count at the front of the data stream.
+ // Remember lpdata had a word size byte count at the front of it
+ // when it was sent to us.
+
+ // if any bytes got sent via SendFrontEndOfDataStream()...
+ if(cbBytes < cb) {
+
+ // ...first we need to word align this for Escape32()...
+ if((DWORD)lpdata & 0x00000001) {
+ lpdata--;
+ *lpdata = '\0'; // stick a harmless char in the stream
+ cbBytes++; // ...and account for it
+ }
+
+ // ...adjust the data stream ptr to accomodate the byte count...
+ lpdata -= sizeof(USHORT);
+
+ }
+
+ // ...write in the byte count...
+ *(UNALIGNED USHORT *)lpdata = cbBytes;
+
+ // ...and send the remainder of the data stream to the printer.
+ // If an extra page gets sent to the printer, too bad.
+ ul = GETINT16(Escape(hdc,
+ PASSTHROUGH,
+ cbBytes + sizeof(USHORT),
+ lpdata,
+ NULL));
+
+ // if the was an error, return it to the app
+ if(ul <= 0) {
+ return(ul);
+ }
+ // else we managed to get everything sent to the printer OK
+ else {
+ return(cb); // return the number of bytes the app sent
+ }
+ }
+ }
+
+ // return the number of bytes the app requested to send
+ return(cb);
+
+}
+
+
+
+
+
+
+LPBYTE SendFrontEndOfDataStream(HDC hdc, LPBYTE lpData, int *cb, LONG *ul)
+{
+ int diff;
+ LPBYTE lpByte, lpStart;
+
+ // if there's no data or a bad cb, just send it so we can get the error code
+ if((lpData == NULL) || (*cb <= 0)) {
+ *ul = GETINT16(Escape(hdc,
+ PASSTHROUGH,
+ *cb + sizeof(USHORT),
+ lpData,
+ NULL));
+ return(NULL);
+ }
+
+ // find the start of the actual data after the byte count
+ lpStart = lpData + sizeof(USHORT);
+
+ // look for a formfeed char at or near the end of the data stream
+ lpByte = lpStart + ((*cb - 1) * sizeof(BYTE));
+ while(lpByte >= lpStart) {
+
+ // if we have found the odious formfeed char....
+ if((UCHAR)(*lpByte) == 0x0c) {
+
+ diff = lpByte - lpStart;
+
+ // send everything in the stream up to (but not incl) the formfeed
+ if(diff) {
+
+ // adjust the byte count in the data stream
+ *(UNALIGNED USHORT *)lpData = (USHORT)diff;
+
+ // send it to the printer
+ *ul = GETINT16(Escape(hdc,
+ PASSTHROUGH,
+ diff + sizeof(USHORT),
+ lpData,
+ NULL));
+
+ // if there was a problem, return it to the app
+ if(*ul <= 0) {
+ return(NULL);
+ }
+ }
+
+ // else formfeed is the first char in the data stream
+ else {
+ *ul = *cb; // just lie and say we sent it all
+ }
+
+ // adjust the remaining number of bytes
+ *cb -= diff;
+
+ // return ptr to the formfeed char as new start of data stream
+ return(lpByte);
+ }
+
+ lpByte--;
+ }
+
+ // if there are no formfeed's in the data stream just send the whole thing
+ *ul = GETINT16(Escape(hdc,
+ PASSTHROUGH,
+ *cb + sizeof(USHORT),
+ lpData,
+ NULL));
+
+ return(NULL); // specify we sent the whole thing
+
+}
+
+
+
+
+
+
+// note: this assumes that if there is a node, there is a list
+void FreeFormFeedHackNode(PFORMFEEDHACK pNode)
+{
+ PFORMFEEDHACK pCur, pPrev, pListStart;
+
+ pPrev = NULL;
+ pCur = pListStart = gpFormFeedHackList;
+
+ // if there is a node, there must be a node list
+ WOW32ASSERT(pCur);
+
+ if(pNode) {
+
+ while(pCur) {
+
+ if(pCur == pNode) {
+
+ if(pNode->lpBytes) {
+ free_w(pNode->lpBytes);
+ }
+
+ if(pPrev) {
+ pPrev->next = pCur->next;
+ }
+ else {
+ pListStart = pCur->next;
+ }
+
+ free_w(pNode);
+ break;
+ }
+ else {
+ pPrev = pCur;
+ pCur = pCur->next;
+ }
+ }
+ }
+
+ gpFormFeedHackList = pListStart;
+}
+
+
+
+
+
+void FreeTaskFormFeedHacks(HAND16 h16)
+{
+ PFORMFEEDHACK pNext, pCur;
+
+ pCur = gpFormFeedHackList;
+
+ while(pCur) {
+
+ if(pCur->hTask16 == h16) {
+
+ // we already told the app we sent this so give it one last try
+ Escape(pCur->hdc,
+ PASSTHROUGH,
+ pCur->cbBytes + sizeof(USHORT),
+ pCur->lpBytes,
+ NULL);
+
+ pNext = pCur->next;
+ if(pCur->lpBytes) {
+ free_w(pCur->lpBytes);
+ }
+
+ if(pCur == gpFormFeedHackList) {
+ gpFormFeedHackList = pNext;
+ }
+
+ free_w(pCur);
+
+ pCur = pNext;
+ }
+ }
+}
+
+
+
+
+
+
+// this should only be called by Escape(,,ENDDOC,,)
+void SendFormFeedHack(HDC hdc)
+{
+ int cb;
+ LPBYTE pBytes = NULL;
+ PFORMFEEDHACK pCur;
+
+ pCur = gpFormFeedHackList;
+
+ while(pCur) {
+
+ if(pCur->hdc == hdc) {
+
+ if(pCur->lpBytes) {
+
+ cb = pCur->cbBytes;
+
+ // point to actual data after byte count
+ pBytes = pCur->lpBytes + sizeof(USHORT);
+
+ // strip the form feed from the buffered data stream...
+ if((UCHAR)(*pBytes) == 0x0c) {
+ *pBytes = '\0';
+ pBytes++;
+ cb--;
+ }
+
+ // strip the carriage ret from the buffered data stream...
+ // (some apps put a carriage return after the last formfeed)
+ if((UCHAR)(*pBytes) == 0x0d) {
+ *pBytes = '\0';
+ cb--;
+ }
+
+ // ...and send it to the printer
+ if(cb > 0) {
+ Escape(hdc,
+ PASSTHROUGH,
+ cb + sizeof(USHORT),
+ pCur->lpBytes,
+ NULL);
+ }
+ }
+
+ // free this node from the hack list now
+ FreeFormFeedHackNode(pCur);
+
+ break;
+ }
+ pCur = pCur->next;
+ }
+}
+
+
+
+
+
+PFORMFEEDHACK FindFormFeedHackNode(HDC hdc)
+{
+ PFORMFEEDHACK pCur;
+
+
+ pCur = gpFormFeedHackList;
+
+ while(pCur) {
+
+ if(pCur->hdc == hdc) {
+ return(pCur);
+ }
+
+ pCur = pCur->next;
+ }
+
+ return(NULL);
+}
+
+
+
+
+// this will only get called if PART of the data stream got sent to the printer
+PFORMFEEDHACK CreateFormFeedHackNode(HDC hdc, int cb, LPBYTE lpData)
+{
+ LPBYTE pBytes;
+ PFORMFEEDHACK pNode;
+
+ // allocate a new node
+ pNode = malloc_w(sizeof(FORMFEEDHACK));
+
+ // if we were able to get one...
+ if(pNode) {
+
+ // ...allocate a buffer for the data stream
+ pBytes = malloc_w(cb + sizeof(USHORT));
+
+ // if we were able to get one...
+ if(pBytes) {
+
+ // ...fill in the node...
+ pNode->hdc = hdc;
+ pNode->lpBytes = pBytes;
+ pNode->cbBytes = cb;
+ pNode->hTask16 = CURRENTPTD()->htask16;
+
+ // ...and stick the new node at the front of the node list
+ pNode->next = gpFormFeedHackList;
+ gpFormFeedHackList = pNode;
+
+ // add the new size to the front of the data stream
+ *(UNALIGNED USHORT *)pBytes = (USHORT)cb;
+ pBytes += sizeof(USHORT);
+
+ // copy the the data stream into the node buffer
+ RtlCopyMemory(pBytes, lpData, cb);
+
+ return(pNode);
+ }
+
+ // else if we couldn't get a data stream buffer...
+ else {
+ free_w(pNode);
+ }
+ }
+
+ return(NULL); // return NULL if either allocate failed
+}
+
+
+
+
+
+
+// this should only be called by Escape(,,AbortDOC,,) and AbortDoc()
+void RemoveFormFeedHack(HDC hdc)
+{
+ PFORMFEEDHACK pNode;
+
+ pNode = FindFormFeedHackNode(hdc);
+
+ if(pNode) {
+
+ FreeFormFeedHackNode(pNode);
+ }
+}
diff --git a/private/mvdm/wow32/wgdi.h b/private/mvdm/wow32/wgdi.h
new file mode 100644
index 000000000..cf5089a36
--- /dev/null
+++ b/private/mvdm/wow32/wgdi.h
@@ -0,0 +1,162 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGDI.H
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+typedef struct _LINEDDADATA { /* LineDDAdata */
+ VPPROC vpfnLineDDAProc; // 16-bit function
+ DWORD dwUserDDAParam; // user param, if any
+} LINEDDADATA, *PLINEDDADATA;
+
+typedef struct _ENUMOBJDATA { /* LineDDAdata */
+ INT ObjType;
+ VPPROC vpfnEnumObjProc; // 16-bit function
+ VPVOID vpObjData;
+ DWORD dwUserParam; // user param, if any
+} ENUMOBJDATA, *PENUMOBJDATA;
+
+ULONG FASTCALL WG32Arc(PVDMFRAME pFrame);
+ULONG FASTCALL WG32BitBlt(PVDMFRAME pFrame);
+ULONG FASTCALL WG32Chord(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CombineRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateBitmap(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateBitmapIndirect(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateBrushIndirect(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateCompatibleBitmap(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateCompatibleDC(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateDC(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateDIBPatternBrush(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateDIBitmap(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateDiscardableBitmap(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateEllipticRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateEllipticRgnIndirect(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateHatchBrush(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateIC(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreatePatternBrush(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreatePen(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreatePenIndirect(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreatePolyPolygonRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreatePolygonRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateRectRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateRectRgnIndirect(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateRoundRectRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateSolidBrush(PVDMFRAME pFrame);
+ULONG FASTCALL WG32DPtoLP(PVDMFRAME pFrame);
+ULONG FASTCALL WG32DeleteDC(PVDMFRAME pFrame);
+ULONG FASTCALL WG32DeleteObject(PVDMFRAME pFrame);
+ULONG FASTCALL WG32DeviceMode(PVDMFRAME pFrame);
+ULONG FASTCALL WG32Ellipse(PVDMFRAME pFrame);
+ULONG FASTCALL WG32EnumObjects(PVDMFRAME pFrame);
+ULONG FASTCALL WG32EqualRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32Escape(PVDMFRAME pFrame);
+ULONG FASTCALL WG32ExcludeClipRect(PVDMFRAME pFrame);
+ULONG FASTCALL WG32ExtDeviceMode(PVDMFRAME pFrame);
+ULONG FASTCALL WG32DeviceCapabilities(PVDMFRAME pFrame);
+ULONG FASTCALL WG32ExtFloodFill(PVDMFRAME pFrame);
+ULONG FASTCALL WG32FillRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32FloodFill(PVDMFRAME pFrame);
+ULONG FASTCALL WG32FrameRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GdiFlush(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetBitmapBits(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetBitmapDimension(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetBkColor(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetBkMode(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetBrushOrg(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetClipBox(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetCurLogFont(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetCurrentObject(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetCurrentPosition(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetDCOrg(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetDIBits(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetDeviceCaps(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetEnvironment(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetMapMode(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetNearestColor(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetObject(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetObjectType(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetPixel(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetPolyFillMode(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetROP2(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetRegionData(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetRelAbs(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetRgnBox(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetStockObject(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetStretchBltMode(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetViewportExt(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetViewportOrg(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetWindowExt(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetWindowOrg(PVDMFRAME pFrame);
+ULONG FASTCALL WG32IntersectClipRect(PVDMFRAME pFrame);
+ULONG FASTCALL WG32InvertRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32LPtoDP(PVDMFRAME pFrame);
+ULONG FASTCALL WG32LineDDA(PVDMFRAME pFrame);
+ULONG FASTCALL WG32LineTo(PVDMFRAME pFrame);
+ULONG FASTCALL WG32MoveTo(PVDMFRAME pFrame);
+ULONG FASTCALL WG32MulDiv(PVDMFRAME pFrame);
+ULONG FASTCALL WG32OffsetClipRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32OffsetRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32OffsetViewportOrg(PVDMFRAME pFrame);
+ULONG FASTCALL WG32OffsetWindowOrg(PVDMFRAME pFrame);
+ULONG FASTCALL WG32PaintRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32PatBlt(PVDMFRAME pFrame);
+ULONG FASTCALL WG32Pie(PVDMFRAME pFrame);
+ULONG FASTCALL WG32PolyPolygon(PVDMFRAME pFrame);
+ULONG FASTCALL WG32Polygon(PVDMFRAME pFrame);
+ULONG FASTCALL WG32Polyline(PVDMFRAME pFrame);
+ULONG FASTCALL WG32PolyPolylineWOW(PVDMFRAME pFrame);
+ULONG FASTCALL WG32PtInRegion(PVDMFRAME pFrame);
+ULONG FASTCALL WG32PtVisible(PVDMFRAME pFrame);
+ULONG FASTCALL WG32RectInRegion(PVDMFRAME pFrame);
+ULONG FASTCALL WG32RectVisible(PVDMFRAME pFrame);
+ULONG FASTCALL WG32Rectangle(PVDMFRAME pFrame);
+ULONG FASTCALL WG32RestoreDC(PVDMFRAME pFrame);
+ULONG FASTCALL WG32RoundRect(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SaveDC(PVDMFRAME pFrame);
+ULONG FASTCALL WG32ScaleViewportExt(PVDMFRAME pFrame);
+ULONG FASTCALL WG32ScaleWindowExt(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SelectClipRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SelectObject(PVDMFRAME pFrame);
+LONG W32AbortProc(HDC hPr, int code);
+ULONG FASTCALL WG32SetBitmapBits(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetBitmapDimension(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetBkColor(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetBkMode(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetBrushOrg(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetDIBits(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetDIBitsToDevice(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetMapMode(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetMapperFlags(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetObjectOwner(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetPixel(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetPolyFillMode(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetROP2(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetRectRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetRelAbs(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetStretchBltMode(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetViewportExt(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetViewportOrg(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetWindowExt(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetWindowOrg(PVDMFRAME pFrame);
+ULONG FASTCALL WG32StretchBlt(PVDMFRAME pFrame);
+ULONG FASTCALL WG32StretchDIBits(PVDMFRAME pFrame);
+ULONG FASTCALL WG32UnrealizeObject(PVDMFRAME pFrame);
+
+ULONG FASTCALL WG32CreateDIBSection(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetDIBColorTable(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetDIBColorTable(PVDMFRAME pFrame);
+ULONG FASTCALL WG32DMBitBlt(PVDMFRAME pFrame);
+
+BOOL IsFaxPrinterSupportedDevice(PSZ pszDevice);
+BOOL IsFaxPrinterWriteProfileString(PSZ szSection, PSZ szKey, PSZ szString);
+DWORD GetFaxPrinterProfileString(PSZ szSection, PSZ szKey, PSZ szDefault, PSZ szRetBuf, DWORD cbBufSize);
+
+HANDLE hConvert16to32 (int h16);
+HAND16 hConvert32to16 (DWORD h32);
diff --git a/private/mvdm/wow32/wgdi31.c b/private/mvdm/wow32/wgdi31.c
new file mode 100644
index 000000000..790d37a40
--- /dev/null
+++ b/private/mvdm/wow32/wgdi31.c
@@ -0,0 +1,1105 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGDI31.C
+ * WOW32 16-bit Win 3.1 GDI API support
+ *
+ * History:
+ * Created 16-Mar-1992 by Chandan S. Chauhan (ChandanC)
+ *
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+#include <drivinit.h>
+#include "wowgdip.h"
+
+MODNAME(wgdi31.c);
+
+
+// This must be removed POSTBETA 2 for sure. We should be using common defines between
+// GDI and WOW. ChandanC 5/27/94.
+
+#define NOFIRSTSAVE 0x7FFFFFFE
+#define ADD_MSTT 0x7FFFFFFD
+
+// located in wgdi.c
+extern void SendFormFeedHack(HDC hdc);
+extern void RemoveFormFeedHack(HDC hdc);
+
+
+ULONG FASTCALL WG32AbortDoc(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PABORTDOC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ABORTDOC16), parg16);
+
+ // remove any buffered data streams.
+ if(CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_FORMFEEDHACK) {
+ RemoveFormFeedHack(HDC32(parg16->f1));
+ }
+
+ ul = GETINT16(AbortDoc(HDC32(parg16->f1)));
+
+ if ((INT)ul < 0) {
+ WOW32ASSERT ("WOW::WG32AbortDoc: Failed\n");
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateScalableFontResource(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ t2;
+ PSZ t3;
+ PSZ t4;
+ DWORD fHidden;
+ register PCREATESCALABLEFONTRESOURCE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATESCALABLEFONTRESOURCE16), parg16);
+ GETPSZPTR(parg16->f2, t2);
+ GETPSZPTR(parg16->f3, t3);
+ GETPSZPTR(parg16->f4, t4);
+
+ // We need to convert this param to 2 if the app gives 1. This tells GDI
+ // to embed client TID in the private (hidden) font.
+ //
+
+ fHidden = (parg16->f1 == 1) ? 2 : (parg16->f1);
+
+ ul = GETBOOL16(CreateScalableFontResource(fHidden,
+ t2,
+ t3,
+ t4));
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32EndDoc(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PENDDOC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENDDOC16), parg16);
+
+ // send any buffered data streams to the printer.
+ if(CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_FORMFEEDHACK) {
+ SendFormFeedHack(HDC32(parg16->f1));
+ }
+
+ ul = GETINT16(EndDoc(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32EndPage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PENDPAGE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENDPAGE16), parg16);
+
+ ul = GETINT16(EndPage(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32EnumFontFamilies(PVDMFRAME pFrame)
+{
+ return( W32EnumFontHandler(pFrame, TRUE) );
+}
+
+
+ULONG FASTCALL WG32GetAspectRatioFilterEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE AspectRatio;
+ register PGETASPECTRATIOFILTEREX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETASPECTRATIOFILTEREX16), parg16);
+
+ ul = GETBOOL16(GetAspectRatioFilterEx(HDC32(parg16->f1), &AspectRatio));
+
+ PUTSIZE16(parg16->f2, &AspectRatio);
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetBitmapDimensionEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE Dimension;
+ register PGETBITMAPDIMENSIONEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETBITMAPDIMENSIONEX16), parg16);
+
+ ul = GETBOOL16(GetBitmapDimensionEx(HBITMAP32(parg16->f1), &Dimension));
+
+ PUTSIZE16(parg16->f2, &Dimension);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetBoundsRect(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ RECT Bounds;
+ register PGETBOUNDSRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETBOUNDSRECT16), parg16);
+
+ ul = GETUINT16(GetBoundsRect(HDC32(parg16->f1),
+ &Bounds,
+ UINT32(parg16->f3)));
+
+ //
+ // Win16 GetBoundsRect always returns DCB_SET or DCB_RESET.
+ //
+ ul = (ul & DCB_SET) ? DCB_SET : DCB_RESET;
+
+ PUTRECT16(parg16->f2, &Bounds);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetBrushOrgEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT Point;
+ register PGETBRUSHORGEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETBRUSHORGEX16), parg16);
+
+ ul = GETBOOL16(GetBrushOrgEx(HDC32(parg16->f1), &Point));
+
+ PUTPOINT16(parg16->f2, &Point);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetCharABCWidths(PVDMFRAME pFrame)
+{
+ ULONG ul=0;
+ LPABC lpAbc;
+ WORD cb;
+ register PGETCHARABCWIDTHS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCHARABCWIDTHS16), parg16);
+
+ cb = WORD32(parg16->f3) - WORD32(parg16->f2) + 1;
+ if (lpAbc = (LPABC) malloc_w (sizeof(ABC) * cb)) {
+ ul = GETBOOL16(GetCharABCWidths(HDC32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ lpAbc));
+ if (ul) {
+ putabcpairs16(parg16->f4, cb, lpAbc);
+ }
+
+ free_w (lpAbc);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN (ul);
+}
+
+
+
+ULONG FASTCALL WG32GetCurrentPositionEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT Point;
+ register PGETCURRENTPOSITIONEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCURRENTPOSITIONEX16), parg16);
+
+ ul = GETBOOL16(GetCurrentPositionEx(HDC32(parg16->f1), &Point));
+
+ PUTPOINT16(parg16->f2, &Point);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetFontData(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPSTR lpBuffer = NULL;
+ register PGETFONTDATA16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETFONTDATA16), parg16);
+
+ if( parg16->f4 && parg16->f5 ) {
+ if (!(lpBuffer = (LPSTR) malloc_w (DWORD32(parg16->f5)))) {
+ FREEARGPTR(parg16);
+ RETURN ((ULONG)-1);
+ }
+ }
+
+ ul = GETDWORD16(GetFontData(HDC32(parg16->f1),
+ DWORD32(parg16->f2),
+ DWORD32(parg16->f3),
+ lpBuffer,
+ DWORD32(parg16->f5)));
+
+ if( lpBuffer ) {
+ PUTBUFFER16(parg16->f4, DWORD32(parg16->f5), lpBuffer);
+ free_w(lpBuffer);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+ULONG FASTCALL WG32GetGlyphOutline(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPSTR lpBuffer = NULL;
+ MAT2 Matrix;
+ GLYPHMETRICS Metrics;
+ register PGETGLYPHOUTLINE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETGLYPHOUTLINE16), parg16);
+ GETMAT2(parg16->f7, &Matrix);
+
+ if (parg16->f5 && parg16->f6) {
+ if((lpBuffer = (LPSTR) malloc_w(DWORD32(parg16->f5))) == NULL) {
+ FREEARGPTR(parg16);
+ return((ULONG)-1);
+ }
+ }
+
+ ul = GETDWORD16(GetGlyphOutlineWow(HDC32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ parg16->f4 ? &Metrics : (GLYPHMETRICS*)NULL,
+ DWORD32(parg16->f5),
+ lpBuffer,
+ &Matrix));
+
+ if ( FETCHDWORD(parg16->f4) != 0 ) {
+ PUTGLYPHMETRICS16(FETCHDWORD(parg16->f4), &Metrics);
+ }
+
+ if ( lpBuffer ) {
+ PUTBUFFER16(parg16->f6, DWORD32(parg16->f5), lpBuffer);
+ free_w(lpBuffer);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetKerningPairs(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPKERNINGPAIR lpkrnpair = NULL;
+ register PGETKERNINGPAIRS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETKERNINGPAIRS16), parg16);
+
+ if (FETCHDWORD(parg16->f3)) {
+ lpkrnpair = (LPKERNINGPAIR) malloc_w (sizeof(KERNINGPAIR) * (parg16->f2));
+ if (!lpkrnpair) {
+ LOGDEBUG (0, ("WOW::WG32GetKeriningPairs: *** MALLOC failed ***\n"));
+ FREEARGPTR(parg16);
+ RETURN (0);
+ }
+
+ }
+
+ ul = GetKerningPairs(HDC32(parg16->f1), parg16->f2, lpkrnpair);
+
+ if (FETCHDWORD(parg16->f3)) {
+ putkerningpairs16 (FETCHDWORD(parg16->f3), parg16->f2, lpkrnpair);
+ free_w (lpkrnpair);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetOutlineTextMetrics(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETOUTLINETEXTMETRICS16 parg16;
+ UINT cb;
+ UINT new_cb;
+ VPOUTLINETEXTMETRIC16 vpotm;
+ LPOUTLINETEXTMETRIC lpBuffer;
+
+ GETARGPTR(pFrame, sizeof(GETOUTLINETEXTMETRICS16), parg16);
+
+ vpotm = (VPOUTLINETEXTMETRIC16)FETCHDWORD(parg16->f3);
+
+ new_cb = cb = FETCHWORD(parg16->f2);
+
+ if ( vpotm ) {
+ new_cb += sizeof(OUTLINETEXTMETRIC) - sizeof(OUTLINETEXTMETRIC16);
+ if (!(lpBuffer = (LPOUTLINETEXTMETRIC)malloc_w(new_cb))) {
+ FREEARGPTR(parg16);
+ RETURN (0);
+ }
+ } else {
+ lpBuffer = NULL;
+ }
+
+
+ ul = GETDWORD16(GetOutlineTextMetrics(HDC32(parg16->f1), new_cb, lpBuffer));
+
+ if ( vpotm ) {
+ PUTOUTLINETEXTMETRIC16(vpotm, cb, lpBuffer);
+ free_w( lpBuffer );
+ } else {
+ if ( ul != 0 ) {
+ ul -= sizeof(OUTLINETEXTMETRIC) - sizeof(OUTLINETEXTMETRIC16);
+ }
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetRasterizerCaps(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RASTERIZER_STATUS RStatus;
+ register PGETRASTERIZERCAPS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETRASTERIZERCAPS16), parg16);
+
+ ul = GETBOOL16(GetRasterizerCaps(&RStatus, INT32(parg16->f2)));
+
+ PUTRASTERIZERSTATUS16(parg16->f1, &RStatus);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+
+
+#define PUTEXTSIZE16(vp, lp) \
+{ \
+ PSIZE16 p16; \
+ GETVDMPTR(vp, sizeof(SIZE16), p16); \
+ if (((lp)->cx|(lp)->cy) & ~SHRT_MAX) \
+ { \
+ if ((lp)->cx > SHRT_MAX) \
+ STORESHORT(p16->cx, SHRT_MAX); \
+ else \
+ STORESHORT(p16->cx, (lp)->cx); \
+ if ((lp)->cy > SHRT_MAX) \
+ STORESHORT(p16->cy, SHRT_MAX); \
+ else \
+ STORESHORT(p16->cy, (lp)->cy); \
+ } \
+ else \
+ { \
+ STORESHORT(p16->cx, (lp)->cx); \
+ STORESHORT(p16->cy, (lp)->cy); \
+ } \
+ FREEVDMPTR(p16); \
+}
+
+
+ULONG FASTCALL WG32GetTextExtentPoint(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ lpString;
+ SIZE Size;
+ register PGETTEXTEXTENTPOINT16 parg16;
+ HDC hDC32;
+ HDC hDCMenu = NULL;
+ HGDIOBJ hOldFont;
+ HGDIOBJ hFont = NULL;
+ NONCLIENTMETRICS ncm;
+ PTD ptd = CURRENTPTD();
+
+ GETARGPTR(pFrame, sizeof(GETTEXTEXTENTPOINT16), parg16);
+ GETPSZPTR(parg16->f2, lpString);
+
+ hDC32 = HDC32(parg16->f1);
+
+// WP tutorial assumes that the font selected in the hDC for desktop window
+// (ie, result of GetDC(NULL)) is the same font as the font selected for
+// drawing the menu. Unfortunetly in SUR this is not true as the user can
+// select any font for the menu. So we remember the hDC returned for GetDC(0)
+// and check for it in GetTextExtentPoint. If the app does try to use it we
+// find the hDC for the current menu window and substitute that. When the app
+// does another GetDC or ReleaseDC we forget the hDC returned for the original
+// GetDC(0).
+ if ((ptd->dwWOWCompatFlagsEx & WOWCFEX_FIXDCFONT4MENUSIZE) &&
+ (parg16->f1 == ptd->ulLastDesktophDC) &&
+ ((hDCMenu = GetDC(NULL)) != NULL) &&
+ ((ncm.cbSize = sizeof(NONCLIENTMETRICS)) != 0) &&
+ (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, (PVOID)&ncm, 0)) &&
+ ((hFont = CreateFontIndirect(&(ncm.lfMenuFont))) != NULL)) {
+ hOldFont = SelectObject(hDCMenu, hFont);
+ hDC32 = hDCMenu;
+ }
+
+ ul = GETBOOL16(GetTextExtentPoint(hDC32,
+ lpString,
+ INT32(parg16->f3),
+ &Size));
+
+ if (hFont != NULL) {
+ SelectObject(hDCMenu, hOldFont);
+ DeleteObject(hFont);
+ }
+
+ if (hDCMenu != NULL) {
+ ReleaseDC(NULL, hDCMenu);
+ }
+
+ PUTEXTSIZE16(parg16->f4, &Size);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetViewportExtEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE Size;
+ register PGETVIEWPORTEXTEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETVIEWPORTEXTEX16), parg16);
+
+ ul = GETBOOL16(GetViewportExtEx(HDC32(parg16->f1), &Size));
+
+ PUTSIZE16(parg16->f2, &Size);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetViewportOrgEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT Point;
+ register PGETVIEWPORTORGEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETVIEWPORTORGEX16), parg16);
+
+ ul = GETBOOL16(GetViewportOrgEx(HDC32(parg16->f1), &Point));
+
+ PUTPOINT16(parg16->f2, &Point);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetWindowExtEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE Size;
+ register PGETWINDOWEXTEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWEXTEX16), parg16);
+
+ ul = GETBOOL16(GetWindowExtEx( HDC32(parg16->f1),&Size));
+
+ PUTSIZE16(parg16->f2, &Size);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32GetWindowOrgEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT Point;
+ register PGETWINDOWORGEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWORGEX16), parg16);
+
+ ul = GETBOOL16(GetWindowOrgEx(HDC32(parg16->f1), &Point));
+
+ PUTPOINT16(parg16->f2, &Point);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32IsGDIObject(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISGDIOBJECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISGDIOBJECT16), parg16);
+
+ // The Win31 isgdiobject returns the objecttype if handle is valid
+ // eventhough the return value is BOOL. So do the same
+ // - Nanduri
+
+ ul = (ULONG)GetObjectType(HOBJ32(parg16->f1));
+
+ FREEARGPTR(parg16);
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32MoveToEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT Point;
+ LPPOINT lpPoint = NULL;
+ register PMOVETOEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(MOVETOEX16), parg16);
+
+ if (parg16->f4) {
+ lpPoint = &Point;
+ }
+
+ ul = GETBOOL16(MoveToEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ lpPoint));
+ if (parg16->f4) {
+ PUTPOINT16(parg16->f4, lpPoint);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32OffsetViewportOrgEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT Point;
+ LPPOINT lpPoint = NULL;
+ register POFFSETVIEWPORTORGEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OFFSETVIEWPORTEX16), parg16);
+
+ if (parg16->f4) {
+ lpPoint = &Point;
+ }
+
+ ul = GETBOOL16(OffsetViewportOrgEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ lpPoint));
+
+ if (parg16->f4) {
+ PUTPOINT16(parg16->f4, lpPoint);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32OffsetWindowOrgEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT Point;
+ LPPOINT lpPoint = NULL;
+ register POFFSETWINDOWORGEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OFFSETWINDOWORGEX16), parg16);
+
+ if (parg16->f4) {
+ lpPoint = &Point;
+ }
+
+ ul = GETBOOL16(OffsetWindowOrgEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ lpPoint));
+
+ if (parg16->f4) {
+ PUTPOINT16(parg16->f4, lpPoint);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32ResetDC(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ LPDEVMODE lpInitData;
+ register PRESETDC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(RESETDC16), parg16);
+
+ if( lpInitData = ThunkDevMode16to32(FETCHDWORD(parg16->f2)) ) {
+
+ // send any buffered data streams.
+ if(CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_FORMFEEDHACK) {
+ SendFormFeedHack(HDC32(parg16->f1));
+ }
+
+ ul = GETHDC16(ResetDC(HDC32(parg16->f1), lpInitData));
+
+ FREEDEVMODE32(lpInitData);
+
+ }
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32ScaleViewportExtEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE Size;
+ LPSIZE lpSize = NULL;
+ register PSCALEVIEWPORTEXTEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SCALEVIEWPORTEXTEX16), parg16);
+
+ if (parg16->f6) {
+ lpSize = &Size;
+ }
+
+ ul = GETBOOL16(ScaleViewportExtEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ lpSize));
+ if (parg16->f6) {
+ PUTSIZE16(parg16->f6, lpSize);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32ScaleWindowExtEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE Size;
+ LPSIZE lpSize = NULL;
+ register PSCALEWINDOWEXTEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SCALEWINDOWEXTEX16), parg16);
+
+ if (parg16->f6) {
+ lpSize = &Size;
+ }
+
+ ul = GETBOOL16(ScaleWindowExtEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ lpSize));
+ if (parg16->f6) {
+ PUTSIZE16(parg16->f6, lpSize);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32SetAbortProc(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETABORTPROC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETABORTPROC16), parg16);
+
+ ((PTDB)SEGPTR(pFrame->wTDB, 0))->TDB_vpfnAbortProc = FETCHDWORD(parg16->f2);
+
+ ul = GETINT16(SetAbortProc(HDC32(parg16->f1), (ABORTPROC) W32AbortProc));
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32SetBitmapDimensionEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE Size;
+ LPSIZE lpSize = NULL;
+ register PSETBITMAPDIMENSIONEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETBITMAPDIMENSIONEX16), parg16);
+
+ if (parg16->f4) {
+ lpSize = &Size;
+ }
+
+ ul = GETBOOL16(SetBitmapDimensionEx(HBITMAP32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ lpSize));
+ if (parg16->f4) {
+ PUTSIZE16(parg16->f4, lpSize);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32SetBoundsRect(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ RECT rcBounds;
+ register PSETBOUNDSRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETBOUNDSRECT16), parg16);
+ GETRECT16(parg16->f2, &rcBounds);
+
+ ul = GETWORD16(SetBoundsRect(HDC32(parg16->f1),
+ &rcBounds,
+ WORD32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+#if 0 // implemented in gdi.exe
+
+ULONG FASTCALL WG32SetMetaFileBitsBetter(PVDMFRAME pFrame)
+{
+ return(WG32SetMetaFileBits(pFrame));
+}
+
+#endif
+
+ULONG FASTCALL WG32SetViewportExtEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE Size;
+ LPSIZE lpSize = NULL;
+ register PSETVIEWPORTEXTEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETVIEWPORTEXTEX16), parg16);
+
+ if (parg16->f4) {
+ lpSize = &Size;
+ }
+
+ ul = GETBOOL16(SetViewportExtEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ lpSize));
+
+ if (parg16->f4) {
+ PUTSIZE16(parg16->f4, lpSize);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32SetViewportOrgEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT Point;
+ LPPOINT lpPoint = NULL;
+ register PSETVIEWPORTORGEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETVIEWPORTORGEX16), parg16);
+
+ if (parg16->f4) {
+ lpPoint = &Point;
+ }
+
+ ul = GETBOOL16(SetViewportOrgEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ lpPoint));
+ if (parg16->f4) {
+ PUTPOINT16(parg16->f4, lpPoint);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32SetWindowExtEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SIZE Size;
+ LPSIZE lpSize = NULL;
+ register PSETWINDOWEXTEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWEXTEX16), parg16);
+
+ if (parg16->f4) {
+ lpSize = &Size;
+ }
+
+ ul = GETBOOL16(SetWindowExtEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ lpSize));
+ if (parg16->f4) {
+ PUTSIZE16(parg16->f4, lpSize);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32SetWindowOrgEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT Point;
+ LPPOINT lpPoint = NULL;
+ register PSETWINDOWORGEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWORGEX16), parg16);
+
+ if (parg16->f4) {
+ lpPoint = &Point;
+ }
+
+ ul = GETBOOL16(SetWindowOrgEx(HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ lpPoint));
+
+ if (parg16->f4) {
+ PUTPOINT16(parg16->f4, lpPoint);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32StartDoc(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ VPVOID vpDocName;
+ VPVOID vpOutput;
+ DOCINFO DocInfo;
+ LPDOCINFO16 pdi16;
+ register PSTARTDOC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(STARTDOC16), parg16);
+ GETVDMPTR(parg16->f2, sizeof(DOCINFO16), pdi16);
+
+ //
+ // Win32 StartDoc depends on having the correct current directory
+ // when printing to FILE: (which pops up for a filename).
+ //
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+ DocInfo.cbSize = sizeof(DOCINFO);
+
+ vpDocName = FETCHDWORD(pdi16->lpszDocName);
+ vpOutput = FETCHDWORD(pdi16->lpszOutput);
+
+ GETPSZPTR(vpDocName, DocInfo.lpszDocName);
+ GETPSZPTR(vpOutput, DocInfo.lpszOutput);
+
+ DocInfo.lpszDatatype = NULL;
+ DocInfo.fwType = 0;
+
+ FREEVDMPTR(pdi16);
+
+ ul = GETINT16(StartDoc(HDC32(parg16->f1), &DocInfo));
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_NOFIRSTSAVE) {
+ int l;
+ char szBuf[80];
+
+ if ((l = ExtEscape(HDC32(parg16->f1),
+ GETTECHNOLOGY,
+ 0,
+ NULL,
+ sizeof(szBuf),
+ szBuf)) > 0) {
+
+ if (!_stricmp(szBuf, szPostscript)) {
+ l = ExtEscape(HDC32(parg16->f1),
+ NOFIRSTSAVE,
+ 0,
+ NULL,
+ 0,
+ NULL);
+
+ // This HACK is for FH4.0 only. If you have any questions
+ // talk to PingW or ChandanC.
+ // July 21st 1994.
+ //
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_ADD_MSTT) {
+ l = ExtEscape(HDC32(parg16->f1),
+ ADD_MSTT,
+ 0,
+ NULL,
+ 0,
+ NULL);
+ }
+ }
+ }
+ }
+
+ FREEPSZPTR(DocInfo.lpszDocName);
+ FREEPSZPTR(DocInfo.lpszOutput);
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WG32StartPage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSTARTPAGE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(STARTPAGE16), parg16);
+
+ ul = GETINT16(StartPage(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+// InquireVisRgn is an undocumented Win 3.1 API. This code has been
+// suggested by ChuckWh. If this does not fix the FileMaker Pro 2.0
+// problem, then ChuckWh would be providing us with an private entry
+// point.
+// ChandanC 7th Feb 93
+//
+
+HRGN ghrgnVis = NULL;
+
+
+ULONG FASTCALL WG32InquireVisRgn(PVDMFRAME pFrame)
+{
+ register PINQUIREVISRGN16 parg16;
+ extern int GetRandomRgn(HDC hdc, HRGN hrgn, int cmd);
+
+ GETARGPTR(pFrame, sizeof(INQUIREVISRGN16), parg16);
+
+ // call special gdi entry point to get copy of vis rgn
+
+ GetRandomRgn(HDC32(parg16->f1), ghrgnVis, 4);
+
+ FREEARGPTR(parg16);
+
+ RETURN (GETHRGN16(ghrgnVis));
+}
+
+
+BOOL InitVisRgn()
+{
+ ghrgnVis = CreateRectRgn(0,0,0,0);
+
+ return(ghrgnVis != NULL);
+}
+
+
+VOID putabcpairs16(VPABC16 vpAbc, UINT cb, LPABC lpAbc)
+{
+ UINT i;
+ register PABC16 pAbc16;
+
+ GETVDMPTR(vpAbc, sizeof(ABC16), pAbc16);
+
+ for (i=0; i < cb; i++) {
+ pAbc16[i].abcA = (INT16) lpAbc[i].abcA;
+ pAbc16[i].abcB = (WORD) lpAbc[i].abcB;
+ pAbc16[i].abcC = (INT16) lpAbc[i].abcC;
+ }
+
+ FLUSHVDMPTR(vpAbc, sizeof(ABC16), pAbc16);
+ FREEVDMPTR(pAbc16);
+}
+
+
+ULONG FASTCALL WG32GetClipRgn(PVDMFRAME pFrame)
+{
+ register PGETCLIPRGN16 parg16;
+
+ // this is a private win3.1 entry pointed defined as HRGN GetClipRgn(HDC);
+ // NT exports the entry point defined as DWORD GetClipRgn(HDC,HRGN);
+ // NT will not give out the handle to its internal cliprgn so instead
+ // makes a copy. Any app uses this private win3.1 entry point will
+ // have a global region created for it that will go away when the
+ // app goes away.
+
+ GETARGPTR(pFrame, sizeof(GETCLIPRGN16), parg16);
+
+ if (CURRENTPTD()->hrgnClip == NULL)
+ CURRENTPTD()->hrgnClip = CreateRectRgn(0,0,0,0);
+
+ GetClipRgn(HDC32(parg16->f1), CURRENTPTD()->hrgnClip);
+
+ FREEARGPTR(parg16);
+
+ RETURN (GETHRGN16(CURRENTPTD()->hrgnClip));
+}
diff --git a/private/mvdm/wow32/wgdi31.h b/private/mvdm/wow32/wgdi31.h
new file mode 100644
index 000000000..0ce21d552
--- /dev/null
+++ b/private/mvdm/wow32/wgdi31.h
@@ -0,0 +1,107 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGDI31.H
+ * WOW32 16-bit Win 3.1 GDI API support
+ *
+ * History:
+ * Created 16-Mar-1992 by Chandan S. Chauhan (ChandanC)
+--*/
+
+#define PUTSIZE16(vp, lp) {\
+ PSIZE16 p16;\
+ GETVDMPTR(vp, sizeof(SIZE16), p16);\
+ STORESHORT(p16->cx, (lp)->cx);\
+ STORESHORT(p16->cy, (lp)->cy);\
+ FREEVDMPTR(p16);\
+ }
+
+#define PUTBUFFER16(vp, cb, lp) {\
+ LPSTR p16;\
+ GETVDMPTR(vp, sizeof(LPSTR), p16);\
+ RtlCopyMemory(p16, lp, cb);\
+ FREEVDMPTR(p16);\
+ }
+
+#define PUTRASTERIZERSTATUS16(vp, lp) {\
+ PRASTERIZER_STATUS16 p16;\
+ GETVDMPTR(vp, sizeof(RASTERIZER_STATUS16), p16);\
+ STORESHORT(p16->nSize, (lp)->nSize);\
+ STORESHORT(p16->wFlags, (lp)->wFlags);\
+ STORESHORT(p16->nLanguageID, (lp)->nLanguageID);\
+ FREEVDMPTR(p16);\
+ }
+
+#define PUTGLYPHMETRICS16(vp, lp) {\
+ PGLYPHMETRICS16 p16;\
+ GETVDMPTR(vp, sizeof(GLYPHMETRICS16), p16);\
+ STOREWORD(p16->gmBlackBoxX, (lp)->gmBlackBoxX);\
+ STOREWORD(p16->gmBlackBoxY, (lp)->gmBlackBoxY );\
+ STORESHORT(p16->gmptGlyphOrigin.x, (lp)->gmptGlyphOrigin.x);\
+ STORESHORT(p16->gmptGlyphOrigin.y, (lp)->gmptGlyphOrigin.y);\
+ STORESHORT(p16->gmCellIncX, (lp)->gmCellIncX);\
+ STORESHORT(p16->gmCellIncY, (lp)->gmCellIncY);\
+ FREEVDMPTR(p16);\
+ }
+
+#define GETMAT2(vp, lp) {\
+ PMAT216 p16;\
+ GETVDMPTR(vp, sizeof(MAT216), p16);\
+ (lp)->eM11.fract = FETCHWORD(p16->eM11.fract);\
+ (lp)->eM11.value = FETCHSHORT(p16->eM11.value);\
+ (lp)->eM12.fract = FETCHWORD(p16->eM12.fract);\
+ (lp)->eM12.value = FETCHSHORT(p16->eM12.value);\
+ (lp)->eM21.fract = FETCHWORD(p16->eM21.fract);\
+ (lp)->eM21.value = FETCHSHORT(p16->eM21.value);\
+ (lp)->eM22.fract = FETCHWORD(p16->eM22.fract);\
+ (lp)->eM22.value = FETCHSHORT(p16->eM22.value);\
+ FREEVDMPTR(p16);\
+ }
+
+
+ULONG FASTCALL WG32AbortDoc(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateScalableFontResource(PVDMFRAME pFrame);
+ULONG FASTCALL WG32EndDoc(PVDMFRAME pFrame);
+ULONG FASTCALL WG32EndPage(PVDMFRAME pFrame);
+ULONG FASTCALL WG32EnumFontFamilies(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetAspectRatioFilterEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetBitmapDimensionEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetBoundsRect(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetBrushOrgEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetCharABCWidths(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetCurrentPositionEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetFontData(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetGlyphOutline(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetKerningPairs(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetOutlineTextMetrics(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetRasterizerCaps(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetTextExtentPoint(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetViewportExtEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetViewportOrgEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetWindowExtEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetWindowOrgEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32IsGDIObject(PVDMFRAME pFrame);
+ULONG FASTCALL WG32MoveToEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32OffsetViewportOrgEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32OffsetWindowOrgEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32ResetDC(PVDMFRAME pFrame);
+ULONG FASTCALL WG32ScaleViewportExtEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32ScaleWindowExtEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetAbortProc(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetBitmapDimensionEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetBoundsRect(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetMetaFileBitsBetter(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetViewportExtEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetViewportOrgEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetWindowExtEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetWindowOrgEx(PVDMFRAME pFrame);
+ULONG FASTCALL WG32StartDoc(PVDMFRAME pFrame);
+ULONG FASTCALL WG32StartPage(PVDMFRAME pFrame);
+VOID putabcpairs16(VPABC16 vpAbc, UINT c, LPABC lpAbc);
+
+ULONG FASTCALL WG32InquireVisRgn(PVDMFRAME pFrame);
+BOOL InitVisRgn();
+ULONG FASTCALL WG32GetClipRgn(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wgfont.c b/private/mvdm/wow32/wgfont.c
new file mode 100644
index 000000000..eabb77bb2
--- /dev/null
+++ b/private/mvdm/wow32/wgfont.c
@@ -0,0 +1,466 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGFONT.C
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wingdip.h"
+
+MODNAME(wgfont.c);
+
+extern int RemoveFontResourceTracking(LPCSTR psz, UINT id);
+extern int AddFontResourceTracking(LPCSTR psz, UINT id);
+
+
+// a.k.a. WOWAddFontResource
+ULONG FASTCALL WG32AddFontResource(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ register PADDFONTRESOURCE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ADDFONTRESOURCE16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+
+ // note: we will never get an hModule in the low word here.
+ // the 16-bit side resolves hModules to an lpsz before calling us
+
+ if( CURRENTPTD()->dwWOWCompatFlags & WOWCF_UNLOADNETFONTS )
+ {
+ ul = GETINT16(AddFontResourceTracking(psz1,(UINT)CURRENTPTD()));
+ }
+ else
+ {
+ ul = GETINT16(AddFontResourceA(psz1));
+ }
+
+ FREEPSZPTR(psz1);
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+#define PITCH_MASK ( FIXED_PITCH | VARIABLE_PITCH )
+
+ULONG FASTCALL WG32CreateFont(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz14;
+ register PCREATEFONT16 parg16;
+ INT iWidth;
+ char achCapString[LF_FACESIZE];
+ BYTE lfCharSet;
+ BYTE lfPitchAndFamily;
+
+ GETARGPTR(pFrame, sizeof(CREATEFONT16), parg16);
+ GETPSZPTR(parg16->f14, psz14);
+
+ // take careof compatiblity flags:
+ // if a specific width is specified and GACF_30AVGWIDTH compatiblity
+ // flag is set, scaledown the width by 7/8.
+ //
+
+ iWidth = INT32(parg16->f2);
+ if (iWidth != 0 &&
+ (W32GetAppCompatFlags((HAND16)NULL) & GACF_30AVGWIDTH)) {
+ iWidth = (iWidth * 7) / 8;
+ }
+
+ lfCharSet = BYTE32(parg16->f9);
+ lfPitchAndFamily = BYTE32(parg16->f13);
+
+ if (psz14)
+ {
+ // Capitalize the string for faster compares.
+
+ strncpy(achCapString, psz14, LF_FACESIZE);
+ _strupr(achCapString);
+
+ // Here we are going to implement a bunch of Win 3.1 hacks rather
+ // than contaminate the 32-bit engine. These same hacks can be found
+ // in WOW (in the CreateFont/CreateFontIndirect code).
+ //
+ // These hacks are keyed off the facename in the LOGFONT. String
+ // comparisons have been unrolled for maximal performance.
+
+ // Win 3.1 facename-based hack. Some apps, like
+ // Publisher, create a "Helv" font but have the lfPitchAndFamily
+ // set to specify FIXED_PITCH. To work around this, we will patch
+ // the pitch field for a "Helv" font to be variable.
+
+ if ( !strcmp(achCapString, szHelv) )
+ {
+ lfPitchAndFamily |= ( (lfPitchAndFamily & ~PITCH_MASK) | VARIABLE_PITCH );
+ }
+ else
+ {
+ // Win 3.1 hack for Legacy 2.0. When a printer does not enumerate
+ // a "Tms Rmn" font, the app enumerates and gets the LOGFONT for
+ // "Script" and then create a font with the name "Tms Rmn" but with
+ // the lfCharSet and lfPitchAndFamily taken from the LOGFONT for
+ // "Script". Here we will over the lfCharSet to be ANSI_CHARSET.
+
+ if ( !strcmp(achCapString, szTmsRmn) )
+ {
+ lfCharSet = ANSI_CHARSET;
+ }
+ else
+ {
+ // If the lfFaceName is "Symbol", "Zapf Dingbats", or "ZapfDingbats",
+ // enforce lfCharSet to be SYMBOL_CHARSET. Some apps (like Excel) ask
+ // for a "Symbol" font but have the char set set to ANSI. PowerPoint
+ // has the same problem with "Zapf Dingbats".
+
+ if ( !strcmp(achCapString, szSymbol) ||
+ !strcmp(achCapString, szZapfDingbats) ||
+ !strcmp(achCapString, szZapf_Dingbats) )
+ {
+ lfCharSet = SYMBOL_CHARSET;
+ }
+ }
+ }
+
+ // Win3.1(Win95) hack for Mavis Beacon Teaches Typing 3.0
+ // The app uses a fixed width of 34*13 for the typing screen.
+ // NT returns 14 from GetTextExtent for Mavis Beacon Courier FP font (width of 14)
+ // while Win95 returns 13, thus long strings won't fit in the typing screen on NT.
+ // Force the width to 13.
+
+ if ( iWidth==14 && (INT32(parg16->f1)== 20) && !strcmp(achCapString, szMavisCourier))
+ {
+ iWidth = 13;
+ }
+ }
+
+ ul = GETHFONT16(CreateFont(INT32(parg16->f1),
+ iWidth,
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ BYTE32(parg16->f6),
+ BYTE32(parg16->f7),
+ BYTE32(parg16->f8),
+ lfCharSet,
+ BYTE32(parg16->f10),
+ BYTE32(parg16->f11),
+ BYTE32(parg16->f12),
+ lfPitchAndFamily,
+ psz14));
+ FREEPSZPTR(psz14);
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateFontIndirect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LOGFONT logfont;
+ register PCREATEFONTINDIRECT16 parg16;
+ char achCapString[LF_FACESIZE];
+
+ GETARGPTR(pFrame, sizeof(CREATEFONTINDIRECT16), parg16);
+ GETLOGFONT16(parg16->f1, &logfont);
+
+ // Capitalize the string for faster compares.
+
+ strncpy(achCapString, logfont.lfFaceName, LF_FACESIZE);
+ CharUpperBuff(achCapString, LF_FACESIZE);
+
+ // Here we are going to implement a bunch of Win 3.1 hacks rather
+ // than contaminate the 32-bit engine. These same hacks can be found
+ // in WOW (in the CreateFont/CreateFontIndirect code).
+ //
+ // These hacks are keyed off the facename in the LOGFONT. String
+ // comparisons have been unrolled for maximal performance.
+
+ // Win 3.1 facename-based hack. Some apps, like
+ // Publisher, create a "Helv" font but have the lfPitchAndFamily
+ // set to specify FIXED_PITCH. To work around this, we will patch
+ // the pitch field for a "Helv" font to be variable.
+
+ if ( !strcmp(achCapString, szHelv) )
+ {
+ logfont.lfPitchAndFamily |= ( (logfont.lfPitchAndFamily & ~PITCH_MASK) | VARIABLE_PITCH );
+ }
+ else
+ {
+ // Win 3.1 hack for Legacy 2.0. When a printer does not enumerate
+ // a "Tms Rmn" font, the app enumerates and gets the LOGFONT for
+ // "Script" and then create a font with the name "Tms Rmn" but with
+ // the lfCharSet and lfPitchAndFamily taken from the LOGFONT for
+ // "Script". Here we will over the lfCharSet to be ANSI_CHARSET.
+
+ if ( !strcmp(achCapString, szTmsRmn) )
+ {
+ logfont.lfCharSet = ANSI_CHARSET;
+ }
+ else
+ {
+ // If the lfFaceName is "Symbol", "Zapf Dingbats", or "ZapfDingbats",
+ // enforce lfCharSet to be SYMBOL_CHARSET. Some apps (like Excel) ask
+ // for a "Symbol" font but have the char set set to ANSI. PowerPoint
+ // has the same problem with "Zapf Dingbats".
+
+ if ( !strcmp(achCapString, szSymbol) ||
+ !strcmp(achCapString, szZapfDingbats) ||
+ !strcmp(achCapString, szZapf_Dingbats) )
+ {
+ logfont.lfCharSet = SYMBOL_CHARSET;
+ }
+ }
+ }
+
+ ul = GETHFONT16(CreateFontIndirect(&logfont));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+LPSTR lpMSSansSerif = "MS Sans Serif";
+LPSTR lpMSSerif = "MS Serif";
+
+INT W32EnumFontFunc(LPENUMLOGFONT pEnumLogFont,
+ LPNEWTEXTMETRIC pNewTextMetric, INT nFontType, PFNTDATA pFntData)
+{
+ INT iReturn;
+ PARM16 Parm16;
+ LPSTR lpFaceNameT = NULL;
+
+ WOW32ASSERT(pFntData);
+
+ // take care of compatibility flags:
+ // ORin DEVICE_FONTTYPE bit if the fonttype is truetype and the
+ // Compataibility flag GACF_CALLTTDEVICE is set.
+ //
+
+ if (nFontType & TRUETYPE_FONTTYPE) {
+ if (W32GetAppCompatFlags((HAND16)NULL) & GACF_CALLTTDEVICE) {
+ nFontType |= DEVICE_FONTTYPE;
+ }
+ }
+
+ // take care of compatibility flags:
+ // replace Ms Sans Serif with Helv and
+ // replace Ms Serif with Tms Rmn
+ //
+ // only if the facename is NULL and the compat flag GACF_ENUMHELVNTMSRMN
+ // is set.
+
+ if (pFntData->vpFaceName == (VPVOID)NULL) {
+ if (W32GetAppCompatFlags((HAND16)NULL) & GACF_ENUMHELVNTMSRMN) {
+ if (!strcmp(pEnumLogFont->elfLogFont.lfFaceName, lpMSSansSerif)) {
+ strcpy(pEnumLogFont->elfLogFont.lfFaceName, "Helv");
+ lpFaceNameT = lpMSSansSerif;
+ }
+ else if (!strcmp(pEnumLogFont->elfLogFont.lfFaceName, lpMSSerif)) {
+ strcpy(pEnumLogFont->elfLogFont.lfFaceName, "Tms Rmn");
+ lpFaceNameT = lpMSSerif;
+ }
+ }
+ }
+
+CallAgain:
+ pFntData->vpLogFont = stackalloc16(sizeof(ENUMLOGFONT16)+sizeof(NEWTEXTMETRIC16));
+ pFntData->vpTextMetric = (VPVOID)((LPSTR)pFntData->vpLogFont + sizeof(ENUMLOGFONT16));
+
+ PUTENUMLOGFONT16(pFntData->vpLogFont, pEnumLogFont);
+ PUTNEWTEXTMETRIC16(pFntData->vpTextMetric, pNewTextMetric);
+
+ STOREDWORD(Parm16.EnumFontProc.vpLogFont, pFntData->vpLogFont);
+ STOREDWORD(Parm16.EnumFontProc.vpTextMetric, pFntData->vpTextMetric);
+ STOREDWORD(Parm16.EnumFontProc.vpData,pFntData->dwUserFntParam);
+
+ Parm16.EnumFontProc.nFontType = (SHORT)nFontType;
+
+ CallBack16(RET_ENUMFONTPROC, &Parm16, pFntData->vpfnEnumFntProc, (PVPVOID)&iReturn);
+
+ if (((SHORT)iReturn) && lpFaceNameT) {
+ // if the callback returned true, now call with the actual facename
+ // Just to be sure, we again copy all the data for callback. This will
+ // take care of any apps which modify the passed in structures.
+
+ strcpy(pEnumLogFont->elfLogFont.lfFaceName, lpFaceNameT);
+ lpFaceNameT = (LPSTR)NULL;
+ goto CallAgain;
+ }
+ return (SHORT)iReturn;
+}
+
+
+ULONG W32EnumFontHandler( PVDMFRAME pFrame, BOOL fEnumFontFamilies )
+{
+ ULONG ul = 0;
+ PSZ psz2;
+ FNTDATA FntData;
+ register PENUMFONTS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENUMFONTS16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+
+ FntData.vpfnEnumFntProc = DWORD32(parg16->f3);
+ FntData.dwUserFntParam = DWORD32(parg16->f4);
+ FntData.vpFaceName = DWORD32(parg16->f2);
+
+
+ if ( fEnumFontFamilies ) {
+ ul = GETINT16(EnumFontFamilies(HDC32(parg16->f1),
+ psz2,
+ (FONTENUMPROC)W32EnumFontFunc,
+ (LPARAM)&FntData));
+ } else {
+ ul = GETINT16(EnumFonts(HDC32(parg16->f1),
+ psz2,
+ (FONTENUMPROC)W32EnumFontFunc,
+ (LPARAM)&FntData));
+ }
+
+
+
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WG32EnumFonts(PVDMFRAME pFrame)
+{
+ return( W32EnumFontHandler( pFrame, FALSE ) );
+}
+
+
+
+ULONG FASTCALL WG32GetAspectRatioFilter(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ SIZE size2;
+ register PGETASPECTRATIOFILTER16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETASPECTRATIOFILTER16), parg16);
+
+ if (GETDWORD16(GetAspectRatioFilterEx(HDC32(parg16->f1), &size2))) {
+ ul = (WORD)size2.cx | (size2.cy << 16);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetCharWidth(PVDMFRAME pFrame)
+{
+ ULONG ul = 0L;
+ INT ci;
+ PINT pi4;
+ register PGETCHARWIDTH16 parg16;
+ INT BufferT[256];
+
+ GETARGPTR(pFrame, sizeof(GETCHARWIDTH16), parg16);
+
+ ci = WORD32(parg16->wLastChar) - WORD32(parg16->wFirstChar) + 1;
+ pi4 = STACKORHEAPALLOC(ci * sizeof(INT), sizeof(BufferT), BufferT);
+
+ if (pi4) {
+ ULONG ulLast = WORD32(parg16->wLastChar);
+ if (ulLast > 0xff)
+ ulLast = 0xff;
+
+ ul = GETBOOL16(GetCharWidth(HDC32(parg16->hDC),
+ WORD32(parg16->wFirstChar),
+ ulLast,
+ pi4));
+
+ PUTINTARRAY16(parg16->lpIntBuffer, ci, pi4);
+ STACKORHEAPFREE(pi4, BufferT);
+
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+// a.k.a. WOWRemoveFontResource
+ULONG FASTCALL WG32RemoveFontResource(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ register PREMOVEFONTRESOURCE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(REMOVEFONTRESOURCE16), parg16);
+
+ GETPSZPTR(parg16->f1, psz1);
+
+ // note: we will never get an hModule in the low word here.
+ // the 16-bit side resolves hModules to an lpsz before calling us
+
+
+ if( CURRENTPTD()->dwWOWCompatFlags & WOWCF_UNLOADNETFONTS )
+ {
+ ul = GETBOOL16(RemoveFontResourceTracking(psz1,(UINT)CURRENTPTD()));
+ }
+ else
+ {
+ ul = GETBOOL16(RemoveFontResource(psz1));
+ }
+
+ FREEPSZPTR(psz1);
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+/* WG32GetCurLogFont
+ *
+ * This thunk implements the undocumented Win3.0 and Win3.1 API
+ * GetCurLogFont (GDI.411). Symantec QA4.0 uses it.
+ *
+ * HFONT GetCurLogFont (HDC)
+ * HDC hDC; // Device Context
+ *
+ * This function returns the current Logical font selected for the
+ * specified device context.
+ *
+ * To implement this undocumented API we will use the NT undocumented API
+ * GetHFONT.
+ *
+ * SudeepB 08-Mar-1996
+ *
+ */
+
+extern HFONT APIENTRY GetHFONT (HDC hdc);
+
+ULONG FASTCALL WG32GetCurLogFont(PVDMFRAME pFrame)
+{
+
+ ULONG ul;
+ register PGETCURLOGFONT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCURLOGFONT16), parg16);
+
+ ul = GETHFONT16 (GetHFONT(HDC32 (parg16->hDC)));
+
+ FREEARGPTR(parg16);
+
+ return (ul);
+}
diff --git a/private/mvdm/wow32/wgfont.h b/private/mvdm/wow32/wgfont.h
new file mode 100644
index 000000000..82bcfa3c9
--- /dev/null
+++ b/private/mvdm/wow32/wgfont.h
@@ -0,0 +1,43 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGFONT.H
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+/* Enumeration handler data
+ */
+typedef struct _FNTDATA { /* fntdata */
+ VPPROC vpfnEnumFntProc; // 16-bit enumeration function
+ DWORD dwUserFntParam; // user param, if any
+ HMEM16 hLogFont; //
+ VPVOID vpLogFont; // 16-bit storage for logical font
+ HMEM16 hTextMetric; //
+ VPVOID vpTextMetric; // 16-bit storage for textmetric structure
+ VPVOID vpFaceName; // 16bit far ptr - input to Enum Fonts & Families
+} FNTDATA, *PFNTDATA;
+
+
+/* Function prototypes
+ */
+ULONG FASTCALL WG32AddFontResource(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateFont(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateFontIndirect(PVDMFRAME pFrame);
+
+INT W32FontFunc(LPLOGFONT pLogFont,
+ LPTEXTMETRIC pTextMetrics, INT nFontType, PFNTDATA pFntData);
+
+ULONG FASTCALL WG32EnumFonts(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetAspectRatioFilter(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetCharWidth(PVDMFRAME pFrame);
+ULONG FASTCALL WG32RemoveFontResource(PVDMFRAME pFrame);
+
+ULONG W32EnumFontHandler( PVDMFRAME pFrame, BOOL fEnumFontFamilies );
+
diff --git a/private/mvdm/wow32/wgman.c b/private/mvdm/wow32/wgman.c
new file mode 100644
index 000000000..5cee5b105
--- /dev/null
+++ b/private/mvdm/wow32/wgman.c
@@ -0,0 +1,18 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGMAN.C
+ * WOW32 16-bit GDI API support (manually-coded thunks)
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wgman.c);
diff --git a/private/mvdm/wow32/wgman.h b/private/mvdm/wow32/wgman.h
new file mode 100644
index 000000000..0ec87f7dc
--- /dev/null
+++ b/private/mvdm/wow32/wgman.h
@@ -0,0 +1,12 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGMAN.H
+ * WOW32 16-bit GDI API support (manually-coded thunks)
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
diff --git a/private/mvdm/wow32/wgmeta.c b/private/mvdm/wow32/wgmeta.c
new file mode 100644
index 000000000..44fa11e8f
--- /dev/null
+++ b/private/mvdm/wow32/wgmeta.c
@@ -0,0 +1,562 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGMETA.C
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wgmeta.c);
+
+typedef METAHEADER UNALIGNED *PMETAHEADER16;
+
+
+
+
+// WARNING: This function may cause 16-bit memory to move
+VOID CopyMetaFile16FromHMF32(HAND16 hMF16, HMETAFILE hMF32)
+{
+ UINT cbMF32, cbMF16;
+ VPVOID vp;
+ PBYTE pMF16;
+
+
+ if((vp = GlobalLock16(hMF16, &cbMF16)) && hMF32) {
+
+ GETMISCPTR(vp, pMF16);
+
+ cbMF32 = GetMetaFileBitsEx(hMF32, 0, NULL);
+
+ // Verify these are the same size within the 16-bit kernel memory
+ // allocation granularity
+ WOW32WARNMSGF((abs(cbMF16 - cbMF32) < 32),
+ ("WOW32: Size MF16 = %lu MF32 = %lu\n", cbMF16, cbMF32));
+
+ // copy the bits from the 32-bit metafile to the 16-bit metafile memory
+ cbMF32 = GetMetaFileBitsEx(hMF32, min(cbMF16, cbMF32), pMF16);
+
+ GlobalUnlock16(hMF16);
+ FLUSHVDMPTR(vp, cbMF32, pMF16);
+ FREEMISCPTR(pMF16);
+ }
+}
+
+
+
+
+// WARNING: This function may cause 16-bit memory to move
+HAND16 WinMetaFileFromHMF(HMETAFILE hmf, BOOL fFreeOriginal)
+{
+ UINT cbMetaData;
+ VPVOID vpMetaData;
+ PBYTE pMetaData;
+ HAND16 h16;
+
+ /*
+ * Under Windows Metafiles were merely Global Handle to memory
+ * so we have to mimick that behavior because some apps "operate"
+ * on metafile handles directly. (WinWord and PowerPoint to
+ * GlobalSize and GlobalAlloc to size and create metafiles)
+ */
+
+ cbMetaData = GetMetaFileBitsEx(hmf, 0, NULL);
+
+ if (!cbMetaData)
+ return((HAND16)NULL);
+
+ /*
+ * Win 3.1 allocates extra space in MetaFile and OLE2 checks for this.
+ * METAHEADER is defined to be the same size as the 16-bit structure.
+ */
+
+ cbMetaData += sizeof(METAHEADER);
+
+ vpMetaData = GlobalAllocLock16(GMEM_MOVEABLE | GMEM_DDESHARE, cbMetaData, &h16);
+
+ if (!vpMetaData)
+ return((HAND16)NULL);
+
+
+ GETOPTPTR(vpMetaData, 0, pMetaData);
+
+ if (GetMetaFileBitsEx(hmf, cbMetaData, pMetaData)) {
+ GlobalUnlock16(h16);
+ } else {
+ GlobalUnlockFree16(vpMetaData);
+ return((HAND16)NULL);
+ }
+
+ if (fFreeOriginal)
+ DeleteMetaFile(hmf);
+
+ return(h16);
+}
+
+HMETAFILE HMFFromWinMetaFile(HAND16 h16, BOOL fFreeOriginal)
+{
+ INT cb;
+ VPVOID vp;
+ HMETAFILE hmf = (HMETAFILE)0;
+ PMETAHEADER16 pMFH16;
+
+ vp = GlobalLock16(h16, &cb);
+
+ if (vp) {
+ GETMISCPTR(vp, pMFH16);
+
+ hmf = SetMetaFileBitsEx(cb, (LPBYTE)pMFH16);
+
+ if (fFreeOriginal)
+ GlobalUnlockFree16(vp);
+ else
+ GlobalUnlock16(h16);
+
+ FREEMISCPTR(pMFH16);
+ }
+
+ return(hmf);
+}
+
+
+ULONG FASTCALL WG32CloseMetaFile(PVDMFRAME pFrame)
+{
+ HMETAFILE hmf;
+ ULONG ulRet = 0;
+ register PCLOSEMETAFILE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CLOSEMETAFILE16), parg16);
+
+ hmf = CloseMetaFile(HDC32(parg16->f1));
+
+ if (hmf)
+ ulRet = (ULONG)WinMetaFileFromHMF(hmf, TRUE);
+ // WARNING: 16-bit memory may have moved - invalidate flat pointers now
+ FREEVDMPTR(pFrame);
+ FREEARGPTR(parg16);
+ RETURN(ulRet);
+}
+
+
+ULONG FASTCALL WG32CopyMetaFile(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ HMETAFILE hmfNew;
+ HMETAFILE hmf;
+ register PCOPYMETAFILE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(COPYMETAFILE16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+
+ if (psz2) {
+ hmf = HMFFromWinMetaFile(parg16->f1, FALSE);
+ hmfNew = CopyMetaFile(hmf, psz2);
+ DeleteMetaFile(hmf);
+ ul = (ULONG)WinMetaFileFromHMF(hmfNew, TRUE);
+ // WARNING: 16-bit memory may have moved - invalidate flat pointers now
+ FREEVDMPTR(pFrame);
+ FREEARGPTR(parg16);
+ FREEPSZPTR(psz2);
+ } else {
+ UINT cb;
+ VPVOID vp, vpNew;
+ PBYTE pMF, pMFNew;
+ HAND16 h16New, h16;
+
+ h16 = (HAND16)parg16->f1;
+
+ ul = (ULONG) NULL;
+
+ vp = GlobalLock16(h16, &cb);
+ if (vp) {
+
+ /*
+ * Windows app such as WinWord uses GlobalSize to determine
+ * the size of the metafile. However, this size can be larger
+ * than the true size of a metafile. We have to make sure that
+ * both source and destination sizes are identical so that
+ * WinWord doesn't crash.
+ */
+
+ vpNew = GlobalAllocLock16(GMEM_MOVEABLE | GMEM_DDESHARE, cb, &h16New);
+
+ // 16-bit memory may have moved - invalidate flat pointers now
+ FREEVDMPTR(pFrame);
+ FREEARGPTR(parg16);
+ FREEPSZPTR(psz2);
+
+ if (vpNew) {
+ GETMISCPTR(vp, pMF);
+ GETOPTPTR(vpNew, 0, pMFNew);
+
+ RtlCopyMemory(pMFNew, pMF, cb);
+
+ GlobalUnlock16(h16New);
+ FLUSHVDMPTR(vpNew, cb, pMFNew);
+ FREEOPTPTR(pMFNew);
+ ul = h16New;
+ }
+
+ GlobalUnlock16(h16);
+ FREEMISCPTR(pMF);
+ }
+ }
+
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CreateMetaFile(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ register PCREATEMETAFILE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEMETAFILE16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+
+ ul = GETHDC16(CreateMetaFile(psz1));
+
+ FREEPSZPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+//
+// This routine does what the 16-bit parameter validation layer would
+// normally do for metafile handles, but since it is currently disabled,
+// we'll do it here to fix WordPerfect that relies on it. Once true
+// win31-style parameter validation has been re-enabled for metafile
+// handles, all code within the ifndefs here and in WG32DeleteMetaFile
+// can be removed.
+//
+#ifndef PARAMETER_VALIDATION_16_RE_ENABLED
+#define MEMORYMETAFILE 1
+#define DISKMETAFILE 2
+#define HEADERSIZE (sizeof(METAHEADER)/sizeof(WORD))
+#define METAVERSION 0x0300
+#define METAVERSION100 0x0100
+
+BOOL IsValidMetaFile16(PMETAHEADER16 lpMetaData)
+{
+ BOOL sts = FALSE;
+
+ sts = (lpMetaData->mtType == MEMORYMETAFILE ||
+ lpMetaData->mtType == DISKMETAFILE) &&
+ (lpMetaData->mtHeaderSize == HEADERSIZE) &&
+ ((lpMetaData->mtVersion ==METAVERSION) ||
+ (lpMetaData->mtVersion ==METAVERSION100)) ;
+ return sts;
+}
+#endif
+
+ULONG FASTCALL WG32DeleteMetaFile(PVDMFRAME pFrame)
+{
+ ULONG ul = FALSE;
+ VPVOID vp;
+#ifndef PARAMETER_VALIDATION_16_RE_ENABLED
+ PMETAHEADER16 lpMetaData;
+#endif
+
+ register PDELETEMETAFILE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DELETEMETAFILE16), parg16);
+
+ if (vp = GlobalLock16(parg16->f1,NULL)) {
+#ifdef PARAMETER_VALIDATION_16_RE_ENABLED
+ GlobalUnlockFree16(vp);
+ ul = TRUE;
+#else
+ GETVDMPTR(vp, 1, lpMetaData);
+
+ if (IsValidMetaFile16(lpMetaData)) {
+ GlobalUnlockFree16(vp);
+ ul = TRUE;
+ }
+
+ FREEVDMPTR(lpMetaData);
+#endif
+ }
+
+
+ // If this metafile was in DDE conversation, then DDE cleanup code
+ // needs to free its 32 bit counter part. So give DDE clean up
+ // code a chance.
+ // ChandanC
+
+ W32DdeFreeHandle16 (parg16->f1);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+INT WG32EnumMetaFileCallBack(HDC hdc, LPHANDLETABLE lpht, LPMETARECORD lpMR, LONG nObj, PMETADATA pMetaData )
+{
+ INT iReturn;
+ DWORD nWords;
+
+ // update object table if we have one
+ if (pMetaData->parmemp.vpHandleTable)
+ PUTHANDLETABLE16(pMetaData->parmemp.vpHandleTable,nObj,lpht);
+
+ // update MetaRecord
+
+ // don't trash the heap with a bogus record, halt the enumeration
+ nWords = lpMR->rdSize;
+ if (nWords > pMetaData->mtMaxRecordSize) {
+ LOGDEBUG(0,("WOW:bad metafile record during enumeration\n"));
+ WOW32ASSERT(FALSE); // contact barryb
+ return 0; // all done
+ }
+ putstr16(pMetaData->parmemp.vpMetaRecord, (LPSZ)lpMR, nWords*sizeof(WORD));
+
+ CallBack16(RET_ENUMMETAFILEPROC, (PPARM16)&pMetaData->parmemp, pMetaData->vpfnEnumMetaFileProc, (PVPVOID)&iReturn);
+
+ // update the metarec in case the app altered it (Approach does)
+ getstr16(pMetaData->parmemp.vpMetaRecord, (LPSZ)lpMR, nWords*sizeof(WORD));
+
+ // update object table if we have one
+ if (pMetaData->parmemp.vpHandleTable)
+ GETHANDLETABLE16(pMetaData->parmemp.vpHandleTable,nObj,lpht);
+
+ return (SHORT)iReturn;
+
+ hdc; // quiet the compilier; we already know the DC
+}
+
+ULONG FASTCALL WG32EnumMetaFile(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PENUMMETAFILE16 parg16;
+ METADATA metadata;
+ VPVOID vpMetaFile = (VPVOID) NULL;
+ PBYTE pMetaFile;
+ HMETAFILE hmf = (HMETAFILE) 0;
+ HAND16 hMetaFile16;
+ HDC hDC = 0;
+
+ GETARGPTR(pFrame, sizeof(ENUMMETAFILE16), parg16);
+
+ hMetaFile16 = parg16->f2;
+
+ metadata.vpfnEnumMetaFileProc = DWORD32(parg16->f3);
+ metadata.parmemp.vpData = (VPVOID)DWORD32(parg16->f4);
+ metadata.parmemp.vpMetaRecord = (VPVOID) NULL;
+ metadata.parmemp.vpHandleTable = (VPVOID) NULL;
+ metadata.parmemp.hdc = parg16->f1;
+
+ // WinWord never calls SetMetaFileBits; they peeked and know that
+ // a metafile is really a GlobalHandle in Windows so we have
+ // to look for that case.
+
+ hmf = HMFFromWinMetaFile(hMetaFile16, FALSE);
+ if (!hmf)
+ goto EMF_Exit;
+
+ // Get the metafile bits so we can get max record size and number of objects
+
+ vpMetaFile = GlobalLock16(hMetaFile16, NULL);
+ FREEARGPTR(parg16); // memory may have moved
+ FREEVDMPTR(pFrame);
+ if (!vpMetaFile)
+ goto EMF_Exit;
+
+ GETOPTPTR(vpMetaFile, 0, pMetaFile);
+ if (!pMetaFile)
+ goto EMF_Exit;
+
+ metadata.parmemp.nObjects = ((PMETAHEADER16)pMetaFile)->mtNoObjects;
+ metadata.mtMaxRecordSize = ((PMETAHEADER16)pMetaFile)->mtMaxRecord;
+
+ if (metadata.parmemp.nObjects)
+ {
+ PBYTE pHT;
+ DWORD cb = ((PMETAHEADER16)pMetaFile)->mtNoObjects*sizeof(HAND16);
+
+ metadata.parmemp.vpHandleTable = GlobalAllocLock16(GMEM_MOVEABLE, cb, NULL);
+ FREEOPTPTR(pMetaFile); // memory may have moved
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ if (!metadata.parmemp.vpHandleTable)
+ goto EMF_Exit;
+
+ GETOPTPTR(metadata.parmemp.vpHandleTable, 0, pHT);
+ RtlZeroMemory(pHT, cb);
+ }
+
+ metadata.parmemp.vpMetaRecord = GlobalAllocLock16(GMEM_MOVEABLE, metadata.mtMaxRecordSize*sizeof(WORD), NULL);
+ FREEOPTPTR(pMetaFile); // memory may have moved
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ if (!metadata.parmemp.vpMetaRecord)
+ goto EMF_Exit;
+
+ // Corel Draw passes a NULL hDC, we'll create a dummy to keep GDI32 happy.
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_GETDUMMYDC) {
+ if ((hDC = HDC32(metadata.parmemp.hdc)) == 0) {
+ hDC = CreateMetaFile(NULL);
+ }
+ }
+ else {
+ hDC = HDC32(metadata.parmemp.hdc);
+ }
+
+ ul = GETBOOL16(EnumMetaFile(hDC,
+ hmf,
+ (MFENUMPROC)WG32EnumMetaFileCallBack,
+ ((LPARAM)(LPVOID)&metadata)));
+ // 16-bit memory may have moved - nothing to do as no flat ptrs exist now
+
+ // copy the 32-bit metafile back to 16-bit land (the app may have altered
+ // some of the metarecs in its MetaRecCallBackFunc -- Approach does)
+ CopyMetaFile16FromHMF32(hMetaFile16, hmf);
+
+ // Cleanup the dummy hDC created for Corel Draw 5.0.
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_GETDUMMYDC) {
+ if (HDC32(metadata.parmemp.hdc) == 0) {
+ DeleteMetaFile(CloseMetaFile(hDC));
+ }
+ }
+
+EMF_Exit:
+ if (vpMetaFile)
+ GlobalUnlock16(hMetaFile16);
+
+ if (hmf)
+ DeleteMetaFile(hmf);
+
+ if (metadata.parmemp.vpHandleTable)
+ GlobalUnlockFree16(metadata.parmemp.vpHandleTable);
+
+ if (metadata.parmemp.vpMetaRecord)
+ GlobalUnlockFree16(metadata.parmemp.vpMetaRecord);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetMetaFile(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ HMETAFILE hmf;
+ register PGETMETAFILE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETMETAFILE16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+
+ hmf = GetMetaFile(psz1);
+
+ if (hmf)
+ ul = WinMetaFileFromHMF(hmf, TRUE);
+ else
+ ul = 0;
+
+ FREEPSZPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32PlayMetaFile(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ HMETAFILE hmf;
+ register PPLAYMETAFILE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(PLAYMETAFILE16), parg16);
+
+ hmf = HMFFromWinMetaFile(parg16->f2, FALSE);
+
+ ul = GETBOOL16(PlayMetaFile(HDC32(parg16->f1), hmf));
+
+ if (hmf)
+ DeleteMetaFile(hmf);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32PlayMetaFileRecord(PVDMFRAME pFrame)
+{
+ ULONG ul = FALSE;
+ LPHANDLETABLE pHT = NULL;
+ PBYTE pMetaData;
+ WORD wHandles;
+ VPHANDLETABLE16 vpHT;
+ register PPLAYMETAFILERECORD16 parg16;
+
+ GETARGPTR(pFrame, sizeof(PLAYMETAFILERECORD16), parg16);
+
+ wHandles = parg16->f4;
+ vpHT = parg16->f2;
+ if (wHandles && vpHT) {
+ ALLOCHANDLETABLE16(wHandles, pHT);
+ if (!pHT)
+ goto PMFR_Exit;
+
+ GETHANDLETABLE16(vpHT, wHandles, pHT);
+ }
+ GETOPTPTR(parg16->f3, 0, pMetaData);
+
+ ul = (ULONG) PlayMetaFileRecord(HDC32(parg16->f1),
+ pHT,
+ (LPMETARECORD)pMetaData,
+ (UINT)wHandles);
+
+
+ if (wHandles && vpHT) {
+ PUTHANDLETABLE16(vpHT, wHandles, pHT);
+ FREEHANDLETABLE16(pHT);
+ }
+PMFR_Exit:
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+#if 0 // implemented in gdi.exe
+
+ULONG FASTCALL WG32GetMetaFileBits(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PGETMETAFILEBITS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETMETAFILEBITS16), parg16);
+
+ if (GlobalLock16(parg16->f1,NULL))
+ {
+ GlobalUnlock16(parg16->f1);
+ ul = parg16->f1;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+ULONG FASTCALL WG32SetMetaFileBits(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETMETAFILEBITS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETMETAFILEBITS16), parg16);
+
+ ul = parg16->f1;
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+#endif
diff --git a/private/mvdm/wow32/wgmeta.h b/private/mvdm/wow32/wgmeta.h
new file mode 100644
index 000000000..b0f01e234
--- /dev/null
+++ b/private/mvdm/wow32/wgmeta.h
@@ -0,0 +1,39 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGMETA.H
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WG32CloseMetaFile(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CopyMetaFile(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreateMetaFile(PVDMFRAME pFrame);
+ULONG FASTCALL WG32DeleteMetaFile(PVDMFRAME pFrame);
+ULONG FASTCALL WG32EnumMetaFile(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetMetaFile(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetMetaFileBits(PVDMFRAME pFrame);
+ULONG FASTCALL WG32PlayMetaFile(PVDMFRAME pFrame);
+ULONG FASTCALL WG32PlayMetaFileRecord(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetMetaFileBits(PVDMFRAME pFrame);
+HAND16 WinMetaFileFromHMF(HMETAFILE hmf, BOOL fFreeOriginal);
+HMETAFILE HMFFromWinMetaFile(HAND16 h16, BOOL fFreeOriginal);
+
+
+/* MetaFile Enumeration handler data
+ */
+typedef struct _METADATA { /* fntdata */
+ PARMEMP parmemp; // 16-bit enumeration data (WOW.H)
+ VPPROC vpfnEnumMetaFileProc; // 16-bit enumeration function
+ DWORD mtMaxRecordSize;
+} METADATA, *PMETADATA;
+
+
+INT W32EnumMetaFileCallBack(HDC hdc, LPHANDLETABLE lpht, LPMETARECORD lpMR, LONG nObj, PMETADATA pMetaData);
diff --git a/private/mvdm/wow32/wgpal.c b/private/mvdm/wow32/wgpal.c
new file mode 100644
index 000000000..cc325749e
--- /dev/null
+++ b/private/mvdm/wow32/wgpal.c
@@ -0,0 +1,292 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGPAL.C
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * 07-Mar-1991 Jeff Parsons (jeffpar)
+ * Created.
+ *
+ * 09-Apr-1991 NigelT
+ * Various defines are used here to remove calls to Win32
+ * features which don't work yet.
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wgpal.c);
+
+
+ULONG FASTCALL WG32AnimatePalette(PVDMFRAME pFrame)
+{
+ PPALETTEENTRY t4;
+ register PANIMATEPALETTE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ANIMATEPALETTE16), parg16);
+ GETPALETTEENTRY16(parg16->f4, parg16->f3, t4);
+
+ if( t4 ) {
+ AnimatePalette(HPALETTE32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ t4);
+ FREEPALETTEENTRY16(t4);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(0);
+}
+
+
+ULONG FASTCALL WG32CreatePalette(PVDMFRAME pFrame)
+{
+ ULONG ul = 0L;
+ PLOGPALETTE t1;
+ register PCREATEPALETTE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEPALETTE16), parg16);
+ GETLOGPALETTE16(parg16->f1, t1);
+
+ if( t1 ) {
+ ul = GETHPALETTE16(CreatePalette(t1));
+ WOW32APIWARN(ul, "CreatePalette");
+ FREELOGPALETTE16(t1);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetNearestPaletteIndex(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETNEARESTPALETTEINDEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETNEARESTPALETTEINDEX16), parg16);
+
+ ul = GETWORD16(GetNearestPaletteIndex(HPALETTE32(parg16->f1),
+ DWORD32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetPaletteEntries(PVDMFRAME pFrame)
+{
+ ULONG ul = 0L;
+ PPALETTEENTRY t4;
+ register PGETPALETTEENTRIES16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETPALETTEENTRIES16), parg16);
+
+ if( t4 = malloc_w((parg16->f3) * sizeof(PALETTEENTRY)) ) {
+
+ ul = GETWORD16(GetPaletteEntries(HPALETTE32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ t4));
+
+ PUTPALETTEENTRY16(parg16->f4, parg16->f3, t4);
+ FREEPALETTEENTRY16(t4);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetSystemPaletteEntries(PVDMFRAME pFrame)
+{
+ ULONG ul = 0L;
+ PPALETTEENTRY ppal;
+ register PGETSYSTEMPALETTEENTRIES16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETSYSTEMPALETTEENTRIES16), parg16);
+
+ if( ppal = malloc_w((parg16->f3) * sizeof(PALETTEENTRY)) ) {
+
+ ul = GETWORD16(GetSystemPaletteEntries(HDC32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ ppal));
+
+ // if we fail but are on a rgb device, fill in the default 256 entries.
+ // WIN31 just calls Escape(hdc,GETCOLORTABLE) which on NT just calls
+ // GetSysteemPaletteEntries().
+
+ if (!ul && (GetDeviceCaps(HDC32(parg16->f1),BITSPIXEL) > 8))
+ {
+ if (parg16->f4 == 0)
+ {
+ ul = 256;
+ }
+ else
+ {
+ int j;
+ int i = WORD32(parg16->f2);
+ int c = WORD32(parg16->f3);
+
+ if ((c + i) > 256)
+ c = 256 - i;
+
+ if (c > 0)
+ {
+ BYTE abGreenRed[8] = {0x0,0x25,0x48,0x6d,0x92,0xb6,0xdb,0xff};
+ BYTE abBlue[4] = {0x0,0x55,0xaa,0xff};
+
+ // green mask 00000111
+ // red mask 00111000
+ // blue mask 11000000
+ // could certainly do this faster with a table and mem copy
+ // but I don't really care about performance here. Apps
+ // shouldn't be doing this. That is why it is in the wow
+ // layer.
+
+ for (j = 0; j < c; ++j,++i)
+ {
+ ppal[j].peGreen = abGreenRed[i & 0x07];
+ ppal[j].peRed = abGreenRed[(i >> 3) & 0x07];
+ ppal[j].peBlue = abBlue[(i >> 6) & 0x03];
+ ppal[j].peFlags = 0;
+ }
+
+ ul = c;
+ }
+ }
+ }
+
+ PUTPALETTEENTRY16(parg16->f4, ul, ppal);
+ FREEPALETTEENTRY16(ppal);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetSystemPaletteUse(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETSYSTEMPALETTEUSE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETSYSTEMPALETTEUSE16), parg16);
+
+ ul = GETWORD16(GetSystemPaletteUse(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32RealizePalette(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PREALIZEPALETTE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(REALIZEPALETTE16), parg16);
+
+ ul = GETWORD16(RealizePalette(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32ResizePalette(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PRESIZEPALETTE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(RESIZEPALETTE16), parg16);
+
+ ul = GETBOOL16(ResizePalette(HPALETTE32(parg16->f1), WORD32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32SelectPalette(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSELECTPALETTE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SELECTPALETTE16), parg16);
+
+ ul = GETHPALETTE16(SelectPalette(HDC32(parg16->f1),
+ HPALETTE32(parg16->f2),
+ BOOL32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetPaletteEntries(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ PPALETTEENTRY t4;
+ register PSETPALETTEENTRIES16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETPALETTEENTRIES16), parg16);
+ GETPALETTEENTRY16(parg16->f4, parg16->f3, t4);
+
+ if( t4 ) {
+ ul = GETWORD16(SetPaletteEntries(HPALETTE32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ t4));
+ FREEPALETTEENTRY16(t4);
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetSystemPaletteUse(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETSYSTEMPALETTEUSE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETSYSTEMPALETTEUSE16), parg16);
+
+ ul = GETWORD16(SetSystemPaletteUse(HDC32(parg16->f1), WORD32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32UpdateColors(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PUPDATECOLORS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(UPDATECOLORS16), parg16);
+
+ ul = GETINT16(UpdateColors(HDC32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wgpal.h b/private/mvdm/wow32/wgpal.h
new file mode 100644
index 000000000..b2f1f714a
--- /dev/null
+++ b/private/mvdm/wow32/wgpal.h
@@ -0,0 +1,27 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGPAL.H
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WG32AnimatePalette(PVDMFRAME pFrame);
+ULONG FASTCALL WG32CreatePalette(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetNearestPaletteIndex(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetPaletteEntries(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetSystemPaletteEntries(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetSystemPaletteUse(PVDMFRAME pFrame);
+ULONG FASTCALL WU32RealizePalette(PVDMFRAME pFrame);
+ULONG FASTCALL WG32ResizePalette(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SelectPalette(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetPaletteEntries(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetSystemPaletteUse(PVDMFRAME pFrame);
+ULONG FASTCALL WG32UpdateColors(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wgprnset.c b/private/mvdm/wow32/wgprnset.c
new file mode 100644
index 000000000..d431fbbad
--- /dev/null
+++ b/private/mvdm/wow32/wgprnset.c
@@ -0,0 +1,574 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGPRNSET.C
+ * WOW32 printer setup support routines
+ *
+ * These routines help a Win 3.0 task to complete the printer set-up,
+ * when a user initiates the printer setup from the file menu of an
+ * application.
+ *
+ * History:
+ * Created 18-Apr-1991 by Chandan Chauhan (ChandanC)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wgprnset.c);
+
+DLLENTRYPOINTS spoolerapis[WOW_SPOOLERAPI_COUNT] = {"EXTDEVICEMODE", NULL,
+ "DEVICEMODE", NULL,
+ "DEVICECAPABILITIES", NULL,
+ "OpenPrinterA", NULL,
+ "StartDocPrinterA", NULL,
+ "StartPagePrinter", NULL,
+ "EndPagePrinter", NULL,
+ "EndDocPrinter", NULL,
+ "ClosePrinter", NULL,
+ "WritePrinter", NULL,
+ "DeletePrinter", NULL,
+ "GetPrinterDriverDirectoryA", NULL,
+ "AddPrinterA", NULL,
+ "AddPrinterDriverA", NULL,
+ "AddPortExA",NULL};
+
+
+/****************************************************************************
+* *
+* ULONG FASTCALL WG32DeviceMode (PVDMFRAME pFrame) *
+* *
+* (hWnd, hModule, lpDeviceName, lpOutPut) *
+* *
+* This function passes WDevMode structure (which is per wow task) to *
+* Win32 printer driver ExtDeviceMode API. This structure is then *
+* initialized by the printer driver based on the user input. *
+* *
+* Later on, when a WOW task creates a dc (by CreateDC API), the device *
+* mode (WDevMode) structure associated with this wow task is passed along *
+* with the CreateDC API. Which contains the printer setup information *
+* needed to print the document. *
+* *
+****************************************************************************/
+ULONG FASTCALL WG32DeviceMode (PVDMFRAME pFrame)
+{
+
+ register PDEVICEMODE16 parg16;
+ PSZ psz, psz3=NULL, psz4=NULL;
+ HWND hwnd32;
+
+ GETARGPTR(pFrame, sizeof(DEVICEMODE16), parg16);
+
+ // copy all 16-bit params now since 16-bit memory may move if this calls
+ // into a 16-bit fax driver
+ hwnd32 = HWND32(parg16->f1);
+
+ GETPSZPTR(parg16->f3, psz);
+ if(psz) {
+ if(psz3 = malloc_w(lstrlen(psz)+1)) {
+ lstrcpy(psz3, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ GETPSZPTR(parg16->f4, psz);
+ if(psz) {
+ if(psz4 = malloc_w(lstrlen(psz)+1)) {
+ lstrcpy(psz4, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ // invalidate all flat ptrs to 16:16 memory now!
+ FREEARGPTR(parg16);
+
+ if (!(*spoolerapis[WOW_DEVICEMODE].lpfn)) {
+ if (!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
+ return (0);
+ }
+ }
+
+ // this can callback into a 16-bit fax driver!
+ (*spoolerapis[WOW_DEVICEMODE].lpfn)(hwnd32, NULL, psz3, psz4);
+
+ if(psz3) {
+ free_w(psz3);
+ }
+ if(psz4) {
+ free_w(psz4);
+ }
+
+ RETURN(1); // DeviceMode returns void. Charisma checks the return value !
+}
+
+
+
+
+
+/*****************************************************************************
+* *
+* ULONG FASTCALL WG32ExtDeviceMode (PVDMFRAME pFrame) *
+* *
+* INT (hWnd, hDriver, lpDevModeOutput, lpDeviceName, lpPort, *
+* lpDevModeInput, lpProfile, wMode) *
+* *
+* This function is same as DeviceMode except that the wow task supplies *
+* a DeviceMode structure. Apart from it, this API can be called in *
+* different modes. *
+* *
+*****************************************************************************/
+ULONG FASTCALL WG32ExtDeviceMode (PVDMFRAME pFrame)
+{
+ UINT cb;
+ LONG l;
+ HWND hWnd1;
+ WORD wMode8;
+ PSZ psz;
+ PSZ psz4 = NULL, psz5 = NULL, psz7 = NULL;
+ VPVOID vpdm3, vpdm6;
+ LPDEVMODE lpdmInput6;
+ LPDEVMODE lpdmOutput3;
+ register PEXTDEVICEMODE16 parg16;
+
+
+ GETARGPTR(pFrame, sizeof(EXTDEVICEMODE16), parg16);
+
+ // copy the 16-bit parameters into local vars since this may callback
+ // into a 16-bit fax driver and cause 16-bit memory to move
+ hWnd1 = HWND32(parg16->f1);
+ vpdm3 = FETCHDWORD(parg16->f3);
+ vpdm6 = FETCHDWORD(parg16->f6);
+ wMode8 = FETCHWORD(parg16->f8);
+
+ GETPSZPTR(parg16->f4, psz);
+ if(psz) {
+ if(psz4 = malloc_w(lstrlen(psz)+1)) {
+ lstrcpy(psz4, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ GETPSZPTR(parg16->f5, psz);
+ if(psz) {
+ if(psz5 = malloc_w(lstrlen(psz)+1)) {
+ lstrcpy(psz5, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ GETPSZPTR(parg16->f7, psz);
+ if(psz) {
+ if(psz7 = malloc_w(lstrlen(psz)+1)) {
+ lstrcpy(psz7, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ FREEARGPTR(parg16);
+ // all flat ptrs to 16:16 memory are now invalid!!
+
+ if (!(*spoolerapis[WOW_EXTDEVICEMODE].lpfn)) {
+ if (!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
+ return (0);
+ }
+ }
+
+ lpdmInput6 = ThunkDevMode16to32(FETCHDWORD(vpdm6));
+
+ /* if they want output buffer size OR they want to fill output buffer */
+ if( (wMode8 == 0) || (wMode8 & DM_OUT_BUFFER) ) {
+
+ /* get required size for output buffer */
+ l = (*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(hWnd1,
+ NULL,
+ NULL,
+ psz4,
+ psz5,
+ lpdmInput6,
+ psz7,
+ 0);
+
+ // adjust size for WOW handling (see notes in wstruc.c)
+ if(l > 0) {
+ l += sizeof(WOWDM31);
+ cb = (UINT)l;
+ }
+
+ /* if caller wants output buffer filled... */
+ if( (wMode8 != 0) && (vpdm3 != 0L) && l > 0 ) {
+
+ if( lpdmOutput3 = malloc_w(l) ) {
+
+ l = (*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(hWnd1,
+ NULL,
+ lpdmOutput3,
+ psz4,
+ psz5,
+ lpdmInput6,
+ psz7,
+ wMode8);
+
+ /* Data in lpdmOutput3 is only valid with IDOK return. */
+ if( l == IDOK ) {
+
+ // do our WOW magic on this before we give it to the app
+ ThunkDevMode32to16(vpdm3, lpdmOutput3, cb);
+ }
+
+ free_w(lpdmOutput3);
+ }
+ else {
+ l = -1L;
+ }
+ }
+ }
+
+ /* else call for cases where they don't want to fill the output buffer */
+ else {
+
+ l = (*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(hWnd1,
+ NULL,
+ NULL,
+ psz4,
+ psz5,
+ lpdmInput6,
+ psz7,
+ wMode8);
+ }
+
+ if( lpdmInput6 ) {
+ free_w(lpdmInput6);
+ }
+ if(psz4) {
+ free_w(psz4);
+ }
+ if(psz5) {
+ free_w(psz5);
+ }
+ if(psz7) {
+ free_w(psz7);
+ }
+
+ RETURN((ULONG)l);
+
+}
+
+
+
+
+ULONG FASTCALL WG32DeviceCapabilities (PVDMFRAME pFrame)
+{
+ LONG l=0L, cb;
+ WORD fwCap3;
+ PSZ psz;
+ PBYTE pOutput4, pOutput32;
+ VPVOID vpOutput4;
+ PSZ psz1 = NULL;
+ PSZ psz2 = NULL;
+ LPDEVMODE lpdmInput5;
+ DWORD dwDM5;
+ register PDEVICECAPABILITIES16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DEVICECAPABILITIES16), parg16);
+
+ // copy the 16-bit parameters into local vars since this may callback
+ // into a 16-bit fax driver and cause 16-bit memory to move
+ GETPSZPTR(parg16->f1, psz);
+ if(psz) {
+ if(psz1 = malloc_w(lstrlen(psz)+1)) {
+ lstrcpy(psz1, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ GETPSZPTR(parg16->f2, psz);
+ if(psz) {
+ if(psz2 = malloc_w(lstrlen(psz)+1)) {
+ lstrcpy(psz2, psz);
+ }
+ }
+ FREEPSZPTR(psz);
+
+ fwCap3 = FETCHWORD(parg16->f3);
+
+ vpOutput4 = FETCHDWORD(parg16->f4);
+
+ dwDM5 = FETCHDWORD(parg16->f5);
+
+ FREEARGPTR(parg16);
+ // all flat ptrs to 16:16 memory are now invalid!!
+
+ if (!(*spoolerapis[WOW_DEVICECAPABILITIES].lpfn)) {
+ if (!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV",
+ spoolerapis,
+ WOW_SPOOLERAPI_COUNT)) {
+ return (0);
+ }
+ }
+
+ lpdmInput5 = ThunkDevMode16to32(dwDM5);
+
+ LOGDEBUG(LOG_TRACE, ("WG32DeviceCapabilities %d\n", fwCap3));
+
+ switch (fwCap3) {
+
+ // These ones do not fill up an output Buffer
+
+ case DC_FIELDS:
+ case DC_DUPLEX:
+ case DC_SIZE:
+ case DC_EXTRA:
+ case DC_VERSION:
+ case DC_DRIVER:
+ case DC_TRUETYPE:
+ case DC_ORIENTATION:
+ case DC_COPIES:
+
+ l = (*spoolerapis[WOW_DEVICECAPABILITIES].lpfn)(psz1,
+ psz2,
+ fwCap3,
+ NULL,
+ lpdmInput5);
+
+ LOGDEBUG(LOG_TRACE, ("WG32DeviceCapabilities simple case returned %d\n", l));
+
+ // adjust for WOW handling of devmodes // see notes in wstruc.c
+ if(fwCap3 == DC_SIZE) {
+
+ // we always convert NT DevModes to Win3.1 DevModes
+ WOW32WARNMSGF((l==sizeof(DEVMODE)),
+ ("WG32DeviceCapabilities: Unexpected DevMode size: %d\n",l));
+ if(l == sizeof(DEVMODE)) {
+ l = sizeof(DEVMODE31);
+ }
+ }
+ // adjust DriverExtra to allow for difference between NT devmodes
+ // & Win3.1 devmodes + our secret WOW stuff at the end
+ else if(fwCap3 == DC_EXTRA) {
+ l += WOW_DEVMODEEXTRA;
+ }
+ // we tell them Win3.1 for the spec version too
+ else if(fwCap3 == DC_VERSION) {
+ l = WOW_DEVMODE31SPEC; // tell 'em the spec version is Win3.1
+ }
+
+ break;
+
+
+ // These require an output buffer
+ case DC_PAPERS:
+ case DC_PAPERSIZE:
+ case DC_MINEXTENT:
+ case DC_MAXEXTENT:
+ case DC_BINS:
+ case DC_BINNAMES:
+ case DC_ENUMRESOLUTIONS:
+ case DC_FILEDEPENDENCIES:
+ case DC_PAPERNAMES:
+
+ LOGDEBUG(LOG_TRACE, ("WG32DeviceCapabilities more complicated:\n"));
+
+ // We've got to figure out how much memory we will need
+ GETMISCPTR(vpOutput4, pOutput4);
+ if (pOutput4) {
+
+ cb = (*spoolerapis[WOW_DEVICECAPABILITIES].lpfn)(psz1,
+ psz2,
+ fwCap3,
+ NULL,
+ lpdmInput5);
+
+ FREEPSZPTR(pOutput4); // invalidate -16bit memory may have moved
+
+ LOGDEBUG(LOG_TRACE, ("we need %d bytes ", cb));
+
+ if (cb > 0) {
+
+ switch (fwCap3) {
+
+ case DC_PAPERS:
+ cb *= 2;
+ break;
+
+ case DC_BINNAMES:
+ cb *= 24;
+ break;
+
+ case DC_BINS:
+ cb*=2;
+ break;
+
+ case DC_FILEDEPENDENCIES:
+ case DC_PAPERNAMES:
+ cb *= 64;
+ break;
+
+ case DC_MAXEXTENT:
+ case DC_MINEXTENT:
+ case DC_PAPERSIZE:
+ cb *= 8;
+
+ LOGDEBUG(LOG_TRACE, ("DC_PAPERSIZE called: Needed %d bytes\n", cb));
+
+ break;
+
+ case DC_ENUMRESOLUTIONS:
+ cb *= sizeof(LONG)*2;
+ break;
+
+ } // end switch
+
+ pOutput32 = malloc_w(cb);
+
+ if (pOutput32) {
+
+ l = (*spoolerapis[WOW_DEVICECAPABILITIES].lpfn)(psz1, psz2, fwCap3, pOutput32, lpdmInput5);
+
+ if (l >= 0) {
+
+ GETMISCPTR(vpOutput4, pOutput4);
+
+ switch (fwCap3) {
+
+ case DC_PAPERS:
+ if (CURRENTPTD()->dwWOWCompatFlags &
+ WOWCF_RESETPAPER29ANDABOVE) {
+
+ // wordperfect for windows 5.2 GPs if
+ // papertype is > 0x28. so reset such
+ // paper types to 0x1. In particular
+ // this happens if the selected printer
+ // is Epson LQ-510.
+ // - nanduri
+
+ LONG i = l;
+ while(i--) {
+ if (((LPWORD)pOutput32)[i] > 0x28) {
+ ((LPWORD)pOutput32)[i] = 0x1;
+ }
+ }
+ } // end if
+
+ RtlCopyMemory(pOutput4, pOutput32, cb);
+ break;
+
+ case DC_MAXEXTENT:
+ case DC_MINEXTENT:
+ case DC_PAPERSIZE:
+ LOGDEBUG(LOG_TRACE, ("Copying %d points from %0x to %0x\n", l, pOutput32, pOutput4));
+
+ putpoint16(vpOutput4, l,(LPPOINT)pOutput32);
+ break;
+
+ default:
+ LOGDEBUG(LOG_TRACE, ("Copying %d bytes from %0x to %0x\n",cb, pOutput32, pOutput4));
+
+ RtlCopyMemory(pOutput4, pOutput32, cb);
+ break;
+
+ } // end switch
+
+ FLUSHVDMPTR(vpOutput4, (USHORT)cb, pOutput4);
+ FREEPSZPTR(pOutput4);
+
+ } // end if
+
+ free_w(pOutput32);
+
+ } else
+ l = -1;
+ } else
+ l = cb;
+
+
+ } else {
+
+
+ l = (*spoolerapis[WOW_DEVICECAPABILITIES].lpfn)(psz1,
+ psz2,
+ fwCap3,
+ NULL,
+ lpdmInput5);
+
+ LOGDEBUG(LOG_TRACE, ("No Output buffer specified: Returning %d\n", l));
+ }
+
+ break;
+
+ default:
+ LOGDEBUG(LOG_TRACE, ("!!!! WG32DeviceCapabilities unhandled %d\n", fwCap3));
+ l = -1L;
+ break;
+
+ } // end switch
+
+ if (lpdmInput5) {
+ free_w(lpdmInput5);
+ }
+ if(psz1) {
+ free_w(psz1);
+ }
+ if(psz2) {
+ free_w(psz2);
+ }
+
+ RETURN(l);
+}
+
+
+
+
+BOOL LoadLibraryAndGetProcAddresses(char *name, DLLENTRYPOINTS *p, int num)
+{
+ int i;
+ HINSTANCE hInst;
+
+ if (!(hInst = SafeLoadLibrary (name))) {
+ WOW32ASSERTMSGF (FALSE, ("WOW::LoadLibraryAndGetProcAddresses: LoadLibrary('%s') failed\n", name));
+ return FALSE;
+ }
+
+ for (i = 0; i < num ; i++) {
+ p[i].lpfn = (void *) GetProcAddress (hInst, (p[i].name));
+ WOW32ASSERTMSGF (p[i].lpfn, ("WOW::LoadLibraryAndGetProcAddresses: GetProcAddress(%s, '%s') failed\n", name, p[i].name));
+ }
+
+ return TRUE;
+}
+
+#ifdef i386
+/*
+ * "Safe" version of LoadLibrary which preserves floating-point state
+ * across the load. This is critical on x86 because the FP state being
+ * preserved is the 16-bit app's state. MSVCRT.DLL is one offender which
+ * changes the Precision bits in its Dll init routine.
+ *
+ * On RISC, this is an alias for LoadLibrary
+ *
+ */
+HINSTANCE SafeLoadLibrary(char *name)
+{
+ HINSTANCE hInst;
+ BYTE FpuState[108];
+
+ // Save the 487 state
+ _asm {
+ lea ecx, [FpuState]
+ fsave [ecx]
+ }
+
+ hInst = LoadLibrary(name);
+
+ // Restore the 487 state
+ _asm {
+ lea ecx, [FpuState]
+ frstor [ecx]
+ }
+
+ return hInst;
+}
+#endif //i386
diff --git a/private/mvdm/wow32/wgprnset.h b/private/mvdm/wow32/wgprnset.h
new file mode 100644
index 000000000..73d7dfa4e
--- /dev/null
+++ b/private/mvdm/wow32/wgprnset.h
@@ -0,0 +1,23 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGPRNSET.H
+ * WOW32 printer setup support routines
+ *
+ * These routines help a Win 3.0 task to complete the printer set-up,
+ * when a user initiates the printer setup from the file menu of an
+ * application.
+ *
+ * History:
+ * Created 18-Apr-1991 by Chandan Chauhan (ChandanC)
+--*/
+
+
+#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (V)
+
+ULONG FASTCALL WG32DeviceMode (PVDMFRAME pFrame);
+ULONG FASTCALL WG32ExtDeviceMode (PVDMFRAME pFrame);
+ULONG FASTCALL WG32DeviceCapabilities (PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wgtbl.h b/private/mvdm/wow32/wgtbl.h
new file mode 100644
index 000000000..1e4db1135
--- /dev/null
+++ b/private/mvdm/wow32/wgtbl.h
@@ -0,0 +1,23 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGTBL.H
+ * WOW32 16-bit GDI API tables
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* GDI dispatch table
+ */
+extern W32 aw32GDI[];
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iGDIMax;
+#endif
diff --git a/private/mvdm/wow32/wgtbl2.h b/private/mvdm/wow32/wgtbl2.h
new file mode 100644
index 000000000..e6798dde6
--- /dev/null
+++ b/private/mvdm/wow32/wgtbl2.h
@@ -0,0 +1,602 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGTBL2.h
+ * WOW32 16-bit GDI API tables
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_GDI, 0)},
+ {W32FUN(WG32SetBkColor, "SETBKCOLOR", MOD_GDI, sizeof(SETBKCOLOR16))},
+ {W32FUN(WG32SetBkMode, "SETBKMODE", MOD_GDI, sizeof(SETBKMODE16))},
+ {W32FUN(WG32SetMapMode, "SETMAPMODE", MOD_GDI, sizeof(SETMAPMODE16))},
+ {W32FUN(WG32SetROP2, "SETROP2", MOD_GDI, sizeof(SETROP216))},
+ {W32FUN(WG32SetRelAbs, "SETRELABS", MOD_GDI, sizeof(SETRELABS16))},
+ {W32FUN(WG32SetPolyFillMode, "SETPOLYFILLMODE", MOD_GDI, sizeof(SETPOLYFILLMODE16))},
+ {W32FUN(WG32SetStretchBltMode, "SETSTRETCHBLTMODE", MOD_GDI, sizeof(SETSTRETCHBLTMODE16))},
+ {W32FUN(WG32SetTextCharacterExtra, "SETTEXTCHARACTEREXTRA", MOD_GDI, sizeof(SETTEXTCHARACTEREXTRA16))},
+ {W32FUN(WG32SetTextColor, "SETTEXTCOLOR", MOD_GDI, sizeof(SETTEXTCOLOR16))},
+
+ /*** 0010 ***/
+ {W32FUN(WG32SetTextJustification, "SETTEXTJUSTIFICATION", MOD_GDI, sizeof(SETTEXTJUSTIFICATION16))},
+ {W32FUN(WG32SetWindowOrg, "SETWINDOWORG", MOD_GDI, sizeof(SETWINDOWORG16))},
+ {W32FUN(WG32SetWindowExt, "SETWINDOWEXT", MOD_GDI, sizeof(SETWINDOWEXT16))},
+ {W32FUN(WG32SetViewportOrg, "SETVIEWPORTORG", MOD_GDI, sizeof(SETVIEWPORTORG16))},
+ {W32FUN(WG32SetViewportExt, "SETVIEWPORTEXT", MOD_GDI, sizeof(SETVIEWPORTEXT16))},
+ {W32FUN(WG32OffsetWindowOrg, "OFFSETWINDOWORG", MOD_GDI, sizeof(OFFSETWINDOWORG16))},
+ {W32FUN(WG32ScaleWindowExt, "SCALEWINDOWEXT", MOD_GDI, sizeof(SCALEWINDOWEXT16))},
+ {W32FUN(WG32OffsetViewportOrg, "OFFSETVIEWPORTORG", MOD_GDI, sizeof(OFFSETVIEWPORTORG16))},
+ {W32FUN(WG32ScaleViewportExt, "SCALEVIEWPORTEXT", MOD_GDI, sizeof(SCALEVIEWPORTEXT16))},
+ {W32FUN(WG32LineTo, "LINETO", MOD_GDI, sizeof(LINETO16))},
+
+ /*** 0020 ***/
+ {W32FUN(WG32MoveTo, "MOVETO", MOD_GDI, sizeof(MOVETO16))},
+ {W32FUN(WG32ExcludeClipRect, "EXCLUDECLIPRECT", MOD_GDI, sizeof(EXCLUDECLIPRECT16))},
+ {W32FUN(WG32IntersectClipRect, "INTERSECTCLIPRECT", MOD_GDI, sizeof(INTERSECTCLIPRECT16))},
+ {W32FUN(WG32Arc, "ARC", MOD_GDI, sizeof(ARC16))},
+ {W32FUN(WG32Ellipse, "ELLIPSE", MOD_GDI, sizeof(ELLIPSE16))},
+ {W32FUN(WG32FloodFill, "FLOODFILL", MOD_GDI, sizeof(FLOODFILL16))},
+ {W32FUN(WG32Pie, "PIE", MOD_GDI, sizeof(PIE16))},
+ {W32FUN(WG32Rectangle, "RECTANGLE", MOD_GDI, sizeof(RECTANGLE16))},
+ {W32FUN(WG32RoundRect, "ROUNDRECT", MOD_GDI, sizeof(ROUNDRECT16))},
+ {W32FUN(WG32PatBlt, "PATBLT", MOD_GDI, sizeof(PATBLT16))},
+
+ /*** 0030 ***/
+ {W32FUN(WG32SaveDC, "SAVEDC", MOD_GDI, sizeof(SAVEDC16))},
+ {W32FUN(WG32SetPixel, "SETPIXEL", MOD_GDI, sizeof(SETPIXEL16))},
+ {W32FUN(WG32OffsetClipRgn, "OFFSETCLIPRGN", MOD_GDI, sizeof(OFFSETCLIPRGN16))},
+ {W32FUN(WG32TextOut, "TEXTOUT", MOD_GDI, sizeof(TEXTOUT16))},
+ {W32FUN(WG32BitBlt, "BITBLT", MOD_GDI, sizeof(BITBLT16))},
+ {W32FUN(WG32StretchBlt, "STRETCHBLT", MOD_GDI, sizeof(STRETCHBLT16))},
+ {W32FUN(WG32Polygon, "POLYGON", MOD_GDI, sizeof(POLYGON16))},
+ {W32FUN(WG32Polyline, "POLYLINE", MOD_GDI, sizeof(POLYLINE16))},
+ {W32FUN(WG32Escape, "ESCAPE", MOD_GDI, sizeof(ESCAPE16))},
+ {W32FUN(WG32RestoreDC, "RESTOREDC", MOD_GDI, sizeof(RESTOREDC16))},
+
+ /*** 0040 ***/
+ {W32FUN(WG32FillRgn, "FILLRGN", MOD_GDI, sizeof(FILLRGN16))},
+ {W32FUN(WG32FrameRgn, "FRAMERGN", MOD_GDI, sizeof(FRAMERGN16))},
+ {W32FUN(WG32InvertRgn, "INVERTRGN", MOD_GDI, sizeof(INVERTRGN16))},
+ {W32FUN(WG32PaintRgn, "PAINTRGN", MOD_GDI, sizeof(PAINTRGN16))},
+ {W32FUN(WG32SelectClipRgn, "SELECTCLIPRGN", MOD_GDI, sizeof(SELECTCLIPRGN16))},
+ {W32FUN(WG32SelectObject, "SELECTOBJECT", MOD_GDI, sizeof(SELECTOBJECT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "BITMAPBITS", MOD_GDI, 0)},
+ {W32FUN(WG32CombineRgn, "COMBINERGN", MOD_GDI, sizeof(COMBINERGN16))},
+ {W32FUN(WG32CreateBitmap, "CREATEBITMAP", MOD_GDI, sizeof(CREATEBITMAP16))},
+ {W32FUN(WG32CreateBitmapIndirect, "CREATEBITMAPINDIRECT", MOD_GDI, sizeof(CREATEBITMAPINDIRECT16))},
+
+ /*** 0050 ***/
+ {W32FUN(WG32CreateBrushIndirect, "CREATEBRUSHINDIRECT", MOD_GDI, sizeof(CREATEBRUSHINDIRECT16))},
+ {W32FUN(WG32CreateCompatibleBitmap, "CREATECOMPATIBLEBITMAP", MOD_GDI, sizeof(CREATECOMPATIBLEBITMAP16))},
+ {W32FUN(WG32CreateCompatibleDC, "CREATECOMPATIBLEDC", MOD_GDI, sizeof(CREATECOMPATIBLEDC16))},
+ {W32FUN(WG32CreateDC, "CREATEDC", MOD_GDI, sizeof(CREATEDC16))},
+ {W32FUN(WG32CreateEllipticRgn, "CREATEELLIPTICRGN", MOD_GDI, sizeof(CREATEELLIPTICRGN16))},
+ {W32FUN(WG32CreateEllipticRgnIndirect, "CREATEELLIPTICRGNINDIRECT",MOD_GDI, sizeof(CREATEELLIPTICRGNINDIRECT16))},
+ {W32FUN(WG32CreateFont, "CREATEFONT", MOD_GDI, sizeof(CREATEFONT16))},
+ {W32FUN(WG32CreateFontIndirect, "CREATEFONTINDIRECT", MOD_GDI, sizeof(CREATEFONTINDIRECT16))},
+ {W32FUN(WG32CreateHatchBrush, "CREATEHATCHBRUSH", MOD_GDI, sizeof(CREATEHATCHBRUSH16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0060 ***/
+ {W32FUN(WG32CreatePatternBrush, "CREATEPATTERNBRUSH", MOD_GDI, sizeof(CREATEPATTERNBRUSH16))},
+ {W32FUN(WG32CreatePen, "CREATEPEN", MOD_GDI, sizeof(CREATEPEN16))},
+ {W32FUN(WG32CreatePenIndirect, "CREATEPENINDIRECT", MOD_GDI, sizeof(CREATEPENINDIRECT16))},
+ {W32FUN(WG32CreatePolygonRgn, "CREATEPOLYGONRGN", MOD_GDI, sizeof(CREATEPOLYGONRGN16))},
+ {W32FUN(WG32CreateRectRgn, "CREATERECTRGN", MOD_GDI, sizeof(CREATERECTRGN16))},
+ {W32FUN(WG32CreateRectRgnIndirect, "CREATERECTRGNINDIRECT", MOD_GDI, sizeof(CREATERECTRGNINDIRECT16))},
+ {W32FUN(WG32CreateSolidBrush, "CREATESOLIDBRUSH", MOD_GDI, sizeof(CREATESOLIDBRUSH16))},
+ {W32FUN(WG32DPtoLP, "DPTOLP", MOD_GDI, sizeof(DPTOLP16))},
+ {W32FUN(WG32DeleteDC, "DELETEDC", MOD_GDI, sizeof(DELETEDC16))},
+ {W32FUN(WG32DeleteObject, "DELETEOBJECT", MOD_GDI, sizeof(DELETEOBJECT16))},
+
+ /*** 0070 ***/
+ {W32FUN(WG32EnumFonts, "ENUMFONTS", MOD_GDI, sizeof(ENUMFONTS16))},
+ {W32FUN(WG32EnumObjects, "ENUMOBJECTS", MOD_GDI, sizeof(ENUMOBJECTS16))},
+ {W32FUN(WG32EqualRgn, "EQUALRGN", MOD_GDI, sizeof(EQUALRGN16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "EXCLUDEVISRECT", MOD_GDI, 0)},
+ {W32FUN(WG32GetBitmapBits, "GETBITMAPBITS", MOD_GDI, sizeof(GETBITMAPBITS16))},
+ {W32FUN(WG32GetBkColor, "GETBKCOLOR", MOD_GDI, sizeof(GETBKCOLOR16))},
+ {W32FUN(WG32GetBkMode, "GETBKMODE", MOD_GDI, sizeof(GETBKMODE16))},
+ {W32FUN(WG32GetClipBox, "GETCLIPBOX", MOD_GDI, sizeof(GETCLIPBOX16))},
+ {W32FUN(WG32GetCurrentPosition, "GETCURRENTPOSITION", MOD_GDI, sizeof(GETCURRENTPOSITION16))},
+ {W32FUN(WG32GetDCOrg, "GETDCORG", MOD_GDI, sizeof(GETDCORG16))},
+
+ /*** 0080 ***/
+ {W32FUN(WG32GetDeviceCaps, "GETDEVICECAPS", MOD_GDI, sizeof(GETDEVICECAPS16))},
+ {W32FUN(WG32GetMapMode, "GETMAPMODE", MOD_GDI, sizeof(GETMAPMODE16))},
+ {W32FUN(WG32GetObject, "GETOBJECT", MOD_GDI, sizeof(GETOBJECT16))},
+ {W32FUN(WG32GetPixel, "GETPIXEL", MOD_GDI, sizeof(GETPIXEL16))},
+ {W32FUN(WG32GetPolyFillMode, "GETPOLYFILLMODE", MOD_GDI, sizeof(GETPOLYFILLMODE16))},
+ {W32FUN(WG32GetROP2, "GETROP2", MOD_GDI, sizeof(GETROP216))},
+ {W32FUN(WG32GetRelAbs, "GETRELABS", MOD_GDI, sizeof(GETRELABS16))},
+ {W32FUN(WG32GetStockObject, "GETSTOCKOBJECT", MOD_GDI, sizeof(GETSTOCKOBJECT16))},
+ {W32FUN(WG32GetStretchBltMode, "GETSTRETCHBLTMODE", MOD_GDI, sizeof(GETSTRETCHBLTMODE16))},
+ {W32FUN(WG32GetTextCharacterExtra, "GETTEXTCHARACTEREXTRA", MOD_GDI, sizeof(GETTEXTCHARACTEREXTRA16))},
+
+ /*** 0090 ***/
+ {W32FUN(WG32GetTextColor, "GETTEXTCOLOR", MOD_GDI, sizeof(GETTEXTCOLOR16))},
+ {W32FUN(WG32GetTextExtent, "GETTEXTEXTENT", MOD_GDI, sizeof(GETTEXTEXTENT16))},
+ {W32FUN(WG32GetTextFace, "GETTEXTFACE", MOD_GDI, sizeof(GETTEXTFACE16))},
+ {W32FUN(WG32GetTextMetrics, "GETTEXTMETRICS", MOD_GDI, sizeof(GETTEXTMETRICS16))},
+ {W32FUN(WG32GetViewportExt, "GETVIEWPORTEXT", MOD_GDI, sizeof(GETVIEWPORTEXT16))},
+ {W32FUN(WG32GetViewportOrg, "GETVIEWPORTORG", MOD_GDI, sizeof(GETVIEWPORTORG16))},
+ {W32FUN(WG32GetWindowExt, "GETWINDOWEXT", MOD_GDI, sizeof(GETWINDOWEXT16))},
+ {W32FUN(WG32GetWindowOrg, "GETWINDOWORG", MOD_GDI, sizeof(GETWINDOWORG16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "INTERSECTVISRECT", MOD_GDI, 0)},
+ {W32FUN(WG32LPtoDP, "LPTODP", MOD_GDI, sizeof(LPTODP16))},
+
+ /*** 0100 ***/
+ {W32FUN(WG32LineDDA, "LINEDDA", MOD_GDI, sizeof(LINEDDA16))},
+ {W32FUN(WG32OffsetRgn, "OFFSETRGN", MOD_GDI, sizeof(OFFSETRGN16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "OFFSETVISRGN", MOD_GDI, 0)},
+ {W32FUN(WG32PtVisible, "PTVISIBLE", MOD_GDI, sizeof(PTVISIBLE16))},
+ {W32FUN(WG32RectVisible, "RECTVISIBLE", MOD_GDI, sizeof(RECTVISIBLE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "SELECTVISRGN", MOD_GDI, 0)},
+ {W32FUN(WG32SetBitmapBits, "SETBITMAPBITS", MOD_GDI, sizeof(SETBITMAPBITS16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0110 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETDCORG", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "INTERNALCREATEDC", MOD_GDI, 0)},
+ {W32FUN(WG32AddFontResource, "ADDFONTRESOURCE", MOD_GDI, sizeof(ADDFONTRESOURCE16))},
+
+ /*** 0120 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DEATH", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "RESURRECTION", MOD_GDI, 0)},
+ {W32FUN(WG32PlayMetaFile, "PLAYMETAFILE", MOD_GDI, sizeof(PLAYMETAFILE16))},
+ {W32FUN(WG32GetMetaFile, "GETMETAFILE", MOD_GDI, sizeof(GETMETAFILE16))},
+ {W32FUN(WG32CreateMetaFile, "CREATEMETAFILE", MOD_GDI, sizeof(CREATEMETAFILE16))},
+ {W32FUN(WG32CloseMetaFile, "CLOSEMETAFILE", MOD_GDI, sizeof(CLOSEMETAFILE16))},
+ {W32FUN(WG32DeleteMetaFile, "DELETEMETAFILE", MOD_GDI, sizeof(DELETEMETAFILE16))},
+ {W32FUN(LOCALAPI, "MULDIV", MOD_GDI, sizeof(MULDIV16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "SAVEVISRGN", MOD_GDI, 0)},
+
+ /*** 0130 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "RESTOREVISRGN", MOD_GDI, 0)},
+ {W32FUN(WG32InquireVisRgn, "INQUIREVISRGN", MOD_GDI, 0)},
+ {W32FUN(NOPAPI, "SETENVIRONMENT", MOD_GDI, sizeof(SETENVIRONMENT16))},
+ {W32FUN(WG32GetEnvironment, "GETENVIRONMENT", MOD_GDI, sizeof(GETENVIRONMENT16))},
+ {W32FUN(WG32GetRgnBox, "GETRGNBOX", MOD_GDI, sizeof(GETRGNBOX16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "SCANLR", MOD_GDI, 0)},
+ {W32FUN(WG32RemoveFontResource, "REMOVEFONTRESOURCE", MOD_GDI, sizeof(REMOVEFONTRESOURCE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GSV", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DPXLATE", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETWINVIEWEXT", MOD_GDI, 0)},
+
+ /*** 0140 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "SCALEEXT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "WORDSET", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "RECTSTUFF", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "OFFSETORG", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(WG32SetBrushOrg, "SETBRUSHORG", MOD_GDI, sizeof(SETBRUSHORG16))},
+ {W32FUN(WG32GetBrushOrg, "GETBRUSHORG", MOD_GDI, sizeof(GETBRUSHORG16))},
+
+ /*** 0150 ***/
+ {W32FUN(WG32UnrealizeObject, "UNREALIZEOBJECT", MOD_GDI, sizeof(UNREALIZEOBJECT16))},
+ {W32FUN(WG32CopyMetaFile, "COPYMETAFILE", MOD_GDI, sizeof(COPYMETAFILE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(WG32CreateIC, "CREATEIC", MOD_GDI, sizeof(CREATEIC16))},
+ {W32FUN(WG32GetNearestColor, "GETNEARESTCOLOR", MOD_GDI, sizeof(GETNEARESTCOLOR16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "QUERYABORT", MOD_GDI, 0)},
+ {W32FUN(WG32CreateDiscardableBitmap, "CREATEDISCARDABLEBITMAP", MOD_GDI, sizeof(CREATEDISCARDABLEBITMAP16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "COMPATIBLEBITMAP", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENUMCALLBACK", MOD_GDI, 0)},
+ {W32FUN(LOCALAPI, "GETMETAFILEBITS", MOD_GDI, 0)},
+
+ /*** 0160 ***/
+ {W32FUN(LOCALAPI, "SETMETAFILEBITS", MOD_GDI, 0)},
+ {W32FUN(WG32PtInRegion, "PTINREGION", MOD_GDI, sizeof(PTINREGION16))},
+ {W32FUN(WG32GetBitmapDimension, "GETBITMAPDIMENSION", MOD_GDI, sizeof(GETBITMAPDIMENSION16))},
+ {W32FUN(WG32SetBitmapDimension, "SETBITMAPDIMENSION", MOD_GDI, sizeof(SETBITMAPDIMENSION16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "PIXTOLINE", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ISDCDIRTY", MOD_GDI, 0)},
+
+ /*** 0170 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "SETDCSTATUS", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LVBUNION", MOD_GDI, 0)},
+ {W32FUN(WG32SetRectRgn, "SETRECTRGN", MOD_GDI, sizeof(SETRECTRGN16))},
+ {W32FUN(WG32GetClipRgn, "GETCLIPRGN", MOD_GDI, sizeof (GETCLIPRGN16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(WG32EnumMetaFile, "ENUMMETAFILE", MOD_GDI, sizeof(ENUMMETAFILE16))},
+ {W32FUN(WG32PlayMetaFileRecord, "PLAYMETAFILERECORD", MOD_GDI, sizeof(PLAYMETAFILERECORD16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "RCOS", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "RSIN", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETDCSTATE", MOD_GDI, 0)},
+
+ /*** 0180 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "SETDCSTATE", MOD_GDI, 0)},
+ {W32FUN(WG32RectInRegion, "RECTINREGION", MOD_GDI, sizeof(RECTINREGION16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "STUFFVISIBLE", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "STUFFINREGION", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DELETEABOVELINEFONTS", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0190 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(WG32SetBoundsRect, "SETBOUNDSRECT", MOD_GDI, sizeof(SETBOUNDSRECT16))},
+ {W32FUN(WG32GetBoundsRect, "GETBOUNDSRECT", MOD_GDI, sizeof(GETBOUNDSRECT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(LOCALAPI, "SETMETAFILEBITSBETTER", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0200 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(WG32DMBitBlt, "DMBITBLT", MOD_GDI, sizeof(DMBITBLT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMCOLORINFO", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMENUMDFONTS", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMENUMOBJ", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMOUTPUT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMPIXEL", MOD_GDI, 0)},
+
+ /*** 0210 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "DMREALIZEOBJECT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMSTRBLT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMSCANLR", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "BRUTE", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMEXTTEXTOUT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMGETCHARWIDTH", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMSTRETCHBLT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMDIBBITS", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMSTRETCHDIBITS", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DMSETDIBTODEV", MOD_GDI, 0)},
+
+ /*** 0220 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "DMTRANSPOSE", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0230 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "CREATEPQ", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "MINPQ", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "EXTRACTPQ", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "INSERTPQ", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SIZEPQ", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DELETEPQ", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0240 ***/
+ {W32FUN(WG32OpenJob, "OPENJOB", MOD_GDI, sizeof(OPENJOB16))},
+ {W32FUN(WG32WriteSpool, "WRITESPOOL", MOD_GDI, sizeof(WRITESPOOL16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "WRITEDIALOG", MOD_GDI, sizeof(WRITEDIALOG16))},
+ {W32FUN(WG32CloseJob, "CLOSEJOB", MOD_GDI, sizeof(CLOSEJOB16))},
+ {W32FUN(WG32DeleteJob, "DELETEJOB", MOD_GDI, sizeof(DELETEJOB16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETSPOOLJOB", MOD_GDI, 0)},
+ {W32FUN(WG32StartSpoolPage, "STARTSPOOLPAGE", MOD_GDI, sizeof(STARTSPOOLPAGE16))},
+ {W32FUN(WG32EndSpoolPage, "ENDSPOOLPAGE", MOD_GDI, sizeof(ENDSPOOLPAGE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "QUERYJOB", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0250 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "COPY", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DELETESPOOLPAGE", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SPOOLFILE", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0260 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "GETOBJECTTYPE", MOD_GDI, 0)},
+ {W32FUN(WG32GetCurrentObject, "GETCURRENTOBJECT", MOD_GDI, sizeof(GETCURRENTOBJECT16))},
+ {W32FUN(WG32GetRegionData, "GETREGIONDATA", MOD_GDI, sizeof(GETREGIONDATA16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0270 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0280 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0290 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0300 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "ENGINEENUMERATEFONT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENGINEDELETEFONT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENGINEREALIZEFONT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENGINEGETCHARWIDTH", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENGINESETFONTCONTEXT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENGINEGETGLYPHBMP", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENGINEMAKEFONTDIR", MOD_GDI, 0)},
+ {W32FUN(WG32GetCharABCWidths, "GETCHARABCWIDTHS", MOD_GDI, sizeof(GETCHARABCWIDTHS16))},
+ {W32FUN(WG32GetOutlineTextMetrics, "GETOUTLINETEXTMETRICS", MOD_GDI, sizeof(GETOUTLINETEXTMETRICS16))},
+ {W32FUN(WG32GetGlyphOutline, "GETGLYPHOUTLINE", MOD_GDI, sizeof(GETGLYPHOUTLINE16))},
+
+ /*** 0310 ***/
+ {W32FUN(WG32CreateScalableFontResource, "CREATESCALABLEFONTRESOURCE",MOD_GDI, sizeof(CREATESCALABLEFONTRESOURCE16))},
+ {W32FUN(WG32GetFontData, "GETFONTDATA", MOD_GDI, sizeof(GETFONTDATA16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "CONVERTOUTLINEFONTFILE", MOD_GDI, 0)},
+ {W32FUN(WG32GetRasterizerCaps, "GETRASTERIZERCAPS", MOD_GDI, sizeof(GETRASTERIZERCAPS16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENGINEEXTTEXTOUT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0320 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0330 ***/
+ {W32FUN(WG32EnumFontFamilies, "ENUMFONTFAMILIES", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(WG32GetKerningPairs, "GETKERNINGPAIRS", MOD_GDI, sizeof(GETKERNINGPAIRS16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0340 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(WG32GetTextAlign, "GETTEXTALIGN", MOD_GDI, sizeof(GETTEXTALIGN16))},
+ {W32FUN(WG32SetTextAlign, "SETTEXTALIGN", MOD_GDI, sizeof(SETTEXTALIGN16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "MFDRAWTEXT", MOD_GDI, 0)},
+ {W32FUN(WG32Chord, "CHORD", MOD_GDI, sizeof(CHORD16))},
+ {W32FUN(WG32SetMapperFlags, "SETMAPPERFLAGS", MOD_GDI, sizeof(SETMAPPERFLAGS16))},
+
+ /*** 0350 ***/
+ {W32FUN(WG32GetCharWidth, "GETCHARWIDTH", MOD_GDI, sizeof(GETCHARWIDTH16))},
+ {W32FUN(WG32ExtTextOut, "EXTTEXTOUT", MOD_GDI, sizeof(EXTTEXTOUT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETPHYSICALFONTHANDLE", MOD_GDI, 0)},
+ {W32FUN(WG32GetAspectRatioFilter, "GETASPECTRATIOFILTER", MOD_GDI, sizeof(GETASPECTRATIOFILTER16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "SHRINKGDIHEAP", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "FTRAPPING0", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0360 ***/
+ {W32FUN(WG32CreatePalette, "CREATEPALETTE", MOD_GDI, sizeof(CREATEPALETTE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GDISELECTPALETTE", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GDIREALIZEPALETTE", MOD_GDI, 0)},
+ {W32FUN(WG32GetPaletteEntries, "GETPALETTEENTRIES", MOD_GDI, sizeof(GETPALETTEENTRIES16))},
+ {W32FUN(WG32SetPaletteEntries, "SETPALETTEENTRIES", MOD_GDI, sizeof(SETPALETTEENTRIES16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "REALIZEDEFAULTPALETTE", MOD_GDI, 0)},
+ {W32FUN(WG32UpdateColors, "UPDATECOLORS", MOD_GDI, sizeof(UPDATECOLORS16))},
+ {W32FUN(WG32AnimatePalette, "ANIMATEPALETTE", MOD_GDI, sizeof(ANIMATEPALETTE16))},
+ {W32FUN(WG32ResizePalette, "RESIZEPALETTE", MOD_GDI, sizeof(RESIZEPALETTE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0370 ***/
+ {W32FUN(WG32GetNearestPaletteIndex, "GETNEARESTPALETTEINDEX", MOD_GDI, sizeof(GETNEARESTPALETTEINDEX16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(WG32ExtFloodFill, "EXTFLOODFILL", MOD_GDI, sizeof(EXTFLOODFILL16))},
+ {W32FUN(WG32SetSystemPaletteUse, "SETSYSTEMPALETTEUSE", MOD_GDI, sizeof(SETSYSTEMPALETTEUSE16))},
+ {W32FUN(WG32GetSystemPaletteUse, "GETSYSTEMPALETTEUSE", MOD_GDI, sizeof(GETSYSTEMPALETTEUSE16))},
+ {W32FUN(WG32GetSystemPaletteEntries, "GETSYSTEMPALETTEENTRIES", MOD_GDI, sizeof(GETSYSTEMPALETTEENTRIES16))},
+ {W32FUN(WG32ResetDC, "RESETDC", MOD_GDI, 0)},
+ {W32FUN(WG32StartDoc, "STARTDOC", MOD_GDI, sizeof(STARTDOC16))},
+ {W32FUN(WG32EndDoc, "ENDDOC", MOD_GDI, 0)},
+ {W32FUN(WG32StartPage, "STARTPAGE", MOD_GDI, 0)},
+
+ /*** 0380 ***/
+ {W32FUN(WG32EndPage, "ENDPAGE", MOD_GDI, 0)},
+ {W32FUN(WG32SetAbortProc, "SETABORTPROC", MOD_GDI, 0)},
+ {W32FUN(WG32AbortDoc, "ABORTDOC", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0390 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0400 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "FASTWINDOWFRAME", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GDIMOVEBITMAP", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GDIINIT2", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "FINALGDIINIT", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "CREATEREALBITMAPINDIRECT", MOD_GDI, 0)},
+ {W32FUN(WG32CreateBitmap, "CREATEUSERBITMAP", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "CREATEREALBITMAP", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "CREATEUSERDISCARDABLEBITMAP",MOD_GDI, 0)},
+
+ /*** 0410 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "ISVALIDMETAFILE", MOD_GDI, 0)},
+ {W32FUN(WG32GetCurLogFont, "GETCURLOGFONT", MOD_GDI, sizeof(GETCURLOGFONT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "ISDCCURRENTPALETTE", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0420 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0430 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(WG32StretchDIBits, "STRETCHDIBITS", MOD_GDI, sizeof(STRETCHDIBITS16))},
+
+ /*** 0440 ***/
+ {W32FUN(WG32SetDIBits, "SETDIBITS", MOD_GDI, sizeof(SETDIBITS16))},
+ {W32FUN(WG32GetDIBits, "GETDIBITS", MOD_GDI, sizeof(GETDIBITS16))},
+ {W32FUN(WG32CreateDIBitmap, "CREATEDIBITMAP", MOD_GDI, sizeof(CREATEDIBITMAP16))},
+ {W32FUN(WG32SetDIBitsToDevice, "SETDIBITSTODEVICE", MOD_GDI, sizeof(SETDIBITSTODEVICE16))},
+ {W32FUN(WG32CreateRoundRectRgn, "CREATEROUNDRECTRGN", MOD_GDI, sizeof(CREATEROUNDRECTRGN16))},
+ {W32FUN(WG32CreateDIBPatternBrush, "CREATEDIBPATTERNBRUSH", MOD_GDI, sizeof(CREATEDIBPATTERNBRUSH16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DEVICECOLORMATCH", MOD_GDI, 0)},
+
+ /*** 0450 ***/
+ {W32FUN(WG32PolyPolygon, "POLYPOLYGON", MOD_GDI, sizeof(POLYPOLYGON16))},
+ {W32FUN(WG32CreatePolyPolygonRgn, "CREATEPOLYPOLYGONRGN", MOD_GDI, sizeof(CREATEPOLYPOLYGONRGN16))},
+ {W32FUN(WG32DeviceMode, "DEVICEMODE", MOD_GDI, sizeof(DEVICEMODE16))},
+ {W32FUN(WG32ExtDeviceMode, "EXTDEVICEMODE", MOD_GDI, sizeof(EXTDEVICEMODE16))},
+ {W32FUN(WG32DeviceCapabilities, "DEVICECAPABILITIES", MOD_GDI, sizeof(DEVICECAPABILITIES16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_GDI, 0)},
+
+ /*** 0460 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "GDITASKTERMINATION", MOD_GDI, 0)},
+ {W32FUN(WG32SetObjectOwner, "SETOBJECTOWNER", MOD_GDI, 0)},
+ {W32FUN(WG32IsGDIObject, "ISGDIOBJECT", MOD_GDI, sizeof(ISGDIOBJECT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "MAKEOBJECTPRIVATE", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "FIXUPBOGUSPUBLISHERMETAFILE",MOD_GDI, 0)},
+ {W32FUN(WG32RectVisible, "RECTVISIBLE_EHH", MOD_GDI, sizeof(RECTVISIBLE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "RECTINREGION_EHH", MOD_GDI, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "UNICODETOANSI", MOD_GDI, 0)},
+ {W32FUN(WG32GetBitmapDimensionEx, "GETBITMAPDIMENSIONEX", MOD_GDI, sizeof(GETBITMAPDIMENSIONEX16))},
+ {W32FUN(WG32GetBrushOrgEx, "GETBRUSHORGEX", MOD_GDI, sizeof(GETBRUSHORGEX16))},
+
+ /*** 0470 ***/
+ {W32FUN(WG32GetCurrentPositionEx, "GETCURRENTPOSITIONEX", MOD_GDI, sizeof(GETCURRENTPOSITIONEX16))},
+ {W32FUN(WG32GetTextExtentPoint, "GETTEXTEXTENTPOINT", MOD_GDI, sizeof(GETTEXTEXTENTPOINT16))},
+ {W32FUN(WG32GetViewportExtEx, "GETVIEWPORTEXTEX", MOD_GDI, sizeof(GETVIEWPORTEXTEX16))},
+ {W32FUN(WG32GetViewportOrgEx, "GETVIEWPORTORGEX", MOD_GDI, sizeof(GETVIEWPORTORGEX16))},
+ {W32FUN(WG32GetWindowExtEx, "GETWINDOWEXTEX", MOD_GDI, sizeof(GETWINDOWEXTEX16))},
+ {W32FUN(WG32GetWindowOrgEx, "GETWINDOWORGEX", MOD_GDI, sizeof(GETWINDOWORGEX16))},
+ {W32FUN(WG32OffsetViewportOrgEx, "OFFSETVIEWPORTORGEX", MOD_GDI, sizeof(OFFSETVIEWPORTORGEX16))},
+ {W32FUN(WG32OffsetWindowOrgEx, "OFFSETWINDOWORGEX", MOD_GDI, sizeof(OFFSETWINDOWORGEX16))},
+ {W32FUN(WG32SetBitmapDimensionEx, "SETBITMAPDIMENSIONEX", MOD_GDI, sizeof(SETBITMAPDIMENSIONEX16))},
+ {W32FUN(WG32SetViewportExtEx, "SETVIEWPORTEXTEX", MOD_GDI, sizeof(SETVIEWPORTEXTEX16))},
+
+ /*** 0480 ***/
+ {W32FUN(WG32SetViewportOrgEx, "SETVIEWPORTORGEX", MOD_GDI, sizeof(SETVIEWPORTORGEX16))},
+ {W32FUN(WG32SetWindowExtEx, "SETWINDOWEXTEX", MOD_GDI, sizeof(SETWINDOWEXTEX16))},
+ {W32FUN(WG32SetWindowOrgEx, "SETWINDOWORGEX", MOD_GDI, sizeof(SETWINDOWORGEX16))},
+ {W32FUN(WG32MoveToEx, "MOVETOEX", MOD_GDI, sizeof(MOVETOEX16))},
+ {W32FUN(WG32ScaleViewportExtEx, "SCALEVIEWPORTEXTEX", MOD_GDI, sizeof(SCALEVIEWPORTEXTEX16))},
+ {W32FUN(WG32ScaleWindowExtEx, "SCALEWINDOWEXTEX", MOD_GDI, sizeof(SCALEWINDOWEXTEX16))},
+ {W32FUN(WG32GetAspectRatioFilterEx, "GETASPECTRATIOFILTEREX", MOD_GDI, sizeof(GETASPECTRATIOFILTEREX16))},
+ {W32FUN(WG32GetDIBColorTable, "GETDIBCOLORTABLE", MOD_GDI, sizeof(GETDIBCOLORTABLE16))},
+ {W32FUN(WG32SetDIBColorTable, "SETDIBCOLORTABLE", MOD_GDI, sizeof(SETDIBCOLORTABLE16))},
+ {W32FUN(WG32CreateDIBSection, "CREATEDIBSECTION", MOD_GDI, sizeof(CREATEDIBSECTION16))},
+
+ /*** 0490 ***/
+ {W32FUN(WG32PolyPolylineWOW, "POLYPOLYLINEWOW", MOD_GDI, sizeof(POLYPOLYLINEWOW16))},
diff --git a/private/mvdm/wow32/wgtext.c b/private/mvdm/wow32/wgtext.c
new file mode 100644
index 000000000..4a808a1a3
--- /dev/null
+++ b/private/mvdm/wow32/wgtext.c
@@ -0,0 +1,294 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGTEXT.C
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+ * 10-Nov-1992 Modified GetTextMetrics to GetTextMetricsWOW by Chandan Chauhan
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wgtext.c);
+
+
+ULONG FASTCALL WG32ExtTextOut(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t5;
+ PSTR pstr6;
+ PINT p8;
+ register PEXTTEXTOUT16 parg16;
+ INT BufferT[256];
+
+ GETARGPTR(pFrame, sizeof(EXTTEXTOUT16), parg16);
+ GETRECT16(parg16->f5, &t5);
+ GETSTRPTR(parg16->f6, parg16->f7, pstr6);
+ if (DWORD32(parg16->f8)) {
+ p8 = STACKORHEAPALLOC(parg16->f7 * sizeof(INT), sizeof(BufferT), BufferT);
+ getintarray16((VPINT16)DWORD32(parg16->f8), parg16->f7, p8); // *this* INT array is optional
+ } else {
+ p8 = NULL;
+ }
+
+
+ ul = GETBOOL16(ExtTextOut(
+ HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ (WORD32(parg16->f4) & (ETO_CLIPPED|ETO_OPAQUE)),
+ &t5,
+ pstr6,
+ WORD32(parg16->f7),
+ (LPINT)p8
+ ));
+
+ FREESTRPTR(pstr6);
+ STACKORHEAPFREE(p8, BufferT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetTextAlign(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETTEXTALIGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETTEXTALIGN16), parg16);
+
+ ul = GETWORD16(GetTextAlign(
+ HDC32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetTextCharacterExtra(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETTEXTCHARACTEREXTRA16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETTEXTCHARACTEREXTRA16), parg16);
+
+ ul = GETINT16(GetTextCharacterExtra(
+ HDC32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetTextColor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETTEXTCOLOR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETTEXTCOLOR16), parg16);
+
+ ul = GETDWORD16(GetTextColor(
+ HDC32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetTextExtent(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSTR pstr2;
+ SIZE size4;
+ register PGETTEXTEXTENT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETTEXTEXTENT16), parg16);
+ GETSTRPTR(parg16->f2, parg16->f3, pstr2);
+
+ if (GETDWORD16(GetTextExtentPoint(
+ HDC32(parg16->f1),
+ pstr2,
+ INT32(parg16->f3),
+ &size4
+ )))
+ {
+ // check if either cx or cy are bigger than SHRT_MAX == 7fff
+ // but do it in ONE SINGLE check
+
+ if ((size4.cx | size4.cy) & ~SHRT_MAX)
+ {
+ if (size4.cx > SHRT_MAX)
+ ul = SHRT_MAX;
+ else
+ ul = (ULONG)size4.cx;
+
+ if (size4.cy > SHRT_MAX)
+ ul |= (SHRT_MAX << 16);
+ else
+ ul |= (ULONG)(size4.cy << 16);
+ }
+ else
+ {
+ ul = (ULONG)(size4.cx | (size4.cy << 16));
+ }
+
+ }
+ FREESTRPTR(pstr2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetTextFace(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PBYTE pb3;
+ register PGETTEXTFACE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETTEXTFACE16), parg16);
+ ALLOCVDMPTR(parg16->f3, parg16->f2, pb3);
+
+ ul = GETINT16(GetTextFace(
+ HDC32(parg16->f1),
+ INT32(parg16->f2),
+ pb3
+ ));
+
+ FLUSHVDMPTR(parg16->f3, (USHORT)ul, pb3);
+ FREEVDMPTR(pb3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32GetTextMetrics(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ TEXTMETRIC t2;
+ register PGETTEXTMETRICS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETTEXTMETRICS16), parg16);
+
+ ul = GETBOOL16(GetTextMetrics(
+ HDC32(parg16->f1),
+ &t2
+ ));
+
+
+ PUTTEXTMETRIC16(parg16->f2, &t2);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetTextAlign(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETTEXTALIGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETTEXTALIGN16), parg16);
+
+ ul = GETWORD16(SetTextAlign(
+ HDC32(parg16->f1),
+ WORD32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetTextCharacterExtra(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETTEXTCHARACTEREXTRA16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETTEXTCHARACTEREXTRA16), parg16);
+
+ ul = GETINT16(SetTextCharacterExtra(
+ HDC32(parg16->f1),
+ INT32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetTextColor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETTEXTCOLOR16 parg16;
+ COLORREF color;
+
+ GETARGPTR(pFrame, sizeof(SETTEXTCOLOR16), parg16);
+
+ color = DWORD32(parg16->f2);
+
+ if (((ULONG)color >= 0x03000000) &&
+ (HIWORD(color) != 0x10ff))
+ {
+ color &= 0xffffff;
+ }
+
+ ul = GETDWORD16(SetTextColor(
+ HDC32(parg16->f1),
+ color
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32SetTextJustification(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETTEXTJUSTIFICATION16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETTEXTJUSTIFICATION16), parg16);
+
+ ul = GETINT16(SetTextJustification(
+ HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32TextOut(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSTR pstr4;
+ register PTEXTOUT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(TEXTOUT16), parg16);
+ GETSTRPTR(parg16->f4, parg16->f5, pstr4);
+
+ ul = GETBOOL16(TextOut(
+ HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ pstr4,
+ INT32(parg16->f5)
+ ));
+
+ FREESTRPTR(pstr4);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
diff --git a/private/mvdm/wow32/wgtext.h b/private/mvdm/wow32/wgtext.h
new file mode 100644
index 000000000..6d23e0f27
--- /dev/null
+++ b/private/mvdm/wow32/wgtext.h
@@ -0,0 +1,27 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WGTEXT.H
+ * WOW32 16-bit GDI API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WG32ExtTextOut(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetTextAlign(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetTextCharacterExtra(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetTextColor(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetTextExtent(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetTextFace(PVDMFRAME pFrame);
+ULONG FASTCALL WG32GetTextMetrics(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetTextAlign(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetTextCharacterExtra(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetTextColor(PVDMFRAME pFrame);
+ULONG FASTCALL WG32SetTextJustification(PVDMFRAME pFrame);
+ULONG FASTCALL WG32TextOut(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wheap.c b/private/mvdm/wow32/wheap.c
new file mode 100644
index 000000000..b424e475e
--- /dev/null
+++ b/private/mvdm/wow32/wheap.c
@@ -0,0 +1,48 @@
+//*****************************************************************************
+//
+// Small Heap -
+//
+// This heap is used for allocating small size linked list structures.
+// This will reduce WOW's working set as the linked structures will be
+// together (less scattered) than if they were allocated from the
+// general purpose wow heap.
+//
+// 07-Oct-93 NanduriR Created.
+//
+//*****************************************************************************
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wheap.c);
+
+
+
+HANDLE hWOWHeapSmall;
+
+
+BOOL FASTCALL CreateSmallHeap()
+{
+ hWOWHeapSmall = HeapCreate (HEAP_NO_SERIALIZE, 4096, GROW_HEAP_AS_NEEDED);
+ return (BOOL)hWOWHeapSmall;
+}
+
+
+PVOID FASTCALL malloc_w_small (ULONG size)
+{
+ PVOID pv = HeapAlloc(hWOWHeapSmall, 0, size);
+
+#ifdef DEBUG
+ if (pv == (PVOID)NULL) {
+ LOGDEBUG(0, ("malloc_w_small: HeapAlloc failed\n"));
+ }
+#endif
+ return pv;
+
+}
+
+
+BOOL FASTCALL free_w_small(PVOID p)
+{
+ return HeapFree(hWOWHeapSmall, 0, (LPSTR)(p));
+}
diff --git a/private/mvdm/wow32/wheap.h b/private/mvdm/wow32/wheap.h
new file mode 100644
index 000000000..454bd9ff8
--- /dev/null
+++ b/private/mvdm/wow32/wheap.h
@@ -0,0 +1,36 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WHEAP.H
+ * WOW32 Heap Support (Instead of using malloc/free from CRT)
+ *
+ * History:
+ * Created 13-Dec-1991 by Sudeep Bharati (sudeepb)
+--*/
+
+//
+// Dynamic memory macros
+//
+// On checked (debug) builds, malloc_w and friends complain when they fail.
+//
+
+PVOID FASTCALL malloc_w(ULONG size);
+PVOID FASTCALL malloc_w_zero (ULONG size);
+PVOID FASTCALL realloc_w (PVOID p, ULONG size, DWORD dwFlags);
+VOID FASTCALL free_w(PVOID p);
+
+PVOID FASTCALL malloc_w_or_die(ULONG size);
+
+#define INITIAL_WOW_HEAP_SIZE 32*1024 // 32k
+#define GROW_HEAP_AS_NEEDED 0 // grow heap as needed
+
+
+//*****************************************************************************
+// Small Heap -
+//*****************************************************************************
+BOOL FASTCALL CreateSmallHeap(VOID);
+PVOID FASTCALL malloc_w_small (ULONG size);
+BOOL FASTCALL free_w_small(PVOID p);
diff --git a/private/mvdm/wow32/win30api.xls b/private/mvdm/wow32/win30api.xls
new file mode 100644
index 000000000..4dd091ffe
--- /dev/null
+++ b/private/mvdm/wow32/win30api.xls
Binary files differ
diff --git a/private/mvdm/wow32/winsockp.h b/private/mvdm/wow32/winsockp.h
new file mode 100644
index 000000000..187a7c78f
--- /dev/null
+++ b/private/mvdm/wow32/winsockp.h
@@ -0,0 +1,195 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ Winsockp.h
+
+Abstract:
+
+ Private header file for WOW winsock support.
+
+Author:
+
+ David Treadwell (davidtr) 02-Oct-1992
+
+Revision History:
+
+--*/
+
+#include "wow32.h"
+#include <winsock.h>
+#include <wowwsock.h>
+#include "wcall16.h"
+#include "wsocktbl.h"
+
+typedef struct _WINSOCK_THREAD_DATA {
+ VPVOID vIpAddress;
+ VPHOSTENT16 vHostent;
+ VPSERVENT16 vServent;
+ VPPROTOENT16 vProtoent;
+ VPPROC vBlockingHook;
+ DWORD ThreadSerialNumber;
+ DWORD ThreadStartupCount;
+ WORD ThreadVersion;
+} WINSOCK_THREAD_DATA, *PWINSOCK_THREAD_DATA;
+
+extern DWORD WWS32TlsSlot;
+extern RTL_CRITICAL_SECTION WWS32CriticalSection;
+extern LIST_ENTRY WWS32AsyncContextBlockListHead;
+extern WORD WWS32AsyncTaskHandleCounter;
+extern LIST_ENTRY WWS32SocketHandleListHead;
+extern WORD WWS32SocketHandleCounter;
+extern BOOL WWS32SocketHandleCounterWrapped;
+extern DWORD WWS32ThreadSerialNumberCounter;
+
+#define WWS32IpAddress \
+ ( ((PWINSOCK_THREAD_DATA)(TlsGetValue( WWS32TlsSlot )))->IpAddress )
+#define WWS32vIpAddress \
+ ( ((PWINSOCK_THREAD_DATA)(TlsGetValue( WWS32TlsSlot )))->vIpAddress )
+#define WWS32vHostent \
+ ( ((PWINSOCK_THREAD_DATA)(TlsGetValue( WWS32TlsSlot )))->vHostent )
+#define WWS32vServent \
+ ( ((PWINSOCK_THREAD_DATA)(TlsGetValue( WWS32TlsSlot )))->vServent )
+#define WWS32vProtoent \
+ ( ((PWINSOCK_THREAD_DATA)(TlsGetValue( WWS32TlsSlot )))->vProtoent )
+#define WWS32vBlockingHook \
+ ( ((PWINSOCK_THREAD_DATA)(TlsGetValue( WWS32TlsSlot )))->vBlockingHook )
+#define WWS32ThreadSerialNumber \
+ ( ((PWINSOCK_THREAD_DATA)(TlsGetValue( WWS32TlsSlot )))->ThreadSerialNumber )
+#define WWS32ThreadStartupCount \
+ ( ((PWINSOCK_THREAD_DATA)(TlsGetValue( WWS32TlsSlot )))->ThreadStartupCount )
+#define WWS32ThreadVersion \
+ ( ((PWINSOCK_THREAD_DATA)(TlsGetValue( WWS32TlsSlot )))->ThreadVersion )
+
+#define WWS32IsThreadVersion10 ( WWS32ThreadVersion == MAKEWORD(1, 0) )
+#define WWS32IsThreadVersion11 ( WWS32ThreadVersion == MAKEWORD(1, 1) )
+
+#define WWS32IsThreadInitialized \
+ ( TlsGetValue( WWS32TlsSlot ) == NULL ? FALSE : TRUE )
+
+typedef struct _WINSOCK_ASYNC_CONTEXT_BLOCK {
+ LIST_ENTRY ContextBlockListEntry;
+ HANDLE AsyncTaskHandle32;
+ HAND16 AsyncTaskHandle16;
+ VPVOID vBuffer16;
+ DWORD Buffer16Length;
+ PVOID Buffer32;
+} WINSOCK_ASYNC_CONTEXT_BLOCK, *PWINSOCK_ASYNC_CONTEXT_BLOCK;
+
+typedef struct _WINSOCK_SOCKET_INFO {
+ LIST_ENTRY GlobalSocketListEntry;
+ SOCKET SocketHandle32;
+ DWORD ThreadSerialNumber;
+ HAND16 SocketHandle16;
+} WINSOCK_SOCKET_INFO, *PWINSOCK_SOCKET_INFO;
+
+PFD_SET
+AllocateFdSet32 (
+ IN PFD_SET16 FdSet16
+ );
+
+INT
+ConvertFdSet16To32 (
+ IN PFD_SET16 FdSet16,
+ IN PFD_SET FdSet32
+ );
+
+VOID
+ConvertFdSet32To16 (
+ IN PFD_SET FdSet32,
+ IN PFD_SET16 FdSet16
+ );
+
+int PASCAL
+WSApSetPostRoutine (
+ IN PVOID PostRoutine
+ );
+
+typedef
+BOOL
+(*PWINSOCK_POST_ROUTINE) (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL
+WWS32DispatchPostMessage (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL
+WWS32PostAsyncSelect (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL
+WWS32PostAsyncGetHost (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL
+WWS32PostAsyncGetProto (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL
+WWS32PostAsyncGetServ (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+PWINSOCK_ASYNC_CONTEXT_BLOCK
+WWS32FindAndRemoveAsyncContext (
+ IN HANDLE AsyncTaskHandle32
+ );
+
+HAND16
+WWS32GetAsyncTaskHandle16 (
+ VOID
+ );
+
+VOID
+WWS32TaskCleanup(
+ VOID
+ );
+
+//
+// Message types used by WWS32DispatchPostMessage to dispatch a post
+// message call to the appropriate routine.
+//
+
+#define WWS32_MESSAGE_ASYNC_SELECT 0
+#define WWS32_MESSAGE_ASYNC_GETHOST 1
+#define WWS32_MESSAGE_ASYNC_GETPROTO 2
+#define WWS32_MESSAGE_ASYNC_GETSERV 3
+
+//
+// An arbitrary value that indicates the default blocking hook is in use.
+//
+
+#define WWS32_DEFAULT_BLOCKING_HOOK 0xFFFFFFFF
+
+//
+// Determine if a pointer is DWORD aligned.
+//
+
+#define IS_DWORD_ALIGNED(p) (((DWORD)(p) & (sizeof(DWORD)-1)) == 0)
+
diff --git a/private/mvdm/wow32/winspldl.h b/private/mvdm/wow32/winspldl.h
new file mode 100644
index 000000000..dac8926ce
--- /dev/null
+++ b/private/mvdm/wow32/winspldl.h
@@ -0,0 +1,28 @@
+
+extern BOOL fWinspoolLoaded;
+
+
+extern DWORD (WINAPI *lpfnDEVICECAPABILITIES)(LPSTR lpDriverName, LPSTR lpDeviceName,
+ WORD nIndex, LPSTR lpOutput, LPDEVMODE lpDevMode);
+
+extern BOOL (WINAPI *lpfnDEVICEMODE)(HWND hWnd, LPSTR lpDriverName, LPSTR lpDeviceName, LPSTR lpOutput);
+
+extern DWORD (WINAPI *lpfnEXTDEVICEMODE)(HWND hWnd,LPSTR lpDriverName,
+ LPDEVMODE lpDevModeOutput, LPSTR lpDeviceName, LPSTR lpPort,
+ LPDEVMODE lpDevModeInput, LPSTR lpProfile, DWORD flMode);
+
+extern BOOL (WINAPI *lpfnOpenPrinter)(LPSTR pPrinterName, LPHANDLE phPrinter,
+ VOID *pDefault);
+
+extern DWORD (WINAPI *lpfnStartDocPrinter)(HANDLE hPrinter, DWORD Level,
+ LPBYTE pDocInfo);
+
+extern BOOL (WINAPI *lpfnStartPagePrinter)(HANDLE hPrinter);
+extern BOOL (WINAPI *lpfnEndPagePrinter)(HANDLE hPrinter);
+extern BOOL (WINAPI *lpfnEndDocPrinter)(HANDLE hPrinter);
+extern BOOL (WINAPI *lpfnClosePrinter)(HANDLE hPrinter);
+extern BOOL (WINAPI *lpfnWritePrinter)(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
+ LPDWORD pcWritten);
+extern BOOL (WINAPI *lpfnDeletePrinter)(HANDLE hPrinter);
+
+BOOL LoadWinspoolAndGetProcAddresses();
diff --git a/private/mvdm/wow32/wintype.xls b/private/mvdm/wow32/wintype.xls
new file mode 100644
index 000000000..db4689b4b
--- /dev/null
+++ b/private/mvdm/wow32/wintype.xls
Binary files differ
diff --git a/private/mvdm/wow32/witbl.h b/private/mvdm/wow32/witbl.h
new file mode 100644
index 000000000..b778dcb39
--- /dev/null
+++ b/private/mvdm/wow32/witbl.h
@@ -0,0 +1,23 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WITBL.H
+ * WOW32 16-bit Internal API tables
+ *
+ * History:
+ * Created 22-Apr-1992 by FritzS
+--*/
+
+
+
+/* Internal dispatch table
+ */
+extern W32 aw32Internal[];
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iInternalMax;
+#endif
diff --git a/private/mvdm/wow32/wkbdtbl2.h b/private/mvdm/wow32/wkbdtbl2.h
new file mode 100644
index 000000000..d49503d52
--- /dev/null
+++ b/private/mvdm/wow32/wkbdtbl2.h
@@ -0,0 +1,177 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKBTBL2.h
+ * WOW32 16-bit Keyboard API tables
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_KEYBOARD, 0)},
+ {W32FUN(LOCALAPI, "INQUIRE", MOD_KEYBOARD, 0)},
+ {W32FUN(LOCALAPI, "ENABLE", MOD_KEYBOARD, 0)},
+ {W32FUN(LOCALAPI, "DISABLE", MOD_KEYBOARD, 0)},
+ {W32FUN(WKB32ToAscii, "TOASCII", MOD_KEYBOARD, sizeof(TOASCII16))},
+ {W32FUN(WKB32AnsiToOem, "ANSITOOEM", MOD_KEYBOARD, sizeof(ANSITOOEM16))},
+ {W32FUN(WKB32OemToAnsi, "OEMTOANSI", MOD_KEYBOARD, sizeof(OEMTOANSI16))},
+ {W32FUN(LOCALAPI, "SETSPEED", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0010 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0020 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0030 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0040 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0050 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0060 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0070 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0080 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0090 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0100 ***/
+ {W32FUN(LOCALAPI, "SCREENSWITCHENABLE",MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0110 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+
+ /*** 0120 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KEYBOARD, 0)},
+ {W32FUN(LOCALAPI, "GETTABLESEG", MOD_KEYBOARD, 0)},
+ {W32FUN(LOCALAPI, "NEWTABLE", MOD_KEYBOARD, 0)},
+ {W32FUN(WKB32OemKeyScan, "OEMKEYSCAN", MOD_KEYBOARD, sizeof(OEMKEYSCAN16))},
+ {W32FUN(WKB32VkKeyScan, "VKKEYSCAN", MOD_KEYBOARD, sizeof(VKKEYSCAN16))},
+
+ /*** 0130 ***/
+ {W32FUN(WKB32GetKeyboardType, "GETKEYBOARDTYPE", MOD_KEYBOARD, sizeof(GETKEYBOARDTYPE16))},
+ {W32FUN(WKB32MapVirtualKey, "MAPVIRTUALKEY", MOD_KEYBOARD, sizeof(MAPVIRTUALKEY16))},
+ {W32FUN(WKB32GetKBCodePage, "GETKBCODEPAGE", MOD_KEYBOARD, 0)},
+ {W32FUN(WKB32GetKeyNameText, "GETKEYNAMETEXT", MOD_KEYBOARD, sizeof(GETKEYNAMETEXT16))},
+ {W32FUN(WKB32AnsiToOemBuff, "ANSITOOEMBUFF", MOD_KEYBOARD, sizeof(ANSITOOEMBUFF16))},
+ {W32FUN(WKB32OemToAnsiBuff, "OEMTOANSIBUFF", MOD_KEYBOARD, sizeof(OEMTOANSIBUFF16))},
+ {W32FUN(LOCALAPI, "ENABLEKBSYSREQ", MOD_KEYBOARD, 0)},
+ {W32FUN(LOCALAPI, "GETBIOSKEYPROC", MOD_KEYBOARD, 0)},
diff --git a/private/mvdm/wow32/wkbman.c b/private/mvdm/wow32/wkbman.c
new file mode 100644
index 000000000..9d4f3073d
--- /dev/null
+++ b/private/mvdm/wow32/wkbman.c
@@ -0,0 +1,225 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKBMAN.C
+ * WOW32 16-bit Keyboard API support (manually-coded thunks)
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * Modified 13-Jan-1992 by Nandurir . Added all the code.
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wkbman.c);
+
+ULONG FASTCALL WKB32ToAscii(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PTOASCII16 parg16;
+ LPSTR lpstrT;
+ LPVOID lpvoidT;
+
+ GETARGPTR(pFrame, sizeof(TOASCII16), parg16);
+ GETPSZPTR(parg16->f3, lpstrT);
+ GETMISCPTR(parg16->f4, lpvoidT);
+
+ ul = ToAscii((WORD)(parg16->f1),
+ (WORD)(parg16->f2),
+ lpstrT,
+ lpvoidT,
+ (WORD)(parg16->f5));
+
+
+ FREEPSZPTR(lpstrT);
+ FLUSHVDMPTR(parg16->f4, 4, lpvoidT);
+ FREEMISCPTR(lpvoidT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WKB32AnsiToOem(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ int cb;
+ register PANSITOOEM16 parg16;
+ LPSTR lpstrAnsi, lpstrOem;
+
+ GETARGPTR(pFrame, sizeof(ANSITOOEM16), parg16);
+ GETPSZPTR(parg16->f1, lpstrAnsi);
+ GETPSZPTR(parg16->f2, lpstrOem);
+
+ cb = strlen(lpstrAnsi);
+
+ ul = AnsiToOem(lpstrAnsi, lpstrOem);
+
+ FLUSHVDMPTR(parg16->f2, cb, lpstrOem);
+ FREEPSZPTR(lpstrAnsi);
+ FREEPSZPTR(lpstrOem);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WKB32OemToAnsi(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ int cb;
+ register POEMTOANSI16 parg16;
+ LPSTR lpstrAnsi, lpstrOem;
+
+ GETARGPTR(pFrame, sizeof(OEMTOANSI16), parg16);
+ GETPSZPTR(parg16->f1, lpstrOem);
+ GETPSZPTR(parg16->f2, lpstrAnsi);
+
+ cb = strlen(lpstrOem);
+
+ ul = OemToAnsi(lpstrOem, lpstrAnsi);
+
+ FLUSHVDMPTR(parg16->f2, cb, lpstrAnsi);
+ FREEPSZPTR(lpstrOem);
+ FREEPSZPTR(lpstrAnsi);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WKB32OemKeyScan(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register POEMKEYSCAN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OEMKEYSCAN16), parg16);
+
+ ul = (ULONG)OemKeyScan((WORD)(parg16->f1));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WKB32VkKeyScan(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PVKKEYSCAN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(VKKEYSCAN16), parg16);
+
+ ul = (ULONG)VkKeyScan((CHAR)(parg16->f1));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WKB32GetKeyboardType(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETKEYBOARDTYPE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETKEYBOARDTYPE16), parg16);
+
+ ul = GetKeyboardType(INT32(parg16->f1));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WKB32MapVirtualKey(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PMAPVIRTUALKEY16 parg16;
+
+ GETARGPTR(pFrame, sizeof(MAPVIRTUALKEY16), parg16);
+
+ ul = MapVirtualKey((UINT)(parg16->f1), (UINT)(parg16->f2));
+
+ // MapVirtualKey sets the high bit (Win16 & Win32) to indicate diacritic
+ if (ul & 0x80000000) {
+ ul |= 0x8000;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WKB32GetKBCodePage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ ul = (ULONG)GetKBCodePage();
+
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WKB32GetKeyNameText(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETKEYNAMETEXT16 parg16;
+ LPSTR lpstrT;
+
+ GETARGPTR(pFrame, sizeof(GETKEYNAMETEXT16), parg16);
+ GETPSZPTR(parg16->f2, lpstrT);
+
+ ul = (ULONG)GetKeyNameText(DWORD32(parg16->f1), lpstrT,
+ (INT)(WORD)(parg16->f3));
+
+ FLUSHVDMPTR(parg16->f2, (WORD) (parg16->f3), lpstrT);
+ FREEPSZPTR(lpstrT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WKB32AnsiToOemBuff(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PANSITOOEMBUFF16 parg16;
+ LPSTR lpstrAnsi, lpstrOem;
+
+ GETARGPTR(pFrame, sizeof(ANSITOOEMBUFF16), parg16);
+ GETPSZPTR(parg16->f1, lpstrAnsi);
+ GETPSZPTR(parg16->f2, lpstrOem);
+
+
+ ul = AnsiToOemBuff(lpstrAnsi, lpstrOem, (DWORD)(WORD)(parg16->f3));
+
+ FLUSHVDMPTR(parg16->f2, ((parg16->f3) ? (parg16->f3) : 0xFFFF), lpstrOem);
+ FREEPSZPTR(lpstrAnsi);
+ FREEPSZPTR(lpstrOem);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WKB32OemToAnsiBuff(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register POEMTOANSIBUFF16 parg16;
+ LPSTR lpstrAnsi, lpstrOem;
+
+ GETARGPTR(pFrame, sizeof(OEMTOANSIBUFF16), parg16);
+ GETPSZPTR(parg16->f1, lpstrOem);
+ GETPSZPTR(parg16->f2, lpstrAnsi);
+
+ ul = (ULONG)OemToAnsiBuff(lpstrOem, lpstrAnsi, (DWORD)(WORD)(parg16->f3));
+
+ FLUSHVDMPTR(parg16->f2, ((parg16->f3) ? (parg16->f3) : 0xFFFF), lpstrAnsi);
+ FREEPSZPTR(lpstrOem);
+ FREEPSZPTR(lpstrAnsi);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wkbman.h b/private/mvdm/wow32/wkbman.h
new file mode 100644
index 000000000..456a52f03
--- /dev/null
+++ b/private/mvdm/wow32/wkbman.h
@@ -0,0 +1,31 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKBMAN.H
+ * WOW32 16-bit Keyboard API support (manually-coded thunks)
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* Keyboard thunks
+ */
+
+
+ULONG FASTCALL WKB32ToAscii(PVDMFRAME pFrame);
+ULONG FASTCALL WKB32AnsiToOem(PVDMFRAME pFrame);
+ULONG FASTCALL WKB32OemToAnsi(PVDMFRAME pFrame);
+ULONG FASTCALL WKB32OemKeyScan(PVDMFRAME pFrame);
+ULONG FASTCALL WKB32VkKeyScan(PVDMFRAME pFrame);
+ULONG FASTCALL WKB32GetKeyboardType(PVDMFRAME pFrame);
+ULONG FASTCALL WKB32MapVirtualKey(PVDMFRAME pFrame);
+ULONG FASTCALL WKB32GetKBCodePage(PVDMFRAME pFrame);
+ULONG FASTCALL WKB32GetKeyNameText(PVDMFRAME pFrame);
+ULONG FASTCALL WKB32AnsiToOemBuff(PVDMFRAME pFrame);
+ULONG FASTCALL WKB32OemToAnsiBuff(PVDMFRAME pFrame);
+
diff --git a/private/mvdm/wow32/wkbtbl.h b/private/mvdm/wow32/wkbtbl.h
new file mode 100644
index 000000000..c1f0919ec
--- /dev/null
+++ b/private/mvdm/wow32/wkbtbl.h
@@ -0,0 +1,23 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKBTBL.H
+ * WOW32 16-bit Keyboard API tables
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* Keyboard dispatch table
+ */
+extern W32 aw32Keyboard[];
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iKeyboardMax;
+#endif
diff --git a/private/mvdm/wow32/wkernel.c b/private/mvdm/wow32/wkernel.c
new file mode 100644
index 000000000..80562472f
--- /dev/null
+++ b/private/mvdm/wow32/wkernel.c
@@ -0,0 +1,816 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKERNEL.C
+ * WOW32 16-bit Kernel API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wkernel.c);
+
+ULONG FASTCALL WK32RegOpenKey32(PVDMFRAME pFrame)
+{
+ HKEY hKey, hKeyTmp;
+ PSZ pszKey;
+ PHKEY phKey;
+ register PREGOPENKEY3216 parg16;
+ ULONG ulRet;
+
+ GETARGPTR(pFrame, sizeof(REGOPENKEY3216), parg16);
+ hKey = (HKEY) FETCHDWORD(parg16->hKey);
+ GETPSZPTR(parg16->lpszSubKey, pszKey);
+ GETVDMPTR(parg16->phkResult, sizeof(*phKey), phKey);
+
+ ulRet = RegOpenKey(hKey, pszKey, &hKeyTmp);
+
+ STOREDWORD(*phKey, hKeyTmp);
+ FREEVDMPTR(phKey);
+ FREEPSZPTR(pszKey);
+ FREEARGPTR(parg16);
+
+ return ulRet;
+
+}
+
+ULONG FASTCALL WK32RegEnumKey32(PVDMFRAME pFrame)
+{
+ HKEY hKey;
+ DWORD dwSubKey;
+ PSZ pszName;
+ DWORD cchName;
+ register PREGENUMKEY3216 parg16;
+ ULONG ulRet;
+
+ GETARGPTR(pFrame, sizeof(REGENUMKEY3216), parg16);
+ hKey = (HKEY) FETCHDWORD(parg16->hKey);
+ dwSubKey = FETCHDWORD(parg16->iSubKey);
+ GETPSZPTR(parg16->lpszName, pszName);
+ cchName = FETCHDWORD(parg16->cchName);
+ ulRet = RegEnumKey(hKey, dwSubKey, pszName, cchName);
+
+ FREEPSZPTR(pszName);
+ FREEARGPTR(parg16);
+
+ return ulRet;
+}
+
+ULONG FASTCALL WK32RegEnumValue32(PVDMFRAME pFrame)
+{
+ HKEY hKey;
+ DWORD dwValue, cchValueTmp, dwTypeTmp, cbDataTmp;
+ PSZ pszValue;
+ LPDWORD lpcchValue;
+ LPDWORD lpdwType;
+ LPBYTE lpbData;
+ LPDWORD lpcbData;
+ register PREGENUMVALUE3216 parg16;
+ ULONG ulRet;
+
+ GETARGPTR(pFrame, sizeof(REGENUMVALUE3216), parg16);
+ hKey = (HKEY) FETCHDWORD(parg16->hKey);
+ dwValue = FETCHDWORD(parg16->iValue);
+ GETPSZPTR(parg16->lpszValue, pszValue);
+ GETVDMPTR(parg16->lpcchValue, sizeof(*lpcchValue), lpcchValue);
+ cchValueTmp = FETCHDWORD(*lpcchValue);
+ GETVDMPTR(parg16->lpdwType, sizeof(*lpdwType), lpdwType);
+ dwTypeTmp = FETCHDWORD(*lpdwType);
+ GETMISCPTR(parg16->lpbData, lpbData);
+ GETVDMPTR(parg16->lpcbData, sizeof(*lpcbData), lpcbData);
+ cbDataTmp = FETCHDWORD(*lpcbData);
+
+ ulRet = RegEnumValue(hKey, dwValue, pszValue, &cchValueTmp,
+ NULL, &dwTypeTmp, lpbData, &cbDataTmp);
+
+ STOREDWORD(*lpcchValue, cchValueTmp);
+ STOREDWORD(*lpdwType, dwTypeTmp);
+ STOREDWORD(*lpcbData, cbDataTmp);
+
+ FREEVDMPTR(lpcbData);
+ FREEMISCPTR(lpbData);
+ FREEVDMPTR(lpdwType);
+ FREEVDMPTR(lpcchValue);
+ FREEPSZPTR(pszValue);
+ FREEARGPTR(parg16);
+
+ return ulRet;
+}
+
+ULONG FASTCALL WK32RegCloseKey32(PVDMFRAME pFrame)
+{
+ HKEY hKey;
+ register PREGCLOSEKEY3216 parg16;
+ ULONG ulRet;
+
+ GETARGPTR(pFrame, sizeof(REGCLOSEKEY3216), parg16);
+ hKey = (HKEY) FETCHDWORD(parg16->hKey);
+ ulRet = RegCloseKey(hKey);
+
+ FREEARGPTR(parg16);
+
+ return ulRet;
+}
+
+ULONG FASTCALL WK32WritePrivateProfileString(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ pszSection;
+ PSZ pszKey;
+ PSZ pszValue;
+ PSZ pszFilename;
+ register PWRITEPRIVATEPROFILESTRING16 parg16;
+ BOOL fIsWinIni;
+ CHAR szLowercase[MAX_PATH];
+
+ GETARGPTR(pFrame, sizeof(WRITEPRIVATEPROFILESTRING16), parg16);
+ GETPSZPTR(parg16->f1, pszSection);
+ GETPSZPTR(parg16->f2, pszKey);
+ GETPSZPTR(parg16->f3, pszValue);
+ GETPSZPTR(parg16->f4, pszFilename);
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+ strcpy(szLowercase, pszFilename);
+ _strlwr(szLowercase);
+
+ fIsWinIni = IS_WIN_INI(szLowercase);
+
+ // Trying to install or change default printer to fax printer?
+ if (fIsWinIni &&
+ pszSection &&
+ pszKey &&
+ pszValue &&
+ !_stricmp(pszSection, szDevices) &&
+ IsFaxPrinterWriteProfileString(pszSection, pszKey, pszValue)) {
+
+ ul = TRUE;
+ goto Done;
+ }
+
+ ul = GETBOOL16( WritePrivateProfileString(
+ pszSection,
+ pszKey,
+ pszValue,
+ pszFilename
+ ));
+
+ if( ul != 0 &&
+ fIsWinIni &&
+ IS_EMBEDDING_SECTION( pszSection ) &&
+ pszKey != NULL &&
+ pszValue != NULL ) {
+
+ UpdateClassesRootSubKey( pszKey, pszValue);
+ }
+
+Done:
+ FREEPSZPTR(pszSection);
+ FREEPSZPTR(pszKey);
+ FREEPSZPTR(pszValue);
+ FREEPSZPTR(pszFilename);
+ FREEARGPTR(parg16);
+
+ return ul;
+}
+
+
+ULONG FASTCALL WK32WriteProfileString(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ pszSection;
+ PSZ pszKey;
+ PSZ pszValue;
+ register PWRITEPROFILESTRING16 parg16;
+
+ GETARGPTR(pFrame, sizeof(WRITEPROFILESTRING16), parg16);
+ GETPSZPTR(parg16->f1, pszSection);
+ GETPSZPTR(parg16->f2, pszKey);
+ GETPSZPTR(parg16->f3, pszValue);
+
+ // Trying to install or change default printer to fax printer?
+ if (pszSection &&
+ pszKey &&
+ pszValue &&
+ !_stricmp(pszSection, szDevices) &&
+ IsFaxPrinterWriteProfileString(pszSection, pszKey, pszValue)) {
+
+ ul = TRUE;
+ goto Done;
+ }
+
+ ul = GETBOOL16( WriteProfileString(
+ pszSection,
+ pszKey,
+ pszValue
+ ));
+
+ if( ( ul != 0 ) &&
+ IS_EMBEDDING_SECTION( pszSection ) &&
+ ( pszKey != NULL ) &&
+ ( pszValue != NULL ) ) {
+ UpdateClassesRootSubKey( pszKey, pszValue);
+ }
+
+Done:
+ FREEPSZPTR(pszSection);
+ FREEPSZPTR(pszKey);
+ FREEPSZPTR(pszValue);
+ FREEARGPTR(parg16);
+ return ul;
+}
+
+
+ULONG FASTCALL WK32GetProfileString(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ pszSection;
+ PSZ pszKey;
+ PSZ pszDefault;
+ PSZ pszReturnBuffer;
+ UINT cchMax;
+ register PGETPROFILESTRING16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETPROFILESTRING16), parg16);
+ GETPSZPTR(parg16->f1, pszSection);
+ GETPSZPTR(parg16->f2, pszKey);
+ GETPSZPTR(parg16->f3, pszDefault);
+ ALLOCVDMPTR(parg16->f4, parg16->f5, pszReturnBuffer);
+ cchMax = INT32(parg16->f5);
+
+ if (IS_EMBEDDING_SECTION( pszSection ) &&
+ !WasSectionRecentlyUpdated() ) {
+ if( pszKey == NULL ) {
+ UpdateEmbeddingAllKeys();
+ } else {
+ UpdateEmbeddingKey( pszKey );
+ }
+ SetLastTimeUpdated();
+
+ } else if (pszSection &&
+ pszKey &&
+ !_stricmp(pszSection, szDevices) &&
+ IsFaxPrinterSupportedDevice(pszKey)) {
+
+ ul = GETINT16(GetFaxPrinterProfileString(pszSection, pszKey, pszDefault, pszReturnBuffer, cchMax));
+ goto FlushAndReturn;
+ }
+
+ ul = GETINT16(GetProfileString(
+ pszSection,
+ pszKey,
+ pszDefault,
+ pszReturnBuffer,
+ cchMax));
+
+
+ //
+ // Win3.1/Win95 compatibility: Zap any trailing blanks in pszDefault
+ // with nulls, but only if the default string was returned. To detect
+ // the default string being returned we need to ignore trailing blanks.
+ //
+ // Because of the high usage of this API, we only zap trailing blanks
+ // if a compatibility bit is turned on.
+ //
+ // This code is duplicated in thunks for GetProfileString and
+ // GetPrivateProfileString, update both if you make changes.
+ //
+
+ if ((CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_ZAPGPPSDEFBLANKS) &&
+ pszDefault &&
+ pszKey
+ ) {
+
+ int n, nLenDef;
+
+ //
+ // If the returned string is a prefix of the default string...
+ // ul is strlen(pszReturnBuffer)
+ //
+
+ nLenDef = strlen(pszDefault);
+
+ if (nLenDef > (int)ul &&
+ RtlEqualMemory(pszDefault, pszReturnBuffer, ul)) {
+
+ //
+ // And the only difference is trailing blanks...
+ //
+
+ for (n = (int)ul; n < nLenDef; n++) {
+
+ if (' ' != pszDefault[n]) {
+ break;
+ }
+
+#ifdef DBCS
+ if (IsDBCSLeadByte(pszDefault[n]) {
+ n++;
+ }
+#endif
+ }
+
+ if (n >= nLenDef) {
+
+ char szBuf[512];
+
+ //
+ // The returned string is the same as the default string
+ // without trailing blanks, but this might be coincidence,
+ // so see if a call with empty pszDefault returns anything.
+ // If it does, we don't zap because the default isn't
+ // being used.
+ //
+
+ if (0 == GetProfileString(pszSection, pszKey, "", szBuf, sizeof szBuf)) {
+
+ //
+ // Zap first trailing blank in pszDefault with null.
+ //
+
+ pszDefault[ul] = 0;
+ FLUSHVDMPTR(parg16->f3 + ul, 1, pszDefault + ul);
+ }
+ }
+ }
+ }
+
+#ifdef DEBUG
+
+ //
+ // Make noise on the debugger if pszDefault has trailing blanks at
+ // this point indicating that WOWCFEX_ZAPGPPSDEFBLANKS might need
+ // to be turned on for this app.
+ //
+
+ if ( ! (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_ZAPGPPSDEFBLANKS) &&
+ pszKey &&
+ pszDefault &&
+ ' ' == pszDefault[strlen(pszDefault) - 1]) {
+
+ char szMsg[256];
+
+ sprintf(szMsg,
+ "\n"
+ "WOW32 COMPATIBILITY ALERT: Task %.8s has trailing blanks in pszDefault to\n"
+ "Get[Private]ProfileString but WOWCFEX_ZAPGPPSDEFBLANKS (0x00000000 0x%08x)\n"
+ "is not enabled. Try enabling this bit if you're having problems.\n"
+ "\n",
+ ((PTDB)SEGPTR(CURRENTPTD()->htask16,0))->TDB_ModName,
+ WOWCFEX_ZAPGPPSDEFBLANKS
+ );
+ OutputDebugString(szMsg);
+ }
+#endif
+
+
+FlushAndReturn:
+ FLUSHVDMPTR(parg16->f4, (ul + (pszSection && pszKey) ? 1 : 2), pszReturnBuffer);
+ FREEPSZPTR(pszSection);
+ FREEPSZPTR(pszKey);
+ FREEPSZPTR(pszDefault);
+ FREEVDMPTR(pszReturnBuffer);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GetPrivateProfileString(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ pszSection;
+ PSZ pszKey;
+ PSZ pszDefault;
+ PSZ pszReturnBuffer;
+ PSZ pszFilename;
+ DWORD cFlagsEx;
+ UINT cchMax;
+ register PGETPRIVATEPROFILESTRING16 parg16;
+ CHAR szLowercase[MAX_PATH];
+
+ GETARGPTR(pFrame, sizeof(GETPRIVATEPROFILESTRING16), parg16);
+ GETPSZPTR(parg16->f1, pszSection);
+ GETPSZPTR(parg16->f2, pszKey);
+ GETPSZPTR(parg16->f3, pszDefault);
+ ALLOCVDMPTR(parg16->f4, parg16->f5, pszReturnBuffer);
+ GETPSZPTR(parg16->f6, pszFilename);
+
+ // PC3270 (Personal communications): while installing this app it calls
+ // GetPrivateProfileString (sectionname, NULL, defaultbuffer, returnbuffer,
+ // cch = 0, filename). On win31 this call returns relevant data in return
+ // buffer and corresponding size as return value. On NT, since the
+ // buffersize(cch) is '0' no data is copied into the return buffer and
+ // return value is zero which makes this app abort installation.
+ //
+ // So restricted compatibility:
+ // if above is the case set
+ // cch = 64k - offset of returnbuffer;
+ //
+ // A safer 'cch' would be
+ // cch = GlobalSize(selector of returnbuffer) -
+ // (offset of returnbuffer);
+ // - nanduri
+
+ if (!(cchMax = INT32(parg16->f5))) {
+ if (pszKey == (PSZ)NULL) {
+ if (pszReturnBuffer != (PSZ)NULL) {
+ cchMax = 0xffff - (LOW16(parg16->f4));
+ }
+ }
+ }
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+ strcpy(szLowercase, pszFilename);
+ _strlwr(szLowercase);
+
+ if (IS_WIN_INI( szLowercase )) {
+
+ if (IS_EMBEDDING_SECTION( pszSection ) &&
+ !WasSectionRecentlyUpdated() ) {
+ if( pszKey == NULL ) {
+ UpdateEmbeddingAllKeys();
+ } else {
+ UpdateEmbeddingKey( pszKey );
+ }
+ SetLastTimeUpdated();
+
+ } else if (pszSection &&
+ pszKey &&
+ !_stricmp(pszSection, szDevices) &&
+ IsFaxPrinterSupportedDevice(pszKey)) {
+
+ ul = GETINT16(GetFaxPrinterProfileString(pszSection, pszKey, pszDefault, pszReturnBuffer, cchMax));
+ goto FlushAndReturn;
+ }
+ }
+
+ ul = GETUINT16(GetPrivateProfileString(
+ pszSection,
+ pszKey,
+ pszDefault,
+ pszReturnBuffer,
+ cchMax,
+ pszFilename));
+
+
+ // start comaptibility hacks
+ cFlagsEx = CURRENTPTD()->dwWOWCompatFlagsEx;
+ if(cFlagsEx & (WOWCFEX_ZAPGPPSDEFBLANKS | WOWCFEX_SAYITSNOTTHERE)) {
+
+ //
+ // Win3.1/Win95 compatibility: Zap any trailing blanks in pszDefault
+ // with nulls, but only if the default string was returned. To detect
+ // the default string being returned we need to ignore trailing blanks.
+ //
+ // Because of the high usage of this API, we only zap trailing blanks
+ // if a compatibility bit is turned on.
+ //
+ // This code is duplicated in thunks for GetProfileString and
+ // GetPrivateProfileString, update both if you make changes.
+ //
+
+ if ((cFlagsEx & WOWCFEX_ZAPGPPSDEFBLANKS) && pszDefault && pszKey) {
+
+ int n, nLenDef;
+
+ //
+ // If the returned string is a prefix of the default string...
+ // ul is strlen(pszReturnBuffer)
+ //
+
+ nLenDef = strlen(pszDefault);
+
+ if (nLenDef > (int)ul &&
+ RtlEqualMemory(pszDefault, pszReturnBuffer, ul)) {
+
+ //
+ // And the only difference is trailing blanks...
+ //
+
+ for (n = (int)ul; n < nLenDef; n++) {
+
+ if (' ' != pszDefault[n]) {
+ break;
+ }
+
+#ifdef DBCS
+ if (IsDBCSLeadByte(pszDefault[n]) {
+ n++;
+ }
+#endif
+ }
+
+ if (n >= nLenDef) {
+
+ char szBuf[512];
+
+ //
+ // The returned string is the same as the default string
+ // without trailing blanks, but this might be coincidence,
+ // so see if a call with empty pszDefault returns anything.
+ // If it does, we don't zap because the default isn't
+ // being used.
+ //
+
+ if (0 == GetPrivateProfileString(pszSection, pszKey, "", szBuf, sizeof szBuf, pszFilename)) {
+
+ //
+ // Zap first trailing blank in pszDefault with null.
+ //
+
+ pszDefault[ul] = 0;
+ FLUSHVDMPTR(parg16->f3 + ul, 1, pszDefault + ul);
+ }
+ }
+ }
+ }
+
+ // CrossTalk 2.2 gets hung in a loop while trying to match a printer in
+ // their xtalk.ini file with a printer name in the PrintDlg listbox.
+ // There is a bug in their code for handling this that gets exposed by
+ // the fact that NT PrintDlg listboxes do not include the port name as
+ // Win3.1 & Win'95 do. We avoid the buggy code altogether with this
+ // hack by telling them that the preferred printer isn't stored in
+ // xtalk.ini. See bug #43168 a-craigj
+
+ if(cFlagsEx & WOWCFEX_SAYITSNOTTHERE) {
+ if(strstr(szLowercase, "xtalk.ini")) {
+ if(!_stricmp(pszSection, "Printer")) {
+ if(!_stricmp(pszKey, "Device")) {
+ strcpy(pszReturnBuffer, pszDefault);
+ ul = strlen(pszReturnBuffer);
+ }
+ }
+ }
+ }
+ }
+
+#ifdef DEBUG
+
+ //
+ // Make noise on the debugger if pszDefault has trailing blanks at
+ // this point indicating that WOWCFEX_ZAPGPPSDEFBLANKS might need
+ // to be turned on for this app.
+ //
+
+ if ( ! (cFlagsEx & WOWCFEX_ZAPGPPSDEFBLANKS) &&
+ pszKey &&
+ pszDefault &&
+ ' ' == pszDefault[strlen(pszDefault) - 1]) {
+
+ char szMsg[256];
+
+ sprintf(szMsg,
+ "\n"
+ "WOW32 COMPATIBILITY ALERT: Task %.8s has trailing blanks in pszDefault to\n"
+ "Get[Private]ProfileString but WOWCFEX_ZAPGPPSDEFBLANKS (0x00000000 0x%08x)\n"
+ "is not enabled. Try enabling this bit if you're having problems.\n"
+ "\n",
+ ((PTDB)SEGPTR(CURRENTPTD()->htask16,0))->TDB_ModName,
+ WOWCFEX_ZAPGPPSDEFBLANKS
+ );
+ OutputDebugString(szMsg);
+ }
+#endif
+
+
+FlushAndReturn:
+ if (ul) {
+ FLUSHVDMPTR(parg16->f4, (ul + (pszSection && pszKey) ? 1 : 2), pszReturnBuffer);
+ LOGDEBUG(8,("GetPrivateProfileString returns '%s'\n", pszReturnBuffer));
+ }
+
+#ifdef DEBUG
+
+ //
+ // Check for bad return on retrieving entire section by walking
+ // the section making sure it's full of null-terminated strings
+ // with an extra null at the end. Also ensure that this all fits
+ // within the buffer.
+ //
+
+ if (!pszKey) {
+ PSZ psz;
+
+ //
+ // We don't want to complain if the poorly-formed buffer was the one
+ // passed in as pszDefault by the caller.
+ //
+
+ // Although the api docs clearly state that pszDefault should never
+ // be null but win3.1 is nice enough to still deal with this. Delphi is
+ // passing pszDefault as NULL and this following code causes an
+ // assertion in WOW. So added the pszDefault check first.
+ //
+ // sudeepb 11-Sep-1995
+
+
+ if (!pszDefault || strcmp(pszReturnBuffer, pszDefault)) {
+
+ psz = pszReturnBuffer;
+
+ while (psz < (pszReturnBuffer + ul + 2) && *psz) {
+ psz += strlen(psz) + 1;
+ }
+
+ WOW32ASSERTMSGF(
+ psz < (pszReturnBuffer + ul + 2),
+ ("GetPrivateProfileString of entire section returns poorly formed buffer.\n"
+ "pszReturnBuffer = %p, return value = %d\n",
+ pszReturnBuffer,
+ ul
+ ));
+ }
+ }
+
+#endif // DEBUG
+
+ FREEPSZPTR(pszSection);
+ FREEPSZPTR(pszKey);
+ FREEPSZPTR(pszDefault);
+ FREEVDMPTR(pszReturnBuffer);
+ FREEPSZPTR(pszFilename);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+ULONG FASTCALL WK32GetProfileInt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ PSZ psz2;
+ register PGETPROFILEINT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETPROFILEINT16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+ GETPSZPTR(parg16->f2, psz2);
+
+ ul = GETWORD16(GetProfileInt(
+ psz1,
+ psz2,
+ INT32(parg16->f3)
+ ));
+
+ //
+ // In HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics, there
+ // are a bunch of values that define the screen appearance. You can
+ // watch these values get updated when you go into the display control
+ // panel applet and change the "appearance scheme", or any of the
+ // individual elements. The win95 shell is different than win31 in that it
+ // sticks "twips" values in there instead of pixels. These are calculated
+ // with the following formula:
+ //
+ // twips = - pixels * 72 * 20 / cyPixelsPerInch
+ //
+ // pixels = -twips * cyPixelsPerInch / (72*20)
+ //
+ // So if the value is negative, it is in twips, otherwise it in pixels.
+ // The idea is that these values are device independent. NT is
+ // different than win95 in that we provide an Ini file mapping to this
+ // section of the registry where win95 does not. Now, when the Lotus
+ // Freelance Graphics 2.1 tutorial runs, it mucks around with the look
+ // of the screen, and it changes the border width of window frames by
+ // using SystemParametersInfo(). When it tries to restore it, it uses
+ // GetProfileInt("Windows", "BorderWidth", <default>), which on win31
+ // returns pixels, on win95 returns the default (no ini mapping), and
+ // on NT returns TWIPS. Since this negative number is interpreted as
+ // a huge UINT, then the window frames become huge. What this code
+ // below will do is translate the number back to pixels. [neilsa]
+ //
+
+ if ((CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_PIXELMETRICS) &&
+ !_stricmp(psz1, "Windows") &&
+ !_stricmp(psz2, "BorderWidth") &&
+ ((INT)ul < 0)) {
+
+ HDC hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
+ ul = (ULONG) (-(INT)ul * GetDeviceCaps(hDC, LOGPIXELSY)/(72*20));
+ DeleteDC(hDC);
+
+ }
+
+ FREEPSZPTR(psz1);
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WK32GetPrivateProfileInt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ PSZ psz2;
+ PSZ psz4;
+ register PGETPRIVATEPROFILEINT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETPRIVATEPROFILEINT16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+ GETPSZPTR(parg16->f2, psz2);
+ GETPSZPTR(parg16->f4, psz4);
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+ ul = GETWORD16(GetPrivateProfileInt(
+ psz1,
+ psz2,
+ INT32(parg16->f3),
+ psz4
+ ));
+
+ FREEPSZPTR(psz1);
+ FREEPSZPTR(psz2);
+ FREEPSZPTR(psz4);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WK32GetModuleFileName(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PGETMODULEFILENAME16 parg16;
+ HANDLE hT;
+
+ GETARGPTR(pFrame, sizeof(GETMODULEFILENAME16), parg16);
+ ALLOCVDMPTR(parg16->f2, parg16->f3, psz2);
+
+ if ( ISTASKALIAS(parg16->f1) ) {
+ ul = GetHtaskAliasProcessName(parg16->f1,psz2,INT32(parg16->f3));
+ } else {
+ hT = (parg16->f1) ? (HMODULE32(parg16->f1)) : GetModuleHandle(NULL) ;
+ ul = GETINT16(GetModuleFileName(hT, psz2, INT32(parg16->f3)));
+ }
+
+ FLUSHVDMPTR(parg16->f2, strlen(psz2)+1, psz2);
+ FREEVDMPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32FreeResource(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PFREERESOURCE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(FREERESOURCE16), parg16);
+
+ ul = GETBOOL16(FreeResource(
+ HCURSOR32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WK32GetDriveType(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ CHAR RootPathName[] = "?:\\";
+ register PGETDRIVETYPE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETDRIVETYPE16), parg16);
+
+ // Form Root path
+ RootPathName[0] = (CHAR)('A'+ parg16->f1);
+
+ ul = GetDriveType (RootPathName);
+ // bugbug - temporariy fixed, should be removed when base changes
+ // its return value for non-exist drives
+ // Windows 3.0 sdk manaul said this api should return 1
+ // if the drive doesn't exist. Windows 3.1 sdk manual said
+ // this api should return 0 if it failed. Windows 3.1 winfile.exe
+ // expects 0 for noexisting drives. The NT WIN32 API uses
+ // 3.0 convention. Therefore, we reset the value to zero
+ // if it is 1.
+ if (ul <= 1)
+ ul = 0;
+
+ // DRIVE_CDROM and DRIVE_RAMDISK are not supported under Win 3.1
+ if ( ul == DRIVE_CDROM ) {
+ ul = DRIVE_REMOTE;
+ }
+ if ( ul == DRIVE_RAMDISK ) {
+ ul = DRIVE_FIXED;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wkernel.h b/private/mvdm/wow32/wkernel.h
new file mode 100644
index 000000000..ead40321b
--- /dev/null
+++ b/private/mvdm/wow32/wkernel.h
@@ -0,0 +1,89 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKERNEL.H
+ * WOW32 16-bit Kernel API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WK32AccessResource(PVDMFRAME pFrame);
+ULONG FASTCALL WK32AddAtom(PVDMFRAME pFrame);
+ULONG FASTCALL WK32AllocDStoCSAlias(PVDMFRAME pFrame);
+ULONG FASTCALL WK32AllocResource(PVDMFRAME pFrame);
+ULONG FASTCALL WK32AllocSelector(PVDMFRAME pFrame);
+ULONG FASTCALL WK32Catch(PVDMFRAME pFrame);
+ULONG FASTCALL WK32DebugBreak(PVDMFRAME pFrame);
+ULONG FASTCALL WK32DeleteAtom(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FatalExit(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FindAtom(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FindResource(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FreeLibrary(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FreeModule(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FreeProcInstance(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FreeResource(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FreeSelector(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetAtomHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetAtomName(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetCodeHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetCodeInfo(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetCurrentPDB(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetCurrentTask(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetDOSEnvironment(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetDriveType(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetFreeSpace(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetInstanceData(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetModuleFileName(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetModuleHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetModuleUsage(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetNumTasks(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetPrivateProfileInt(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetPrivateProfileString(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetProcAddress(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetProfileInt(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetProfileString(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetSystemDirectory(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetTempDrive(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetTempFileName(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetVersion(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetWinFlags(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetWindowsDirectory(PVDMFRAME pFrame);
+ULONG FASTCALL WK32InitAtomTable(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LimitEmsPages(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LoadLibrary(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LoadModule(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LoadResource(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LockResource(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LockSegment(PVDMFRAME pFrame);
+ULONG FASTCALL WK32MakeProcInstance(PVDMFRAME pFrame);
+ULONG FASTCALL WK32OpenFile(PVDMFRAME pFrame);
+ULONG FASTCALL WK32OutputDebugString(PVDMFRAME pFrame);
+ULONG FASTCALL WK32SetErrorMode(PVDMFRAME pFrame);
+ULONG FASTCALL WK32SetHandleCount(PVDMFRAME pFrame);
+ULONG FASTCALL WK32SetResourceHandler(PVDMFRAME pFrame);
+ULONG FASTCALL WK32SetSwapAreaSize(PVDMFRAME pFrame);
+ULONG FASTCALL WK32SizeofResource(PVDMFRAME pFrame);
+ULONG FASTCALL WK32SwapRecording(PVDMFRAME pFrame);
+ULONG FASTCALL WK32SwitchStackBack(PVDMFRAME pFrame);
+ULONG FASTCALL WK32SwitchStackTo(PVDMFRAME pFrame);
+ULONG FASTCALL WK32Throw(PVDMFRAME pFrame);
+ULONG FASTCALL WK32UnlockSegment(PVDMFRAME pFrame);
+ULONG FASTCALL WK32ValidateCodeSegments(PVDMFRAME pFrame);
+ULONG FASTCALL WK32ValidateFreeSpaces(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WinExec(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WritePrivateProfileString(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WriteProfileString(PVDMFRAME pFrame);
+ULONG FASTCALL WK32lstrcat(PVDMFRAME pFrame);
+ULONG FASTCALL WK32lstrcpy(PVDMFRAME pFrame);
+ULONG FASTCALL WK32lstrlen(PVDMFRAME pFrame);
+ULONG FASTCALL WK32RegOpenKey32(PVDMFRAME pFrame);
+ULONG FASTCALL WK32RegEnumKey32(PVDMFRAME pFrame);
+ULONG FASTCALL WK32RegEnumValue32(PVDMFRAME pFrame);
+ULONG FASTCALL WK32RegCloseKey32(PVDMFRAME pFrame);
+
diff --git a/private/mvdm/wow32/wkfileio.c b/private/mvdm/wow32/wkfileio.c
new file mode 100644
index 000000000..6b24944e0
--- /dev/null
+++ b/private/mvdm/wow32/wkfileio.c
@@ -0,0 +1,2214 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1993 Microsoft Corporation
+ *
+ * WKFILEIO.C
+ * WOW32 KRNL FAST FILEIO ROUTINES
+ *
+ * History:
+ * Routines removed from wkman.c
+ * Created 1-Jan-1993 by Matt Felton (mattfe)
+ *
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+#include "dossvc.h"
+#include "demexp.h"
+#include "nt_vdd.h"
+
+
+MODNAME(wkfileio.c);
+
+extern DOSWOWDATA DosWowData;
+
+// Files which are mapped are kept in a single linked list
+// gpCacheHead -> the most recently accessed entry
+//
+
+BOOL fCacheInit = TRUE; // Set False When initialized
+PHMAPPEDFILEALIAS gpCacheHead = NULL;
+HMAPPEDFILEALIAS aMappedFileCache[MAX_MAPPED_FILES] = {0}; // File Handle To MappedFile Array
+
+DWORD dwTotalCacheBytes = 0;
+DWORD dwTotalCacheAccess = 0;
+
+#ifdef DEBUG
+INT fileiolevel = 12;
+INT fileoclevel = 8;
+#endif
+
+BOOL FASTCALL IsModuleSymantecInstall(HAND16 hMod16);
+
+
+//
+// named pipe stuff
+//
+
+BOOL
+LoadVdmRedir(
+ VOID
+ );
+
+BOOL
+IsVdmRedirLoaded(
+ VOID
+ );
+
+BOOL
+IsNamedPipeName(
+ IN LPSTR Name
+ );
+
+PSTR
+TruncatePath83(
+ IN OUT PSTR,
+ IN PSTR
+ );
+
+CRITICAL_SECTION VdmLoadCritSec;
+
+//
+// invent some typedefs to avoid compiler warnings from GetProcAddress
+//
+
+typedef
+BOOL
+(*VR_READ_NAMED_PIPE_FUNC)(
+ IN HANDLE Handle,
+ IN LPBYTE Buffer,
+ IN DWORD Buflen,
+ OUT LPDWORD BytesRead,
+ OUT LPDWORD Error
+ );
+
+typedef
+BOOL
+(*VR_WRITE_NAMED_PIPE_FUNC)(
+ IN HANDLE Handle,
+ IN LPBYTE Buffer,
+ IN DWORD Buflen,
+ OUT LPDWORD BytesRead
+ );
+
+typedef
+BOOL
+(*VR_IS_NAMED_PIPE_HANDLE_FUNC)(
+ IN HANDLE Handle
+ );
+
+typedef
+BOOL
+(*VR_ADD_OPEN_NAMED_PIPE_INFO_FUNC)(
+ IN HANDLE Handle,
+ IN LPSTR lpFileName
+ );
+
+typedef
+LPSTR
+(*VR_CONVERT_LOCAL_NT_PIPE_NAME_FUNC)(
+ OUT LPSTR Buffer OPTIONAL,
+ IN LPSTR Name
+ );
+
+typedef
+BOOL
+(*VR_REMOVE_OPEN_NAMED_PIPE_INFO_FUNC)(
+ IN HANDLE Handle
+ );
+
+typedef
+VOID
+(*VR_CANCEL_PIPE_IO_FUNC)(
+ IN DWORD Thread
+ );
+
+//
+// prototypes for functions dynamically loaded from VDMREDIR.DLL
+//
+
+BOOL
+(*VrReadNamedPipe)(
+ IN HANDLE Handle,
+ IN LPBYTE Buffer,
+ IN DWORD Buflen,
+ OUT LPDWORD BytesRead,
+ OUT LPDWORD Error
+ ) = NULL;
+
+BOOL
+(*VrWriteNamedPipe)(
+ IN HANDLE Handle,
+ IN LPBYTE Buffer,
+ IN DWORD Buflen,
+ OUT LPDWORD BytesWritten
+ ) = NULL;
+
+BOOL
+DefaultIsNamedPipeHandle(
+ IN HANDLE Handle
+ );
+
+BOOL
+DefaultIsNamedPipeHandle(
+ IN HANDLE Handle
+ )
+{
+ return FALSE;
+}
+
+BOOL
+(*VrIsNamedPipeHandle)(
+ IN HANDLE Handle
+ ) = DefaultIsNamedPipeHandle;
+
+BOOL
+(*VrAddOpenNamedPipeInfo)(
+ IN HANDLE Handle,
+ IN LPSTR lpFileName
+ ) = NULL;
+
+LPSTR
+(*VrConvertLocalNtPipeName)(
+ OUT LPSTR Buffer OPTIONAL,
+ IN LPSTR Name
+ ) = NULL;
+
+BOOL
+(*VrRemoveOpenNamedPipeInfo)(
+ IN HANDLE Handle
+ ) = NULL;
+
+VOID
+DefaultVrCancelPipeIo(
+ IN DWORD Thread
+ );
+
+VOID
+DefaultVrCancelPipeIo(
+ IN DWORD Thread
+ )
+{
+ (void)(Thread);
+}
+
+VOID
+(*VrCancelPipeIo)(
+ IN DWORD Thread
+ ) = DefaultVrCancelPipeIo;
+
+HANDLE hVdmRedir;
+BOOL VdmRedirLoaded = FALSE;
+
+BOOL
+LoadVdmRedir(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Load the VDMREDIR DLL if it is not already loaded. Called from OpenFile
+ only. Since file operations cannot be performed on a file that has not
+ been opened, it is safe to only call this function on open
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOL
+ TRUE VdmRedir.DLL is loaded
+ FALSE no it isn't
+
+--*/
+
+{
+ BOOL currentLoadState;
+
+ //
+ // need critical section - Windows apps end up being multi-threaded in
+ // 32-bit world - might have simultaneous opens
+ //
+
+ EnterCriticalSection(&VdmLoadCritSec);
+ if (!VdmRedirLoaded) {
+ if ((hVdmRedir = LoadLibrary("VDMREDIR")) != NULL) {
+ if ((VrReadNamedPipe = (VR_READ_NAMED_PIPE_FUNC)GetProcAddress(hVdmRedir, "VrReadNamedPipe")) == NULL) {
+ goto closeAndReturn;
+ }
+ if ((VrWriteNamedPipe = (VR_WRITE_NAMED_PIPE_FUNC)GetProcAddress(hVdmRedir, "VrWriteNamedPipe")) == NULL) {
+ goto closeAndReturn;
+ }
+ if ((VrIsNamedPipeHandle = (VR_IS_NAMED_PIPE_HANDLE_FUNC)GetProcAddress(hVdmRedir, "VrIsNamedPipeHandle")) == NULL) {
+ goto closeAndReturn;
+ }
+ if ((VrAddOpenNamedPipeInfo = (VR_ADD_OPEN_NAMED_PIPE_INFO_FUNC)GetProcAddress(hVdmRedir, "VrAddOpenNamedPipeInfo")) == NULL) {
+ goto closeAndReturn;
+ }
+ if ((VrConvertLocalNtPipeName = (VR_CONVERT_LOCAL_NT_PIPE_NAME_FUNC)GetProcAddress(hVdmRedir, "VrConvertLocalNtPipeName")) == NULL) {
+ goto closeAndReturn;
+ }
+ if ((VrRemoveOpenNamedPipeInfo = (VR_REMOVE_OPEN_NAMED_PIPE_INFO_FUNC)GetProcAddress(hVdmRedir, "VrRemoveOpenNamedPipeInfo")) == NULL) {
+ goto closeAndReturn;
+ }
+ if ((VrCancelPipeIo = (VR_CANCEL_PIPE_IO_FUNC)GetProcAddress(hVdmRedir, "VrCancelPipeIo")) == NULL) {
+ VrCancelPipeIo = DefaultVrCancelPipeIo;
+
+closeAndReturn:
+ CloseHandle(hVdmRedir);
+ } else {
+ VdmRedirLoaded = TRUE;
+ }
+ }
+ }
+ currentLoadState = VdmRedirLoaded;
+ LeaveCriticalSection(&VdmLoadCritSec);
+ return currentLoadState;
+}
+
+BOOL
+IsVdmRedirLoaded(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Checks current load state of VDMREDIR.DLL
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOL
+ TRUE VdmRedir.DLL is loaded
+ FALSE no it isn't
+
+--*/
+
+{
+ BOOL currentLoadState;
+
+ EnterCriticalSection(&VdmLoadCritSec);
+ currentLoadState = VdmRedirLoaded;
+ LeaveCriticalSection(&VdmLoadCritSec);
+ return currentLoadState;
+}
+
+BOOL
+IsNamedPipeName(
+ IN LPSTR Name
+ )
+
+/*++
+
+Routine Description:
+
+ Lifted from VDMREDIR.DLL - we don't want to load the entire DLL if we
+ need to check for a named pipe
+
+ Checks if a string designates a named pipe. As criteria for the decision
+ we use:
+
+ \\computername\PIPE\...
+
+ DOS (client-side) can only open a named pipe which is created at a server
+ and must therefore be prefixed by a computername
+
+Arguments:
+
+ Name - to check for (Dos) named pipe syntax
+
+Return Value:
+
+ BOOL
+ TRUE - Name refers to (local or remote) named pipe
+ FALSE - Name doesn't look like name of pipe
+
+--*/
+
+{
+ int CharCount;
+
+ if (IS_ASCII_PATH_SEPARATOR(*Name)) {
+ ++Name;
+ if (IS_ASCII_PATH_SEPARATOR(*Name)) {
+ ++Name;
+ CharCount = 0;
+ while (*Name && !IS_ASCII_PATH_SEPARATOR(*Name)) {
+ ++Name;
+ ++CharCount;
+ }
+ if (!CharCount || !*Name) {
+
+ //
+ // Name is \\ or \\\ or just \\name which I don't understand,
+ // so its not a named pipe - fail it
+ //
+
+ return FALSE;
+ }
+
+ //
+ // bump name past next path separator. Note that we don't have to
+ // check CharCount for max. length of a computername, because this
+ // function is called only after the (presumed) named pipe has been
+ // successfully opened, therefore we know that the name has been
+ // validated
+ //
+
+ ++Name;
+ } else {
+ return FALSE;
+ }
+
+ //
+ // We are at <something> (after \ or \\<name>\). Check if <something>
+ // is [Pp][Ii][Pp][Ee][\\/]
+ //
+
+ if (!_strnicmp(Name, "PIPE", 4)) {
+ Name += 4;
+ if (IS_ASCII_PATH_SEPARATOR(*Name)) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/* WK32FileRead - Read a file
+ *
+ *
+ * Entry - fh File Handle
+ * bufsize Count to read
+ * lpBuf Buffer Address
+ *
+ * Exit
+ * SUCCESS
+ * Count of bytes read
+ *
+ * FAILURE
+ * system status code
+ * Concept Borrowed from demFileRead
+ *
+ */
+
+ULONG FASTCALL WK32FileRead (PVDMFRAME pFrame)
+{
+ PFILEIOREAD16 parg16;
+ LPBYTE pSrc;
+ LPBYTE pDst;
+ INT dwBytesRead;
+ DWORD bufsize, dwError, dwBytesLeft, dwHighDWord;
+ HANDLE hFile;
+ PHMAPPEDFILEALIAS pCache = 0;
+
+ GETARGPTR(pFrame, sizeof(MAPPEDFILEIOREAD16), parg16);
+
+ bufsize = FETCHDWORD(parg16->bufsize);
+ dwBytesRead = bufsize;
+
+ hFile = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, NULL, NULL);
+
+ if (!hFile) {
+ dwBytesRead = 0xffff0006;
+ FREEARGPTR(parg16);
+ return(dwBytesRead);
+ }
+
+ //
+ // It is legitimate to ask to read more bytes than are left in the
+ // selector passed in, if the file is short enough to not actually
+ // overrun the selector. In this case we don't want limit checking,
+ // so zero is passed as the required size to GETVDMPTR().
+ //
+
+ GETVDMPTR(parg16->lpBuf, 0, pDst);
+
+ // If its the KRNL doing IO then find the File in the Cache
+
+ if ( vptopPDB == parg16->lpPDB ) {
+
+ if ( !(pCache = FINDMAPFILECACHE(hFile)) ){
+
+ // Cache Entry Not Found so Add it
+
+ pCache = ALLOCMAPFILECACHE();
+ pCache->fAccess = W32MapViewOfFile( pCache, hFile);
+ }
+ if (pCache->fAccess) {
+
+ // Calculate Starting Read Address in File
+
+ pSrc = pCache->lpStartingAddressOfView + pCache->lFilePointer;
+
+ dwBytesRead = bufsize;
+
+ // Adjust Size so as to not read off the End of File
+
+ if (pCache->lFilePointer > pCache->dwFileSize) {
+ dwBytesRead = 0;
+ } else {
+ if (pCache->lFilePointer + dwBytesRead > pCache->dwFileSize) {
+ dwBytesRead-=((pCache->lFilePointer+dwBytesRead)-pCache->dwFileSize);
+ }
+ }
+
+ LOGDEBUG(fileiolevel, ("MapFileRead fh:%04X fh32:%08X pSrc:%08X Bytes:%08X pDsc %08X\n"
+ ,FETCHWORD(parg16->fh),hFile, pSrc,dwBytesRead,FETCHDWORD(parg16->lpBuf)));
+
+ // Could get PageIO Errors, especially reading over the network
+ // So do try-except around the mapped read.
+
+ try {
+ RtlCopyMemory(pDst, pSrc, dwBytesRead);
+ pCache->lFilePointer += dwBytesRead;
+ dwTotalCacheBytes += dwBytesRead;
+ dwTotalCacheAccess++;
+ } except (TRUE) {
+ SetFilePointer( hFile, pCache->lFilePointer, NULL, FILE_BEGIN );
+ FREEMAPFILECACHE(pCache->hfile32);
+ pCache->hfile32 = hFile;
+ pCache->fAccess = FALSE;
+ pCache = 0;
+ }
+ }
+ }
+
+ if ((pCache == 0) || (pCache->fAccess == FALSE)) {
+
+ // Do The File Read via the File System
+
+ if (IsVdmRedirLoaded() && VrIsNamedPipeHandle(hFile)) {
+
+ DWORD error;
+
+ if (!VrReadNamedPipe(hFile, pDst, (DWORD)bufsize, &dwBytesRead, &error)) {
+ dwBytesRead = error | 0xffff0000;
+ }
+ } else if (ReadFile (hFile, pDst, (DWORD)bufsize, &dwBytesRead,
+ NULL) == FALSE){
+ // In Win3.1 it is not an error to hit EOF during a read
+ // AmiPro asks for more bytes than they allocated for the buffer
+ dwError = GetLastError();
+ if(dwError == ERROR_NOACCESS) {
+
+ // how far to end of file?
+ dwBytesLeft = GetFileSize(hFile, &dwHighDWord) -
+ SetFilePointer(hFile, 0L, NULL, FILE_CURRENT);
+
+ // if there's tons left OR what was already tried - forget it
+ if(dwHighDWord || (dwBytesLeft >= bufsize)) {
+ dwBytesRead = dwError | 0xffff0000;
+ }
+
+ // else try again with the smaller request
+ else if (ReadFile (hFile, pDst, dwBytesLeft, &dwBytesRead,
+ NULL) == FALSE){
+
+ dwBytesRead = GetLastError() | 0xffff0000;
+ }
+
+ }
+ else {
+ dwBytesRead = dwError | 0xffff0000;
+ }
+ }
+
+ LOGDEBUG(fileiolevel, ("IOFileRead fh:%X fh32:%X Bytes req:%X read:%X pDsc %08X\n"
+ ,FETCHWORD(parg16->fh),hFile,bufsize,dwBytesRead, FETCHDWORD(parg16->lpBuf)));
+
+ } else {
+
+ if ((dwTotalCacheBytes > CACHE_BYTE_THRESHOLD) ||
+ (dwTotalCacheAccess > CACHE_ACCESS_THRESHOLD) ||
+ (dwBytesRead > CACHE_READ_THRESHOLD)) {
+ FlushMapFileCaches();
+ }
+
+ }
+
+ //
+ // If the read was successful, let the emulator know that
+ // these bytes have changed.
+ //
+ // On checked builds perform limit check now that we know the
+ // actual number of bytes read. We wait until now to allow
+ // for a requested read size which would overrun the selector,
+ // but against a file which has few enough bytes remaining
+ // that the selector isn't actually overrun.
+ //
+
+ if ((dwBytesRead & 0xffff0000) != 0xffff0000) {
+
+ FLUSHVDMCODEPTR(parg16->lpBuf, (WORD)dwBytesRead, pDst);
+
+#ifdef DEBUG
+ FREEVDMPTR(pDst);
+ GETVDMPTR(parg16->lpBuf, dwBytesRead, pDst);
+#endif
+ }
+
+ FREEVDMPTR(pDst);
+
+ FREEARGPTR(parg16);
+ return (dwBytesRead);
+}
+
+
+PHMAPPEDFILEALIAS FindMapFileCache(HANDLE hFile)
+{
+ PHMAPPEDFILEALIAS pCache, prev;
+ if (fCacheInit) {
+ InitMapFileCache();
+ }
+
+ pCache = gpCacheHead;
+ prev = 0;
+
+ while ( (pCache->hfile32 != hFile) && (pCache->hpfNext !=0) ) {
+ prev = pCache;
+ pCache = pCache->hpfNext;
+ }
+
+ // If we found it, then make sure its at the front of the list
+
+ if (pCache->hfile32 == hFile) {
+ if (prev != 0) {
+ prev->hpfNext = pCache->hpfNext;
+ pCache->hpfNext = gpCacheHead;
+ gpCacheHead = pCache;
+ }
+ }else{
+
+ // If it was not found return error
+
+ pCache = 0;
+ }
+
+ return(pCache);
+}
+
+
+PHMAPPEDFILEALIAS AllocMapFileCache()
+{
+ PHMAPPEDFILEALIAS pCache, prev;
+
+ if (fCacheInit) {
+ InitMapFileCache();
+ }
+
+ pCache = gpCacheHead;
+ prev = 0;
+
+ while ( (pCache->hpfNext != 0) && (pCache->hfile32 != 0) ) {
+ prev = pCache;
+ pCache = pCache->hpfNext;
+ }
+
+ if (prev != 0) {
+ prev->hpfNext = pCache->hpfNext;
+ pCache->hpfNext = gpCacheHead;
+ gpCacheHead = pCache;
+ }
+
+ // If The found entry was in use, then Free
+
+ if (pCache->hfile32 != 0) {
+ FREEMAPFILECACHE(pCache->hfile32);
+ }
+
+ return(pCache);
+}
+
+VOID FreeMapFileCache(HANDLE hFile)
+{
+ PHMAPPEDFILEALIAS pCache;
+
+ if ( pCache = FINDMAPFILECACHE(hFile) ) {
+ LOGDEBUG(fileiolevel,("FreeMapFileCache: hFile:%08x hMappedFileObject:%08X\n",
+ hFile,pCache->hMappedFileObject));
+ if ( pCache->lpStartingAddressOfView != 0 ) {
+ UnmapViewOfFile( pCache->lpStartingAddressOfView );
+ }
+ if ( pCache->hMappedFileObject != 0) {
+ CloseHandle( pCache->hMappedFileObject );
+ }
+ if (pCache->fAccess) {
+ SetFilePointer( hFile, pCache->lFilePointer, NULL, FILE_BEGIN );
+ }
+ pCache->hfile32 = 0;
+ pCache->hMappedFileObject = 0;
+ pCache->lpStartingAddressOfView = 0;
+ pCache->lFilePointer = 0;
+ pCache->dwFileSize = 0;
+ pCache->fAccess = FALSE;
+ }
+}
+
+VOID InitMapFileCache()
+{
+ PHMAPPEDFILEALIAS pCache;
+ INT i;
+
+ pCache = &aMappedFileCache[0];
+ gpCacheHead = 0;
+
+ for ( i = 1; i <= MAX_MAPPED_FILES-1; i++ ) {
+ pCache->hfile32 = 0;
+ pCache->hMappedFileObject = 0;
+ pCache->lpStartingAddressOfView = 0;
+ pCache->lFilePointer = 0;
+ pCache->dwFileSize = 0;
+ pCache->fAccess = FALSE;
+ pCache->hpfNext = gpCacheHead;
+ gpCacheHead = pCache;
+ pCache = &aMappedFileCache[i];
+ }
+ fCacheInit = FALSE;
+}
+
+
+BOOL W32MapViewOfFile( PHMAPPEDFILEALIAS pCache, HANDLE hFile)
+{
+ pCache->fAccess = FALSE;
+ pCache->hfile32 = hFile;
+ pCache->lpStartingAddressOfView = 0;
+ pCache->hMappedFileObject = CreateFileMapping( hFile,
+ 0,
+ PAGE_READONLY, 0, 0, 0);
+ if (pCache->hMappedFileObject != 0) {
+ pCache->lpStartingAddressOfView = MapViewOfFile( pCache->hMappedFileObject,
+ FILE_MAP_READ, 0, 0, 0);
+
+ if (pCache->lpStartingAddressOfView != 0 ) {
+ pCache->lFilePointer = SetFilePointer( hFile, 0, 0, FILE_CURRENT );
+ pCache->dwFileSize = GetFileSize(hFile, 0);
+ pCache->fAccess = TRUE; // Assume Read Access
+ } else {
+ CloseHandle(pCache->hMappedFileObject);
+ }
+ }
+ return(pCache->fAccess);
+}
+
+/* FlushMapFileCaches
+ *
+ * Entry - None
+ *
+ * Exit - None
+ *
+ */
+
+VOID FlushMapFileCaches()
+{
+ PHMAPPEDFILEALIAS pCache;
+
+ if (fCacheInit) {
+ return;
+ }
+
+ WOW32ASSERT(gpCacheHead != NULL);
+ pCache = gpCacheHead;
+
+ dwTotalCacheBytes = dwTotalCacheAccess = 0;
+
+ while ( (pCache->hpfNext !=0) ) {
+ if (pCache->hfile32 != 0) {
+ FREEMAPFILECACHE(pCache->hfile32);
+ }
+ pCache = pCache->hpfNext;
+ }
+}
+
+
+/* WK32FileWrite - Write to a file
+ *
+ *
+ * Entry - fh File Handle
+ * bufsize Count to read
+ * lpBuf Buffer Address
+ *
+ * Exit
+ * SUCCESS
+ * Count of bytes read
+ *
+ * FAILURE
+ * system status code
+ * Concept Borrowed from demFileWrite
+ *
+ */
+
+ULONG FASTCALL WK32FileWrite (PVDMFRAME pFrame)
+{
+HANDLE hFile;
+DWORD dwBytesWritten;
+DWORD bufsize;
+PBYTE pb1;
+register PFILEIOWRITE16 parg16;
+PHMAPPEDFILEALIAS pCache;
+
+ GETARGPTR(pFrame, sizeof(FILEIOWRITE16), parg16);
+
+ bufsize = FETCHDWORD(parg16->bufsize);
+
+ if ( HIWORD(parg16->lpBuf) == 0 ) {
+ pb1 = (PVOID)GetRModeVDMPointer(FETCHDWORD(parg16->lpBuf));
+ } else {
+ GETVDMPTR(parg16->lpBuf, bufsize, pb1);
+ }
+
+ hFile = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, NULL, NULL);
+
+ if (!hFile) {
+ dwBytesWritten = 0xffff0006; // DOS Invalid Handle Error
+ goto Cleanup;
+ }
+
+ // We don't Support Writing to Mapped Files
+
+ if ( (pCache = FINDMAPFILECACHE(hFile)) && pCache->fAccess ) {
+ if (pCache->lpStartingAddressOfView) {
+ SetFilePointer( hFile, pCache->lFilePointer, NULL, FILE_BEGIN );
+ FREEMAPFILECACHE(hFile);
+ }
+ pCache->fAccess = FALSE;
+ pCache->hfile32 = hFile;
+ }
+
+ // In DOS CX=0 truncates or extends the file to current file pointer.
+ if (bufsize == 0){
+ if (SetEndOfFile(hFile) == FALSE) {
+ dwBytesWritten = GetLastError() | 0xffff0000;
+ LOGDEBUG(fileiolevel, ("IOFileWrite fh:%X fh32:%X SetEndOfFile failed pDsc %08X\n",
+ FETCHWORD(parg16->fh),hFile,FETCHDWORD(parg16->lpBuf)));
+ } else {
+ dwBytesWritten = 0;
+ LOGDEBUG(fileiolevel, ("IOFileWrite fh:%X fh32:%X truncated at current position pDsc %08X\n",
+ FETCHWORD(parg16->fh),hFile,FETCHDWORD(parg16->lpBuf)));
+ }
+ }
+ else {
+ if (IsVdmRedirLoaded() && VrIsNamedPipeHandle(hFile)) {
+ if (!VrWriteNamedPipe(hFile, pb1, (DWORD)bufsize, &dwBytesWritten)) {
+ dwBytesWritten = GetLastError() | 0xffff0000;
+ }
+ } else {
+ if (( WriteFile (hFile,
+ pb1,
+ (DWORD)bufsize,
+ &dwBytesWritten,
+ NULL)) == FALSE){
+ dwBytesWritten = GetLastError() | 0xffff0000;
+ }
+ }
+ LOGDEBUG(fileiolevel, ("IOFileWrite fh:%X fh32:%X Bytes req:%X written:%X pDsc %08X\n",
+ FETCHWORD(parg16->fh),hFile,bufsize,dwBytesWritten,FETCHDWORD(parg16->lpBuf)));
+ }
+
+Cleanup:
+ FREEVDMPTR(pb1);
+ FREEARGPTR(parg16);
+ return (dwBytesWritten);
+}
+
+
+/* WK32FileLSeek - Change File Pointer
+ *
+ *
+ * Entry - fh File Handle
+ * fileOffset New Location
+ * mode Positioning Method
+ * 0 - File Absolute
+ * 1 - Relative to Current Position
+ * 2 - Relative to end of file
+ *
+ * Exit
+ * SUCCESS
+ * New Location
+ *
+ * FAILURE
+ * system status code
+ *
+ */
+
+ULONG FASTCALL WK32FileLSeek (PVDMFRAME pFrame)
+{
+HANDLE hFile;
+ULONG dwLoc;
+PHMAPPEDFILEALIAS pCache;
+register PFILEIOLSEEK16 parg16;
+
+#if (FILE_BEGIN != 0 || FILE_CURRENT != 1 || FILE_END !=2)
+ #error "Win32 values not DOS compatible"
+#
+
+#endif
+
+ GETARGPTR(pFrame, sizeof(FILEIOLSEEK16), parg16);
+
+ hFile = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, NULL, NULL);
+
+ if (!hFile) {
+ FREEARGPTR(parg16);
+ return(0xffff0006);
+ }
+
+ if ( (vptopPDB == parg16->lpPDB) && (pCache = FINDMAPFILECACHE(hFile)) && pCache->fAccess ) {
+
+ // File Is in the Cache
+ // Update our Seek Pointer
+
+ LOGDEBUG(fileiolevel, ("CachedSeek fh:%04X Mode %04X pointer %08X\n",FETCHWORD(parg16->fh),FETCHWORD(parg16->mode),FETCHDWORD(parg16->fileOffset)));
+
+ switch(FETCHWORD(parg16->mode)) {
+ case FILE_BEGIN:
+ pCache->lFilePointer = FETCHDWORD(parg16->fileOffset);
+ break;
+ case FILE_CURRENT:
+ pCache->lFilePointer += (LONG)FETCHDWORD(parg16->fileOffset);
+ break;
+ case FILE_END:
+ pCache->lFilePointer = pCache->dwFileSize +
+ (LONG)FETCHDWORD(parg16->fileOffset);
+ break;
+ }
+ dwLoc = pCache->lFilePointer;
+
+ } else {
+
+ DWORD dwLocHi = 0;
+ // File is NOT in Cache so Just do normal Seek.
+
+ if (((dwLoc = SetFilePointer (hFile,
+ FETCHDWORD(parg16->fileOffset),
+ &dwLocHi,
+ (DWORD)FETCHWORD(parg16->mode))) == -1L) &&
+ (GetLastError() != NO_ERROR)) {
+
+ dwLoc = GetLastError() | 0xffff0000;
+ return(dwLoc);
+ }
+
+ if (dwLocHi) {
+ // file pointer has been moved > FFFFFFFF. Truncate it
+ dwLocHi = 0;
+ if (((dwLoc = SetFilePointer (hFile,
+ dwLoc,
+ &dwLocHi,
+ FILE_BEGIN)) == -1L) &&
+ (GetLastError() != NO_ERROR)) {
+
+ dwLoc = GetLastError() | 0xffff0000;
+ return(dwLoc);
+ }
+ }
+
+ }
+
+
+ FREEARGPTR(parg16);
+ return (dwLoc);
+}
+
+
+BOOL IsDevice(PSTR pszFilePath)
+{
+ PSTR pfile, pend;
+ int length;
+ UCHAR device_part[9];
+ PSYSDEV pSys;
+ PUCHAR p;
+
+
+ // Determine the start of the file part of the path.
+
+ if (pfile = strrchr(pszFilePath, '\\')) {
+ pfile++;
+ } else if (pszFilePath[0] && pszFilePath[1] == ':') {
+ pfile = pszFilePath + 2;
+ } else {
+ pfile = pszFilePath;
+ }
+
+
+ // Compute length of pre-dot file name part.
+
+ for (pend = pfile; *pend; pend++) {
+ if (*pend == '.') {
+ break;
+ }
+ }
+ if (pend > pfile && *(pend - 1) == ':') {
+ pend--;
+ }
+ length = (pend - pfile);
+
+ if (length > 8) {
+ return FALSE;
+ }
+
+ RtlFillMemory(device_part + length, 8 - length, ' ');
+ RtlCopyMemory(device_part, pfile, length);
+ device_part[8] = 0;
+ _strupr(device_part);
+
+
+ // Now go through the device chain comparing each entry with
+ // the device part extracted from the file path.
+
+ pSys = pDeviceChain;
+ for (;;) {
+
+ p = pSys->sdevDevName;
+ if (device_part[0] == p[0] &&
+ device_part[1] == p[1] &&
+ device_part[2] == p[2] &&
+ device_part[3] == p[3] &&
+ device_part[4] == p[4] &&
+ device_part[5] == p[5] &&
+ device_part[6] == p[6] &&
+ device_part[7] == p[7]) {
+
+ return TRUE;
+ }
+
+ if (pSys->sdevNext & 0xFFFF == 0xFFFF) {
+ break;
+ }
+
+ pSys = (PSYSDEV) GetRModeVDMPointer(pSys->sdevNext);
+
+ }
+
+
+ // If it wasn't in the chain then it's not a device.
+
+ return FALSE;
+}
+
+
+
+PSTR NormalizeDosPath(PSTR pszPath, WORD wCurrentDriveNumber, PBOOL ItsANamedPipe)
+{
+ static CHAR NewPath[MAX_PATH];
+
+ PSTR p;
+ DWORD cbFilename;
+
+ *ItsANamedPipe = FALSE;
+
+ // Special case the NULL path.
+
+ if (pszPath[0] == 0) {
+ return pszPath;
+ }
+
+ // Apps can pass D:\\computer\share to int 21 open
+ // Win 32 createfile can't cope with the leading drive letter
+ // so remove it as necessary.
+
+ if (strncmp(pszPath+1,":\\\\",3) == 0) {
+ pszPath++;
+ pszPath++;
+ }
+
+ //
+ // if the name specifies a named pipe, load VDMREDIR. If this fails return
+ // an error
+ //
+
+ if (IsNamedPipeName(pszPath)) {
+ if (!LoadVdmRedir()) {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+ *ItsANamedPipe = TRUE;
+
+ //
+ // convert \\<this_computer>\PIPE\foo\bar\etc to \\.\PIPE\...
+ // if we already allocated a buffer for the slash conversion use
+ // that else this call will allocate another buffer (we don't
+ // want to write over DOS memory)
+ //
+
+ p = VrConvertLocalNtPipeName(NULL, pszPath);
+ if (!p) {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ return p;
+ }
+
+ // if there is no drive letter at the beginning of the path
+ // then prepend a drive letter and ':' to the beginning
+ // of the path.
+
+ if (pszPath[1] != ':' &&
+ !(IS_ASCII_PATH_SEPARATOR(pszPath[0]) &&
+ IS_ASCII_PATH_SEPARATOR(pszPath[1]))) {
+
+ cbFilename = strlen( pszPath ) + 1;
+ if( cbFilename > MAX_PATH - 2) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return NULL;
+ }
+
+ NewPath[0] = wCurrentDriveNumber + 'A';
+ NewPath[1] = ':';
+ RtlCopyMemory(NewPath + 2, pszPath, cbFilename);
+ pszPath = NewPath; //return this value
+ }
+
+ return TruncatePath83(NewPath, pszPath);
+}
+
+
+/* TruncatePath83 - Takes as input a path and make sure it has an 8.3 file name
+ *
+ * Entry - pstr-> target buffer[MAX_PATH]
+ * pstr-> string to convert
+ * It is assumed that the string has at the very least a '?:' as
+ * its first two characters, where ? is any drive letter.
+ *
+ * Exit
+ * SUCCESS
+ * return value-> converted string
+ *
+ * FAILURE
+ * return value==NULL
+ *
+ */
+
+PSTR TruncatePath83(PSTR NewPath, PSTR pszPath)
+{
+ PSTR pPathName, pPathNameSlash, pPathExt;
+
+ //
+ // If the string is not already in the buffer, copy it in
+ //
+
+ if (NewPath != pszPath) {
+ strcpy (NewPath, pszPath);
+ }
+
+ //
+ // make sure file name and extension are 8.3
+ //
+
+ pPathName = strrchr(NewPath, '\\');
+ pPathNameSlash = strrchr(NewPath, '/');
+
+ if ((NULL == pPathName) && (NULL == pPathNameSlash)) {
+ pPathName = &NewPath[2]; // 1st char after '?:'
+ } else {
+ if (pPathNameSlash > pPathName) {
+ pPathName = pPathNameSlash;
+ }
+ pPathName++; // 1st char in name
+ }
+
+ if (NULL != (pPathExt = strchr(pPathName, '.'))) { // is there a period?
+
+ pPathExt++; // 1st char in ext
+
+ if (strlen(pPathExt) > 3) { // extension too big?
+ pPathExt[3] = 0; // truncate extension
+ }
+
+ pPathExt--; // back to period
+ if (pPathExt - pPathName > 8) { // is name too big?
+ strcpy (&pPathName[8], pPathExt); // truncate file name
+ }
+ } else {
+ if (strlen(pPathName) > 8) { // is name too big?
+ pPathName[8] = 0; // truncate file name
+ }
+ }
+
+ return(NewPath);
+}
+
+
+/* ExpandDosPath - Expands paths of the form "*.*" to "????????.???"
+ * and merges in currentdirectory info
+ *
+ * N.B. This routine does not handle long file names
+ *
+ * Entry - pstr-> string to convert
+ *
+ * Exit
+ * SUCCESS
+ * return value-> converted string
+ *
+ * FAILURE
+ * return value==NULL
+ *
+ */
+
+PSTR ExpandDosPath(PSTR pszPathGiven)
+
+{
+ static CHAR NewPath[MAX_PATH],TempPath[MAX_PATH]; // this is not reentrant
+ USHORT usNewPathIndex = 0;
+ USHORT usFillCount = 8;
+ UCHAR ucCurrentChar, ucDrive;
+ PSTR pszPath = TempPath;
+ char *pFilePart;
+
+
+ // There is a bug in this routine where it is ignoring /. DOS treats them
+ // same as \. As matches for \ are spread all over this routine, its
+ // much safer to take an entry pass over the string and covert / to \.
+ // sudeepb 29-Jun-1995
+
+ while (pszPathGiven[usNewPathIndex]) {
+ if (pszPathGiven[usNewPathIndex] == '/')
+ pszPath [usNewPathIndex] = '\\';
+ else
+ pszPath [usNewPathIndex] = pszPathGiven[usNewPathIndex];
+ usNewPathIndex++;
+ }
+
+ pszPath [usNewPathIndex] = '\0';
+
+ //
+ // copy filepath into NewPath, add in current drive, directory
+ // if relative path name.
+ //
+ // Note: should be changed later to use GetFullPathName, since
+ // it is equivalent, and should have the correct curr dir,
+ // cur drive. be wary of trailing dots in GetFullPathName
+ // ie. "*." is not the same as "*"
+ //
+
+ if (strncmp(pszPath, "\\\\", 2)) { // should be drive letter
+ ucDrive = *pszPath++;
+ if ((*pszPath++ != ':') || (!isalpha(ucDrive))) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return NULL;
+ }
+
+ NewPath[0] = ucDrive;
+ NewPath[1] = ':';
+ usNewPathIndex = 2;
+
+ if (*pszPath != '\\') {
+ NewPath[usNewPathIndex++] = '\\';
+
+ if (DosWowGetCurrentDirectory ((UCHAR) (toupper(ucDrive)-'A'+1),
+ &NewPath[usNewPathIndex]))
+ {
+ return NULL;
+ }
+
+ usNewPathIndex = strlen(NewPath);
+ if (usNewPathIndex > 3) {
+ NewPath[usNewPathIndex++] = '\\';
+ }
+ }
+
+ pFilePart = strrchr(pszPath, '\\');
+ if (pFilePart) {
+ pFilePart++;
+ } else {
+ pFilePart = pszPath;
+ }
+
+ } else { // check for UNC name, if not UNC, path not found
+ usNewPathIndex = 2;
+ NewPath[0] = NewPath[1] = '\\';
+ pszPath += 2;
+
+ pFilePart = strrchr(pszPath, '\\');
+ if (!pFilePart) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return NULL;
+ }
+ pFilePart++;
+
+ }
+
+ while (pszPath < pFilePart && usNewPathIndex < MAX_PATH) {
+ NewPath[usNewPathIndex++] = *pszPath++;
+ }
+
+
+ ucCurrentChar = *pszPath++;
+ while ((usNewPathIndex < MAX_PATH) && (ucCurrentChar)) {
+
+ if (ucCurrentChar == '*') {
+
+ //
+ // expand "*"s to "?"
+ //
+ while ((usFillCount > 0) && (usNewPathIndex < MAX_PATH)) {
+ NewPath[usNewPathIndex++] = '?';
+ usFillCount--;
+ }
+
+ //
+ // skip to next valid character after expansion
+ //
+ while ((ucCurrentChar != 0) &&
+ (ucCurrentChar != '.') &&
+ (ucCurrentChar != '\\')) {
+ ucCurrentChar = *pszPath++;
+ }
+
+ } else {
+
+ if (ucCurrentChar == '.') {
+ usFillCount = 3; // fill count for .ext
+ } else if (ucCurrentChar == '\\') {
+ usFillCount = 8; // fill count for fn.
+ } else {
+ usFillCount--;
+ }
+
+ NewPath[usNewPathIndex++] = ucCurrentChar;
+
+ //
+ // get next character (except if no more are left)
+ //
+ if (ucCurrentChar) {
+ ucCurrentChar = *pszPath++;
+ }
+ }
+
+ }
+
+ if (usNewPathIndex >= MAX_PATH) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return NULL;
+ }
+
+
+ NewPath[usNewPathIndex] = 0; // trailing zero
+
+ return NewPath;
+}
+
+
+
+BOOL IsCdRomFile(PSTR pszPath)
+{
+ UCHAR pszRootDir[MAX_PATH];
+ UCHAR file_system[MAX_PATH];
+ int i, j;
+
+ // The given path is either a network path or has D: at the start.
+
+ if (!pszPath[0]) {
+ return FALSE;
+ }
+
+ if (pszPath[1] == ':') {
+ pszRootDir[0] = pszPath[0];
+ pszRootDir[1] = ':';
+ pszRootDir[2] = '\\';
+ pszRootDir[3] = 0;
+ } else if (IS_ASCII_PATH_SEPARATOR(pszPath[0]) &&
+ IS_ASCII_PATH_SEPARATOR(pszPath[1])) {
+ j = 0;
+ for (i = 2; pszPath[i]; i++) {
+ if (IS_ASCII_PATH_SEPARATOR(pszPath[i])) {
+ if (++j == 2) {
+ break;
+ }
+ }
+ }
+ memcpy(pszRootDir, pszPath, i);
+ pszRootDir[i] = '\\';
+ pszRootDir[i+1] = 0;
+ } else {
+ return FALSE;
+ }
+
+ if (GetVolumeInformationOem(pszRootDir, NULL, 0, NULL, NULL, NULL,
+ file_system, MAX_PATH) &&
+ !_stricmp(file_system, "CDFS")) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* WK32FileOpen - Open a file
+ *
+ *
+ * Entry - pszPath Path of file to open
+ * wAccess Desired access
+ *
+ * Exit
+ * SUCCESS
+ * handle number
+ *
+ * FAILURE
+ * system status code
+ * -1 to indicate the the requested open was for device and
+ * hence not attempted
+ *
+ */
+
+ULONG FASTCALL WK32FileOpen(PVDMFRAME pFrame)
+{
+ PFILEIOOPEN16 parg16;
+ HANDLE hFile;
+ ULONG ul;
+ SHORT iDosHandle;
+ PSTR pszPath;
+ WORD wAccess;
+ DWORD dwWinAccess;
+ DWORD dwWinShareMode;
+ WORD tmp;
+ PBYTE pJFT;
+ PDOSSFT pSft;
+ PSTR lpFileName;
+ BOOL ItsANamedPipe = FALSE;
+ PHMAPPEDFILEALIAS pCache;
+ PHMAPPEDFILEALIAS pTempCache;
+ PTD ptd;
+
+ //
+ // Get arguments.
+ //
+
+ GETARGPTR(pFrame, sizeof(FILEIOOPEN16), parg16);
+ pszPath = SEGPTR(FETCHWORD(parg16->pszPathSegment),
+ FETCHWORD(parg16->pszPathOffset));
+ wAccess = FETCHWORD(parg16->wAccess);
+
+ //
+ // If the path requested is a device then just pass it
+ // through to DOS.
+ //
+
+ if (IsDevice(pszPath)) {
+ FREEARGPTR(parg16);
+ ul = 0xFFFFFFFF; // magic value to indicate that the open
+ goto Done; // was not attempted.
+ }
+
+ if ((iDosHandle = VDDAllocateDosHandle(0, (PVOID *)&pSft, &pJFT)) < 0) {
+ FREEARGPTR(parg16);
+ ul = ERROR_TOO_MANY_OPEN_FILES | 0xFFFF0000;
+ goto Done;
+ }
+
+ pCache = ALLOCMAPFILECACHE();
+ pCache->hfile32 = 0;
+ pCache->fAccess = FALSE;
+
+ //
+ // Compute dwWinAccess and dwWinShareMode from wAccess.
+ //
+
+ tmp = wAccess&0x7;
+ if (tmp == 0) {
+ pCache->fAccess = TRUE;
+ dwWinAccess = GENERIC_READ;
+ } else if (tmp == 1) {
+ dwWinAccess = GENERIC_WRITE;
+ } else if (tmp == 2) {
+ dwWinAccess = GENERIC_READ | GENERIC_WRITE;
+ } else {
+ FREEARGPTR(parg16);
+ ul = ERROR_INVALID_ACCESS | 0xFFFF0000;
+ goto Done;
+ }
+
+ tmp = wAccess&0x70;
+ dwWinShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ if (tmp == 0) {
+ dwWinShareMode |= FILE_SHARE_DELETE;
+ } else if (tmp == 0x10) {
+ dwWinShareMode = 0;
+ } else if (tmp == 0x20) {
+ dwWinShareMode = FILE_SHARE_READ;
+ } else if (tmp == 0x30) {
+ dwWinShareMode = FILE_SHARE_WRITE;
+ }
+
+
+
+ //
+ // open the file. If we think its a named pipe then use FILE_FLAG_OVERLAPPED
+ // because the client might use DosReadAsyncNmPipe or DosWriteAsyncNmPipe
+ // and the only way to accomplish that is to open the named pipe handle in
+ // overlapped I/O mode now
+ //
+
+ WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
+
+ lpFileName = NormalizeDosPath(pszPath,
+ (WORD) (*(PUCHAR)DosWowData.lpCurDrv),
+ &ItsANamedPipe);
+
+ if (lpFileName) {
+
+ //
+ // This hack fixes the "Living Books" install program, which opens
+ // a file DENY ALL, and then tries to reopen the same file. On DOS,
+ // this succeeds if it is done from the same task, but it doesn't work
+ // on NT. So here we open it without the sharing restrictions, since it
+ // is anyway just a type of .INF file on the CD-ROM.
+ // Currently, the test is very specific, but I can't think of a good
+ // way to do this generically.
+ //
+ if ((dwWinShareMode == 0) &&
+ ((ptd = CURRENTPTD())->dwWOWCompatFlagsEx & WOWCFEX_SAMETASKFILESHARE) &&
+ (IsCdRomFile(lpFileName)) &&
+ (!_stricmp(pszPath, "install.txt"))) {
+ dwWinShareMode = FILE_SHARE_READ;
+ }
+
+ hFile = CreateFileOem(lpFileName,
+ dwWinAccess,
+ dwWinShareMode,
+ NULL,
+ OPEN_EXISTING,
+ ItsANamedPipe ? FILE_FLAG_OVERLAPPED : 0,
+ INVALID_HANDLE_VALUE
+ );
+
+ // If the open failed, includes a request for WRITE, and was to
+ // a CD-ROM then try again without the write request. Since
+ // this is how DOS does it.
+
+ if (hFile == INVALID_HANDLE_VALUE &&
+ dwWinAccess&GENERIC_WRITE &&
+ !ItsANamedPipe &&
+ IsCdRomFile(lpFileName)) {
+
+ dwWinAccess &= ~GENERIC_WRITE;
+
+ hFile = CreateFileOem(lpFileName,
+ dwWinAccess,
+ dwWinShareMode,
+ NULL,
+ OPEN_EXISTING,
+ ItsANamedPipe ? FILE_FLAG_OVERLAPPED : 0,
+ INVALID_HANDLE_VALUE
+ );
+ }
+ } else {
+ hFile = INVALID_HANDLE_VALUE;
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ ul = GetLastError() | 0xFFFF0000;
+ LOGDEBUG(fileoclevel,("WK32FileOpen: %s mode:%02X failed error %d\n",pszPath, wAccess, GetLastError()));
+ FREEARGPTR(parg16);
+ if (ItsANamedPipe) {
+ LocalFree(lpFileName);
+ }
+ pJFT[iDosHandle] = 0xFF; // undo VDDAllocateDosHandle
+ pSft->SFT_Ref_Count--;
+ goto Done;
+ } else if (ItsANamedPipe) {
+
+ //
+ // we have to keep some info around when we open a named pipe
+ //
+
+ VrAddOpenNamedPipeInfo(hFile, lpFileName);
+ }
+
+ LOGDEBUG(fileoclevel,("WK32FileOpen: %s hFile:%08X fh:%04X mode:%02X\n",pszPath, hFile,(WORD)iDosHandle,wAccess));
+
+ // Be defensive. If the app has managed to close the file via DOSEmulation
+ // then we need to make sure we don't have the old file handle in our cache.
+
+ if ( pTempCache = FINDMAPFILECACHE(hFile) ) {
+ pTempCache->fAccess = FALSE;
+ FREEMAPFILECACHE(hFile);
+ }
+
+ pCache->hfile32 = hFile;
+
+ if ((vptopPDB == parg16->lpPDB) && (pCache->fAccess)) {
+ W32MapViewOfFile( pCache, hFile);
+ } else {
+ FREEMAPFILECACHE(hFile);
+ }
+
+ //
+ // Fill in the SFT.
+ //
+
+ VDDAssociateNtHandle(pSft, hFile, wAccess);
+
+
+ FREEARGPTR(parg16);
+
+ if (ItsANamedPipe) {
+ LocalFree(lpFileName);
+ pSft->SFT_Flags |= SFT_NAMED_PIPE;
+ }
+
+ ul = iDosHandle;
+
+Done:
+ return ul;
+}
+
+
+/* WK32FileCreate - Create a file
+ *
+ *
+ * Entry - pszPath Path of file to create
+ *
+ * Exit
+ * SUCCESS
+ * handle number
+ *
+ * FAILURE
+ * system status code
+ * -1 to indicate the the requested open was for device and
+ * hence not attempted
+ *
+ */
+
+ULONG FASTCALL WK32FileCreate(PVDMFRAME pFrame)
+{
+ PWOWFILECREATE16 parg16;
+ HANDLE hFile;
+ ULONG ul;
+ SHORT iDosHandle;
+ PSTR pszPath;
+ PBYTE pJFT;
+ PDOSSFT pSft;
+ PSTR lpFileName;
+ ULONG attributes;
+ BOOL ItsANamedPipe = FALSE;
+ PTD ptd;
+
+ //
+ // Get arguments.
+ //
+
+ GETARGPTR(pFrame, sizeof(WOWFILECREATE16), parg16);
+ pszPath = SEGPTR(FETCHWORD(parg16->pszPathSegment),
+ FETCHWORD(parg16->pszPathOffset));
+
+ if (!(attributes = (DWORD) FETCHWORD(parg16->wAttributes) & 0x27)) {
+ attributes = FILE_ATTRIBUTE_NORMAL;
+ }
+
+ //
+ // If the path requested is a device then just pass it
+ // through to DOS.
+ //
+
+ if (IsDevice(pszPath)) {
+ FREEARGPTR(parg16);
+ ul = 0xFFFFFFFF; // magic value to indicate that the open
+ goto Done; // was not attempted.
+ }
+
+
+ if ((iDosHandle = VDDAllocateDosHandle(0, (PVOID *)&pSft, &pJFT)) < 0) {
+ ul = ERROR_TOO_MANY_OPEN_FILES | 0xFFFF0000;
+ goto Done;
+ }
+
+
+ //
+ // open the file. If we think its a named pipe then use FILE_FLAG_OVERLAPPED
+ // because the client might use DosReadAsyncNmPipe or DosWriteAsyncNmPipe
+ // and the only way to accomplish that is to open the named pipe handle in
+ // overlapped I/O mode now
+ //
+
+ WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
+
+ lpFileName = NormalizeDosPath(pszPath,
+ (WORD) (*(PUCHAR)DosWowData.lpCurDrv),
+ &ItsANamedPipe);
+
+ if (lpFileName) {
+ hFile = CreateFileOem(lpFileName,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ CREATE_ALWAYS,
+ ItsANamedPipe ? attributes | FILE_FLAG_OVERLAPPED : attributes,
+ INVALID_HANDLE_VALUE
+ );
+
+ } else {
+ hFile = INVALID_HANDLE_VALUE;
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ LOGDEBUG(fileoclevel,("WK32FileCreate: %s failed error %d\n",pszPath, GetLastError()));
+ if (ItsANamedPipe) {
+ LocalFree(lpFileName);
+ }
+ pJFT[iDosHandle] = 0xFF; // undo VDDAllocateDosHandle
+ pSft->SFT_Ref_Count--;
+ ul = GetLastError() | 0xFFFF0000;
+ goto Done;
+ } else {
+ if (ItsANamedPipe) {
+
+ //
+ // we have to keep some info around when we open a named pipe
+ //
+
+ VrAddOpenNamedPipeInfo(hFile, lpFileName);
+ }
+
+ //
+ // Symantec Install 3.1 shipped with Q&A 4.0 wants to be sure it's the
+ // only program running, so instead of nicely asking the user to close
+ // other programs, it changes the shell= line in system.ini to its
+ // install.exe, then restarts Windows and continues its installation.
+ // To reverse this change, they sloppily restore a saved copy of
+ // system.ini rather than use the API. Since the shell= line is
+ // mapped to the registry, this sloppy method doesn't work. Later
+ // when they want to create program groups, they try to start DDE
+ // with the shell, and when that fails they read the shell= line
+ // and start the specified program. On NT 4.0, that would be the
+ // install program and things go poorly. On 3.51 they would eventually
+ // give up and launch progman.exe, but since the shell has changed
+ // this no longer works.
+ //
+ // We fix this by detecting their creation (overwriting) of system.ini
+ // and at that point repairing the shell= value to Explorer.exe. This
+ // operation is done by INSTBIN.EXE, module name INSTBIN, which is a
+ // relief because I thought I would have to set WOWCFEX_RESTOREEXPLORER
+ // for module name INSTALL (the primary Symantec Install EXE).
+ //
+ // Thanks to Bob Day for figuring out what the app was doing, I simply
+ // came up with a workaround and implemented it.
+ //
+ // DaveHart 28-Jan-96
+ //
+
+ WOW32ASSERTMSG(vptopPDB != parg16->lpPDB,
+ "KRNL386 does create files, disable this assertion and add test below.\n");
+
+ if ((ptd = CURRENTPTD())->dwWOWCompatFlagsEx & WOWCFEX_RESTOREEXPLORER) {
+
+ char szLowerPath[MAX_PATH];
+ strcpy(szLowerPath, pszPath);
+ _strlwr(szLowerPath);
+
+ if (strstr(szLowerPath, szSystemDotIni)) {
+ if (IsModuleSymantecInstall(ptd->hMod16)) {
+ WritePrivateProfileString(szBoot, szShell, szExplorerDotExe, szSystemDotIni);
+ LOGDEBUG(LOG_ALWAYS, ("Restored shell=Explorer.exe for Symantec Install hack.\n"));
+ }
+ }
+ }
+ }
+
+ FREEARGPTR(parg16);
+
+ LOGDEBUG(fileoclevel,("WK32FileCreate: %s hFile:%08X fh:%04X\n",pszPath, hFile,(WORD)iDosHandle));
+
+ //
+ // Fill in the SFT.
+ //
+
+ VDDAssociateNtHandle(pSft, hFile, 2);
+
+ if (ItsANamedPipe) {
+ LocalFree(lpFileName);
+ pSft->SFT_Flags |= SFT_NAMED_PIPE;
+ }
+
+ ul = iDosHandle;
+
+Done:
+ return ul;
+}
+
+
+/* WK32FileClose - Close a file
+ *
+ *
+ * Entry - hFile Handle of file to close
+ *
+ * Exit
+ * SUCCESS
+ * 0
+ *
+ * FAILURE
+ * Invalid handle status
+ * -1 is returned if this handle is for a device.
+ *
+ */
+
+ULONG FASTCALL WK32FileClose(PVDMFRAME pFrame)
+{
+ PFILEIOCLOSE16 parg16;
+ PBYTE pJFT;
+ HANDLE Handle;
+ PDOSSFT pSFT;
+ ULONG ul;
+
+ GETARGPTR(pFrame, sizeof(FILEIOCLOSE16), parg16);
+
+ Handle = VDDRetrieveNtHandle(0, (SHORT) parg16->hFile, (PVOID *)&pSFT, &pJFT);
+
+ if (!Handle || !pSFT->SFT_Ref_Count) {
+ ul = ERROR_INVALID_HANDLE | 0xFFFF0000;
+ goto Cleanup;
+ }
+
+ if (pSFT->SFT_Flags & 0x80) { // Is this a device handle?
+ ul = 0xFFFFFFFF; // Let DOS handle device handles.
+ goto Cleanup;
+ }
+
+
+ // Set the JFT entry to 0xFF to free it up.
+
+ pJFT[FETCHWORD(parg16->hFile)] = 0xFF;
+
+
+ // Decrement reference count.
+
+ pSFT->SFT_Ref_Count--;
+
+ // Close the handle if the reference count was set to zero.
+
+ if (!pSFT->SFT_Ref_Count) {
+
+ FREEMAPFILECACHE(Handle);
+ LOGDEBUG(fileoclevel,("WK32FileClose: Close Handle:%X fh32:%X\n", parg16->hFile, Handle));
+
+ if (!CloseHandle(Handle)) {
+ ul = GetLastError() | 0xFFFF0000;
+ goto Cleanup;
+ }
+
+ //
+ // check if the handle being closed references a named pipe - we have to
+ // delete some info that we keep for the open named pipe
+ //
+
+ if (!pSFT->SFT_Ref_Count && IsVdmRedirLoaded()) {
+ VrRemoveOpenNamedPipeInfo(Handle);
+ }
+ }
+
+ ul = 0;
+
+Cleanup:
+ FREEARGPTR(parg16);
+ return ul;
+}
+
+
+/* WK32FileGetAttributes - Get file attributes
+ *
+ *
+ * Entry - pszPath File to get attributes from
+ *
+ * Exit
+ * SUCCESS
+ * Attributes for file
+ *
+ * FAILURE
+ * system status code
+ *
+ */
+
+ULONG FASTCALL WK32FileGetAttributes(PVDMFRAME pFrame)
+{
+ PFILEIOGETATTRIBUTES16 parg16;
+ PSTR pszPath, lpFileName;
+ ULONG attributes, l;
+ BOOL ItsANamedPipe;
+
+ GETARGPTR(pFrame, sizeof(FILEIOGETATTRIBUTES16), parg16);
+
+ pszPath = SEGPTR(FETCHWORD(parg16->pszPathSegment),
+ FETCHWORD(parg16->pszPathOffset));
+
+ FREEARGPTR(parg16);
+
+ WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
+
+ if (lpFileName = NormalizeDosPath(pszPath,
+ (WORD) (*(PUCHAR)DosWowData.lpCurDrv),
+ &ItsANamedPipe)) {
+
+ attributes = GetFileAttributesOem(lpFileName);
+ } else {
+ attributes = 0xFFFFFFFF;
+ }
+
+ if (ItsANamedPipe) {
+ LocalFree(lpFileName);
+ }
+
+ if (attributes == 0xFFFFFFFF) {
+ return (0xFFFF0000 | GetLastError());
+ }
+
+ // Success!
+ // Check to make sure that we didn't have a trailing backslash
+ // on this one. In that case we should fail with PATH_NOT_FOUND.
+
+ l = strlen(pszPath);
+
+ if (l > 0 &&
+ IS_ASCII_PATH_SEPARATOR(pszPath[l - 1]) &&
+ l != 1 &&
+ !(l == 3 && pszPath[1] == ':')) {
+
+ return (0xFFFF0000 | ERROR_PATH_NOT_FOUND);
+ }
+
+ return attributes == FILE_ATTRIBUTE_NORMAL
+ ? 0
+ : (attributes & DOS_ATTR_MASK);
+}
+
+
+/* WK32FileSetAttributes - Set file attributes
+ *
+ *
+ * Entry - pszPath File to get attributes from
+ *
+ * Exit
+ * SUCCESS
+ * Attributes for file
+ *
+ * FAILURE
+ * system status code
+ *
+ */
+
+ULONG FASTCALL WK32FileSetAttributes(PVDMFRAME pFrame)
+{
+ PWOWFILESETATTRIBUTES16 parg16;
+ PSTR pszPath, lpFileName;
+ ULONG attributes, l, dwReturn;
+ BOOL ItsANamedPipe;
+
+ GETARGPTR(pFrame, sizeof(WOWFILESETATTRIBUTES16), parg16);
+
+ pszPath = SEGPTR(FETCHWORD(parg16->pszPathSegment),
+ FETCHWORD(parg16->pszPathOffset));
+
+ if (!(attributes = (DWORD) FETCHWORD(parg16->wAttributes))) {
+ attributes = FILE_ATTRIBUTE_NORMAL;
+ }
+
+ FREEARGPTR(parg16);
+
+ // Check to make sure that we didn't have a trailing backslash
+ // on this one. In that case we should fail with PATH_NOT_FOUND.
+
+ l = strlen(pszPath);
+
+ WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
+
+ if ((l > 0 &&
+ IS_ASCII_PATH_SEPARATOR(pszPath[l - 1]) &&
+ l != 1 &&
+ !(l == 3 && pszPath[1] == ':')) ||
+ !(lpFileName = NormalizeDosPath(pszPath,
+ (WORD) (*(PUCHAR)DosWowData.lpCurDrv),
+ &ItsANamedPipe))) {
+
+ dwReturn = 0xFFFF0000 | ERROR_PATH_NOT_FOUND;
+ } else {
+
+ attributes &= DOS_ATTR_MASK;
+
+ if (SetFileAttributesOem(lpFileName, attributes)) {
+ dwReturn = 0;
+ } else {
+ dwReturn = 0xFFFF0000 | GetLastError();
+ }
+ }
+
+ if (ItsANamedPipe) {
+ LocalFree(lpFileName);
+ }
+
+ return (dwReturn);
+}
+
+
+/* WK32FileGetDateTime - Get file date and time
+ *
+ *
+ * Entry - fh DOS file handle
+ *
+ * Exit
+ * SUCCESS
+ * date and time for file
+ *
+ * FAILURE
+ * 0xFFFF
+ *
+ */
+
+ULONG FASTCALL WK32FileGetDateTime(PVDMFRAME pFrame)
+{
+ PFILEIOGETDATETIME16 parg16;
+ HANDLE Handle;
+ FILETIME LastWriteTime, LocalTime;
+ USHORT wDate, wTime;
+
+ GETARGPTR(pFrame, sizeof(FILEIOGETDATETIME16), parg16);
+
+ Handle = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, NULL, NULL);
+
+ FREEARGPTR(parg16);
+
+ if (!Handle ||
+ !GetFileTime(Handle, NULL, NULL, &LastWriteTime) ||
+ !FileTimeToLocalFileTime(&LastWriteTime, &LocalTime) ||
+ !FileTimeToDosDateTime(&LocalTime, &wDate, &wTime)) {
+
+ return 0xFFFF;
+ }
+
+ return (wTime | ((ULONG) wDate << 16));
+}
+
+/* WK32FileSetDateTime - Set file date and time
+ *
+ *
+ * Entry - fh DOS file handle
+ * date
+ * time
+ *
+ * Exit
+ * SUCCESS
+ * date and time for file set
+ *
+ * FAILURE
+ * 0xFFFF
+ *
+ */
+
+ULONG FASTCALL WK32FileSetDateTime(PVDMFRAME pFrame)
+{
+ PWOWFILESETDATETIME16 parg16;
+ HANDLE Handle;
+ FILETIME LastWriteTime, LocalTime;
+ USHORT wDate, wTime;
+
+ GETARGPTR(pFrame, sizeof(WOWFILESETDATETIME16), parg16);
+
+ Handle = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, NULL, NULL);
+
+ wDate = FETCHWORD(parg16->date);
+ wTime = FETCHWORD(parg16->time);
+
+ FREEARGPTR(parg16);
+
+ if (!Handle ||
+ !DosDateTimeToFileTime(wDate, wTime, &LocalTime) ||
+ !LocalFileTimeToFileTime(&LocalTime, &LastWriteTime) ||
+ !SetFileTime(Handle, NULL, NULL, &LastWriteTime)) {
+
+ return 0xFFFF;
+ }
+
+ return (0);
+}
+
+
+/* WK32FileLock - Locks or unlocks file data
+ *
+ *
+ * Entry - fh DOS file handle
+ * cbRegionOffset Start of file portion to lock or unlock
+ * cbRegionLength Length of file portion to lock or unlock
+ * al 0 for lock, 1 for unlock
+ *
+ * Exit
+ * SUCCESS
+ * 0
+ *
+ * FAILURE
+ * system status code
+ *
+ */
+
+ULONG FASTCALL WK32FileLock(PVDMFRAME pFrame)
+{
+ PFILEIOLOCK16 parg16;
+ HANDLE Handle;
+ UCHAR al;
+ DWORD cbOffset;
+ DWORD cbLength;
+
+ GETARGPTR(pFrame, sizeof(FILEIOLOCK16), parg16);
+
+ Handle = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, NULL, NULL);
+
+ al = FETCHWORD(parg16->ax) & 0xFF;
+ cbOffset = FETCHDWORD(parg16->cbRegionOffset);
+ cbLength = FETCHDWORD(parg16->cbRegionLength);
+
+ FREEARGPTR(parg16);
+
+ if (!Handle) {
+ return (0xFFFF0000 | ERROR_INVALID_HANDLE);
+ }
+
+ if (al == 0) { // lock
+
+ if (!LockFile(Handle, cbOffset, 0, cbLength, 0)) {
+ return (0xFFFF0000 | GetLastError());
+ }
+ } else if (al == 1) { // unlock
+
+ if (!UnlockFile(Handle, cbOffset, 0, cbLength, 0)) {
+ return (0xFFFF0000 | GetLastError());
+ }
+ } else { // bad parameter
+ return (0xFFFF0000 | ERROR_INVALID_FUNCTION);
+ }
+
+ return 0;
+}
+
+
+/* WK32FileFindFirst - Path-Style Find First File
+ *
+ * Entry - lpDTA pointer to app's DTA
+ * lpFile sz to path
+ * wAttributes flags for search
+ *
+ * Exit
+ * SUCCESS
+ * 0
+ *
+ * FAILURE
+ * system status code
+ *
+ */
+
+ULONG FASTCALL WK32FileFindFirst(PVDMFRAME pFrame)
+{
+ PWOWFINDFIRST16 parg16;
+ USHORT usSearchAttr;
+ PVOID pDTA;
+ PSTR ExpandName;
+ PSTR pFile;
+ BOOL ItsANamedPipe = FALSE;
+ DWORD dwRet = 0xFFFF0000 | ERROR_PATH_NOT_FOUND;
+
+ GETARGPTR(pFrame, sizeof(WOWFINDFIRST16), parg16);
+ GETVDMPTR(FETCHDWORD(parg16->lpDTA), SIZEOF_DOSSRCHDTA, pDTA);
+ pFile = SEGPTR(FETCHWORD(parg16->pszPathSegment),
+ FETCHWORD(parg16->pszPathOffset)
+ );
+
+ usSearchAttr = FETCHWORD(parg16->wAttributes);
+
+ FREEARGPTR(parg16);
+
+ WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
+
+ pFile = NormalizeDosPath(pFile,
+ (WORD) (*(PUCHAR)DosWowData.lpCurDrv),
+ &ItsANamedPipe
+ );
+
+ //
+ // add in curr directory and expand the "*"s in the path to "?"s
+ //
+ ExpandName = ExpandDosPath (pFile);
+
+
+ //
+ // invoke dem to do the search
+ //
+ if (ExpandName) {
+ dwRet = demFileFindFirst (pDTA, ExpandName, usSearchAttr);
+ } else {
+ dwRet = (DWORD)-1;
+ }
+
+ if (dwRet == -1) {
+ dwRet = 0xFFFF0000 | GetLastError();
+ } else if (dwRet) {
+ dwRet |= 0xFFFF0000;
+ }
+
+ FREEVDMPTR(pDTA);
+
+ if (ItsANamedPipe) {
+ LocalFree(pFile);
+ }
+
+ return (dwRet);
+
+}
+
+
+/* WK32FileFindNext - Path-Style Find Next File
+ *
+ * Entry - lpDTA pointer to app's DTA
+ *
+ * Exit
+ * SUCCESS
+ * 0
+ *
+ * FAILURE
+ * system status code
+ *
+ */
+ULONG FASTCALL WK32FileFindNext(PVDMFRAME pFrame)
+{
+ PWOWFINDNEXT16 parg16;
+ PVOID pDTA;
+ DWORD dwRet;
+
+ GETARGPTR(pFrame, sizeof(WOWFINDNEXT16), parg16);
+
+ GETVDMPTR(FETCHDWORD(parg16->lpDTA), SIZEOF_DOSSRCHDTA, pDTA);
+
+ FREEARGPTR(parg16);
+
+ if (dwRet = demFileFindNext (pDTA))
+ dwRet |= 0xFFFF0000;
+
+ FREEVDMPTR(pDTA);
+
+ return (dwRet);
+
+}
+
+
+BOOL FASTCALL IsModuleSymantecInstall(HAND16 hMod16)
+{
+ VPVOID vpFilename;
+ PSZ pszFilename;
+ CHAR szName[32];
+ CHAR szVersion[16];
+
+ return (
+ (vpFilename = stackalloc16(MAX_PATH)) &&
+ GetModuleFileName16(hMod16, vpFilename, MAX_PATH) &&
+ (pszFilename = GetPModeVDMPointer(vpFilename, MAX_PATH)) &&
+ WowGetProductNameVersion(pszFilename, szName, sizeof szName, szVersion, sizeof szVersion) &&
+ ! _stricmp(szName, "Symantec Install for Windows") &&
+ RtlEqualMemory(szVersion, "3.1.0.", 6)
+ );
+}
diff --git a/private/mvdm/wow32/wkfileio.h b/private/mvdm/wow32/wkfileio.h
new file mode 100644
index 000000000..33ea07e0b
--- /dev/null
+++ b/private/mvdm/wow32/wkfileio.h
@@ -0,0 +1,63 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1993, Microsoft Corporation
+ *
+ * WKLDEG.H
+ * WOW32 KRNL FAST SEGMENT LOADER
+ *
+ * History:
+ * Created 4-Jan-1993 by Matthew Felton (mattfe)
+--*/
+
+#define BADPTR 0xDEADBEEF
+#define FINDMAPFILECACHE(f) FindMapFileCache(f)
+#define ALLOCMAPFILECACHE() AllocMapFileCache()
+#define FREEMAPFILECACHE(h) FreeMapFileCache(h)
+
+#define MAX_MAPPED_FILES 12
+#define CACHE_BYTE_THRESHOLD 64*1024
+#define CACHE_READ_THRESHOLD 32*1024
+#define CACHE_ACCESS_THRESHOLD 20
+
+#define DOS_ATTR_MASK 0x0037 // File attribute bits which are the same
+ // for NT and DOS. See dem\dosdef.h
+
+#define IS_ASCII_PATH_SEPARATOR(ch) (((ch) == '/') || ((ch) == '\\'))
+
+
+typedef struct _HMAPPEDFILEALIAS { /* HMAPPEDFILEALIAS */
+ struct _HMAPPEDFILEALIAS *hpfNext; // Pointer to Next MappedFileCacheEntry
+ HANDLE hfile32;
+ HANDLE hMappedFileObject;
+ LPBYTE lpStartingAddressOfView;
+ DWORD lFilePointer;
+ DWORD dwFileSize;
+ BOOL fAccess;
+} HMAPPEDFILEALIAS, *PHMAPPEDFILEALIAS;
+
+PHMAPPEDFILEALIAS FindMapFileCache(HANDLE hFile);
+PHMAPPEDFILEALIAS AllocMapFileCache();
+
+VOID FreeMapFileCache(HANDLE hFile);
+ULONG FASTCALL WK32FileOpen(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileCreate(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileClose(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileGetAttributes(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileSetAttributes(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileGetDateTime(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileSetDateTime(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileLock(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileRead(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileWrite(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileLSeek(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileFindFirst(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FileFindNext(PVDMFRAME pFrame);
+VOID InitMapFileCache();
+VOID InsertMapFileCache( PHMAPPEDFILEALIAS pCache );
+BOOL W32MapViewOfFile( PHMAPPEDFILEALIAS pCache, HANDLE hFile);
+VOID FlushMapFileCaches(VOID);
+PSTR NormalizeDosPath(PSTR pszPath, WORD wCurrentDriveNumber, PBOOL ItsANamedPipe);
+
+extern INT fileoclevel;
diff --git a/private/mvdm/wow32/wkglobal.c b/private/mvdm/wow32/wkglobal.c
new file mode 100644
index 000000000..1104d510b
--- /dev/null
+++ b/private/mvdm/wow32/wkglobal.c
@@ -0,0 +1,341 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKGLOBAL.C
+ * WOW32 16-bit Kernel API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wkglobal.h"
+
+MODNAME(wkglobal.c);
+
+
+ULONG FASTCALL WK32GlobalAlloc(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALALLOC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALALLOC16), parg16);
+
+ ul = GETHGLOBAL16(GlobalAlloc(
+ WORD32(parg16->f1),
+ DWORD32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalCompact(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALCOMPACT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALCOMPACT16), parg16);
+
+#ifdef API16
+ ul = GETDWORD16(GlobalCompact(
+ DWORD32(parg16->f1)
+ ));
+#else
+ ul = 0;
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalFix(PVDMFRAME pFrame)
+{
+ register PGLOBALFIX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALFIX16), parg16);
+
+#ifdef API16
+ GlobalFix(
+ HGLOBAL32(parg16->f1)
+ );
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+ULONG FASTCALL WK32GlobalFlags(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALFLAGS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALFLAGS16), parg16);
+
+ ul = GETWORD16(GlobalFlags(
+ HGLOBAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalFree(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALFREE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALFREE16), parg16);
+
+ ul = GETHGLOBAL16(GlobalFree(
+ HGLOBAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalHandle(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALHANDLE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALHANDLE16), parg16);
+
+#ifdef API16
+ ul = GETDWORD16(GlobalHandle(
+ WORD32(parg16->f1)
+ ));
+#else
+ ul = 0;
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalLRUNewest(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALLRUNEWEST16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALLRUNEWEST16), parg16);
+
+ ul = GETHGLOBAL16(GlobalLRUNewest(
+ HGLOBAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalLRUOldest(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALLRUOLDEST16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALLRUOLDEST16), parg16);
+
+ ul = GETHGLOBAL16(GlobalLRUOldest(
+ HGLOBAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalLock(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALLOCK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALLOCK16), parg16);
+
+ ul = GETLPSTRBOGUS(GlobalLock(
+ HGLOBAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalNotify(PVDMFRAME pFrame)
+{
+ register PGLOBALNOTIFY16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALNOTIFY16), parg16);
+
+// This is a HACK and MUST be fixed, ChandanC, 11/7/91. This function
+// has been removed from the system.
+
+// GlobalNotify(
+// PROC32(parg16->f1)
+// );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+ULONG FASTCALL WK32GlobalPageLock(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALPAGELOCK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALPAGELOCK16), parg16);
+
+#ifdef API16
+ ul = GETWORD16(GlobalPageLock(
+ HGLOBAL32(parg16->f1)
+ ));
+#else
+ ul = 0;
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalPageUnlock(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALPAGEUNLOCK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALPAGEUNLOCK16), parg16);
+
+#ifdef API16
+ ul = GETWORD16(GlobalPageUnlock(
+ HGLOBAL32(parg16->f1)
+ ));
+#else
+ ul = 0;
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalReAlloc(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALREALLOC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALREALLOC16), parg16);
+
+ ul = GETHGLOBAL16(GlobalReAlloc(
+ HGLOBAL32(parg16->f1),
+ DWORD32(parg16->f2),
+ WORD32(parg16->f3)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalSize(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALSIZE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALSIZE16), parg16);
+
+ ul = GETDWORD16(GlobalSize(
+ HGLOBAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalUnWire(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALUNWIRE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALUNWIRE16), parg16);
+
+#ifdef API16
+ ul = GETBOOL16(GlobalUnWire(
+ HGLOBAL32(parg16->f1)
+ ));
+#else
+ ul = 0;
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalUnfix(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALUNFIX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALUNFIX16), parg16);
+
+#ifdef API16
+ ul = GETBOOL16(GlobalUnfix(
+ HGLOBAL32(parg16->f1)
+ ));
+#else
+ ul = 0;
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalUnlock(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALUNLOCK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALUNLOCK16), parg16);
+
+ ul = GETBOOL16(GlobalUnlock(
+ HGLOBAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32GlobalWire(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGLOBALWIRE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALWIRE16), parg16);
+
+#ifdef API16
+ ul = GETLPSTRBOGUS(GlobalWire(
+ HGLOBAL32(parg16->f1)
+ ));
+#else
+ ul = 0;
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wkglobal.h b/private/mvdm/wow32/wkglobal.h
new file mode 100644
index 000000000..490d8f2de
--- /dev/null
+++ b/private/mvdm/wow32/wkglobal.h
@@ -0,0 +1,33 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKGLOBAL.C
+ * WOW32 16-bit Kernel API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WK32GlobalAlloc(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalCompact(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalFix(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalFlags(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalFree(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalLRUNewest(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalLRUOldest(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalLock(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalNotify(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalPageLock(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalPageUnlock(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalReAlloc(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalSize(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalUnWire(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalUnfix(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalUnlock(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GlobalWire(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wkgthunk.c b/private/mvdm/wow32/wkgthunk.c
new file mode 100644
index 000000000..7d6fb356b
--- /dev/null
+++ b/private/mvdm/wow32/wkgthunk.c
@@ -0,0 +1,583 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1992, Microsoft Corporation
+ *
+ * wkgthunk.C
+ * WOW32 Generic Thunk Mechanism (for OLE 2.0 and others)
+ *
+ * History:
+ * Created 11-MARCH-1993 by Matt Felton (mattfe)
+ *
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wkgthunk.c);
+
+
+HINSTANCE FASTCALL WK32LoadLibraryEx32(PVDMFRAME pFrame)
+{
+ PSZ psz1;
+ HINSTANCE hinstance;
+ PLOADLIBRARYEX32 parg16;
+
+#ifdef i386
+ BYTE FpuState[108];
+
+ // Save the 487 state
+ _asm {
+ lea ecx, [FpuState]
+ fsave [ecx]
+ }
+#endif
+
+ GETARGPTR(pFrame, sizeof(LOADLIBRARYEX32), parg16);
+ GETVDMPTR(parg16->lpszLibFile,0,psz1);
+
+ //
+ // Make sure the Win32 current directory matches this task's.
+ //
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+ hinstance = LoadLibraryEx(psz1, (HANDLE)parg16->hFile, parg16->dwFlags);
+
+ FREEARGPTR(parg16);
+
+#ifdef i386
+ // Restore the 487 state
+ _asm {
+ lea ecx, [FpuState]
+ frstor [ecx]
+ }
+#endif
+
+ return (hinstance);
+}
+
+
+BOOL FASTCALL WK32FreeLibrary32(PVDMFRAME pFrame)
+{
+ BOOL fResult;
+ PFREELIBRARY32 parg16;
+
+ GETARGPTR(pFrame, sizeof(FREELIBRARY32), parg16);
+
+ fResult = FreeLibrary((HMODULE)parg16->hLibModule);
+
+ FREEARGPTR(parg16);
+ return (fResult);
+}
+
+
+FARPROC FASTCALL WK32GetProcAddress32(PVDMFRAME pFrame)
+{
+ FARPROC lpAddress;
+ PSZ psz1;
+ PGETPROCADDRESS32 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETPROCADDRESS32), parg16);
+ GETPSZIDPTR(parg16->lpszProc, psz1);
+
+ lpAddress = GetProcAddress((HMODULE)parg16->hModule, psz1);
+
+ FREEARGPTR(parg16);
+ return (lpAddress);
+}
+
+
+LPVOID FASTCALL WK32GetVDMPointer32(PVDMFRAME pFrame)
+{
+ LPVOID lpAddress;
+ PGETVDMPOINTER32 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETVDMPOITNER32), parg16);
+
+ lpAddress = WOWGetVDMPointer(parg16->lpAddress, 0, parg16->fMode);
+
+ FREEARGPTR(parg16);
+ return(lpAddress);
+}
+
+
+DWORD FASTCALL WK32ICallProc32(PVDMFRAME pFrame)
+{
+ register DWORD dwReturn;
+ PICALLPROC32 parg16;
+ UNALIGNED DWORD *pArg;
+ DWORD fAddress;
+ BOOL fSourceCDECL;
+ BOOL fDestCDECL;
+ UINT cParams;
+ UINT nParam;
+ UNALIGNED DWORD *lpArgs;
+ DWORD dwTemp[32];
+
+ GETARGPTR(pFrame, sizeof(*parg16), parg16);
+
+ fSourceCDECL = HIWORD(parg16->cParams) & CPEX32_SOURCE_CDECL;
+ fDestCDECL = HIWORD(parg16->cParams) & CPEX32_DEST_CDECL;
+
+ // We only support up to 32 parameters
+
+ cParams = LOWORD(parg16->cParams);
+
+ if (cParams > 32)
+ return(0);
+
+ // Don't call to Zero
+
+ if (parg16->lpProcAddress == 0) {
+ LOGDEBUG(LOG_ALWAYS,("WK32ICallProc32 - Error calling to 0 not allowed"));
+ return(0);
+ }
+
+ lpArgs = &parg16->p1;
+
+ // Convert Any 16:16 Addresses to 32 bit
+ // flat as required by fAddressConvert
+
+ pArg = lpArgs;
+
+ fAddress = parg16->fAddressConvert;
+
+ while (fAddress != 0) {
+ if (fAddress & 0x1) {
+ *pArg = (DWORD) GetPModeVDMPointer(*pArg, 0);
+ }
+ pArg++;
+ fAddress = fAddress >> 1;
+ }
+
+ //
+ // The above code is funny. It means that parameter translation will
+ // occur before accounting for the calling convention. This means that
+ // they will be specifying the bit position for pascal by counting the
+ // parameters from the end, whereas with cdecl, they count from the
+ // beginning. Weird for pascal, but that is compatible with what we've
+ // already shipped. cdecl should be more understandable.
+ //
+ // The above comment applies to CallProc32W, for CallProc32ExW,
+ // the lowest bit position always refers to the leftmost parameter.
+ //
+
+ //
+ // Make sure the Win32 current directory matches this task's.
+ //
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+
+#ifdef i386
+
+ {
+ extern DWORD WK32ICallProc32MakeCall(DWORD pfn, DWORD cArgs, VOID *pArgs);
+
+ //
+ // On x86 we call an assembly routine to actually make the call to
+ // the client's Win32 routine. The code is much more compact
+ // this way, and it's the only way we can be compatible with
+ // Win95's implementation, which cleans up the stack if the
+ // routine doesn't.
+ //
+ // This assembly routine "pushes" the arguments by copying
+ // them as a block, so they must be in the proper order for
+ // the destination calling convention.
+ //
+
+ if ( ! fSourceCDECL) {
+ //
+ // Invert the parameters
+ //
+ pArg = lpArgs;
+ lpArgs = dwTemp;
+
+ nParam = cParams;
+ while ( nParam != 0 ) {
+ --nParam;
+ lpArgs[nParam] = *pArg;
+ pArg++;
+ }
+ }
+
+ dwReturn = WK32ICallProc32MakeCall(parg16->lpProcAddress, cParams, lpArgs);
+ }
+
+#else
+
+ if ( fSourceCDECL != fDestCDECL ) {
+ //
+ // Invert the parameters
+ //
+ pArg = lpArgs;
+ lpArgs = dwTemp;
+
+ nParam = cParams;
+ while ( nParam != 0 ) {
+ --nParam;
+ lpArgs[nParam] = *pArg;
+ pArg++;
+ }
+ }
+
+ //
+ // lpArgs now points to the very first parameter in any calling convention
+ // And all of the parameters have been appropriately converted to flat ptrs
+ //
+
+ if ( fDestCDECL ) {
+ typedef int (FAR WINAPIV *FARFUNC)();
+
+ dwReturn = ((FARFUNC)parg16->lpProcAddress)(
+ lpArgs[ 0], lpArgs[ 1], lpArgs[ 2], lpArgs[ 3],
+ lpArgs[ 4], lpArgs[ 5], lpArgs[ 6], lpArgs[ 7],
+ lpArgs[ 8], lpArgs[ 9], lpArgs[10], lpArgs[11],
+ lpArgs[12], lpArgs[13], lpArgs[14], lpArgs[15],
+ lpArgs[16], lpArgs[17], lpArgs[18], lpArgs[19],
+ lpArgs[20], lpArgs[21], lpArgs[22], lpArgs[23],
+ lpArgs[24], lpArgs[25], lpArgs[26], lpArgs[27],
+ lpArgs[28], lpArgs[29], lpArgs[30], lpArgs[31] );
+ } else {
+ //
+ // There HAS to be a better way for portable variable number of
+ // Arguments
+ //
+ switch(cParams) {
+
+ case 0:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)();
+ break;
+ case 1:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[ 0] );
+ break;
+ case 2:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[ 1], lpArgs[ 0] );
+ break;
+ case 3:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+ case 4:
+
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+ case 5:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+ case 6:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+ case 7:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+ case 8:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 9:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 10:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 11:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 12:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 13:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 14:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 15:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+
+ case 16:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 17:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 18:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 19:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 20:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 21:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 22:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 23:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[22], lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 24:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[23], lpArgs[22], lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 25:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[24],
+ lpArgs[23], lpArgs[22], lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 26:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[25], lpArgs[24],
+ lpArgs[23], lpArgs[22], lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 27:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[26], lpArgs[25], lpArgs[24],
+ lpArgs[23], lpArgs[22], lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 28:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[27], lpArgs[26], lpArgs[25], lpArgs[24],
+ lpArgs[23], lpArgs[22], lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 29:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[28],
+ lpArgs[27], lpArgs[26], lpArgs[25], lpArgs[24],
+ lpArgs[23], lpArgs[22], lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 30:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[29], lpArgs[28],
+ lpArgs[27], lpArgs[26], lpArgs[25], lpArgs[24],
+ lpArgs[23], lpArgs[22], lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 31:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[30], lpArgs[29], lpArgs[28],
+ lpArgs[27], lpArgs[26], lpArgs[25], lpArgs[24],
+ lpArgs[23], lpArgs[22], lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ case 32:
+ dwReturn = ((FARPROC)parg16->lpProcAddress)(
+ lpArgs[31], lpArgs[30], lpArgs[29], lpArgs[28],
+ lpArgs[27], lpArgs[26], lpArgs[25], lpArgs[24],
+ lpArgs[23], lpArgs[22], lpArgs[21], lpArgs[20],
+ lpArgs[19], lpArgs[18], lpArgs[17], lpArgs[16],
+ lpArgs[15], lpArgs[14], lpArgs[13], lpArgs[12],
+ lpArgs[11], lpArgs[10], lpArgs[ 9], lpArgs[ 8],
+ lpArgs[ 7], lpArgs[ 6], lpArgs[ 5], lpArgs[ 4],
+ lpArgs[ 3], lpArgs[ 2], lpArgs[ 1], lpArgs[ 0] );
+ break;
+
+ }
+ }
+
+#endif
+
+
+ FREEARGPTR(parg16);
+ return(dwReturn);
+}
+
+
+//
+// Chicago has WOWGetVDMPointerFix, which is just like WOWGetVDMPointer
+// but also calls GlobalFix to keep the 16-bit memory from moving. It
+// has a companion WOWGetVDMPointerUnfix, which is basically a Win32-callable
+// GlobalUnfix.
+//
+// Chicago found the need for these functions because their global heaps
+// can be rearranged while Win32 code called from a generic thunk is
+// executing. In Windows NT, global memory cannot move while in a thunk
+// unless the thunk calls back to the 16-bit side.
+//
+// Our exported WOWGetVDMPointerFix is simply an alias to WOWGetVDMPointer --
+// it does *not* call GlobalFix because it is not needed in 99% of the
+// cases. WOWGetVDMPointerUnfix is implemented below as NOP.
+//
+
+VOID WOWGetVDMPointerUnfix(VPVOID vp)
+{
+ UNREFERENCED_PARAMETER(vp);
+
+ return;
+}
+
+
+//
+// Yielding functions allow 32-bit thunks to avoid 4 16<-->32 transitions
+// involved in calling back to 16-bit side to call Yield or DirectedYield,
+// which are thunked back to user32.
+//
+
+VOID WOWYield16(VOID)
+{
+ //
+ // Since WK32Yield (the thunk for Yield) doesn't use pStack16,
+ // just call it rather than duplicate the code.
+ //
+
+ WK32Yield(NULL);
+}
+
+VOID WOWDirectedYield16(WORD hTask16)
+{
+ //
+ // This is duplicating the code of WK32DirectedYield, the
+ // two must be kept synchronized.
+ //
+
+ BlockWOWIdle(TRUE);
+
+ (pfnOut.pfnDirectedYield)(THREADID32(hTask16));
+
+ BlockWOWIdle(FALSE);
+}
diff --git a/private/mvdm/wow32/wkgthunk.h b/private/mvdm/wow32/wkgthunk.h
new file mode 100644
index 000000000..152a17f8b
--- /dev/null
+++ b/private/mvdm/wow32/wkgthunk.h
@@ -0,0 +1,18 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1992, Microsoft Corporation
+ *
+ * WKGTHUNK.H
+ * WOW32 Generic Thunk Routines
+ *
+ * History:
+ * Created 11-March-1993 by Matthew Felton (mattfe)
+--*/
+
+DWORD FASTCALL WK32ICallProc32(PVDMFRAME pFrame);
+LPVOID FASTCALL WK32GetVDMPointer32(PVDMFRAME pFrame);
+FARPROC FASTCALL WK32GetProcAddress32(PVDMFRAME pFrame);
+BOOL FASTCALL WK32FreeLibrary32(PVDMFRAME pFrame);
+HINSTANCE FASTCALL WK32LoadLibraryEx32(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wklocal.c b/private/mvdm/wow32/wklocal.c
new file mode 100644
index 000000000..2db2c1b84
--- /dev/null
+++ b/private/mvdm/wow32/wklocal.c
@@ -0,0 +1,224 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKLOCAL.C
+ * WOW32 16-bit Kernel API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wklocal.c);
+
+
+ULONG FASTCALL WK32LocalAlloc(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALALLOC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALALLOC16), parg16);
+
+ ul = GETHLOCAL16(LocalAlloc(
+ WORD32(parg16->f1),
+ WORD32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalCompact(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALCOMPACT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALCOMPACT16), parg16);
+
+ ul = GETWORD16(LocalCompact(
+ WORD32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalFlags(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALFLAGS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALFLAGS16), parg16);
+
+ ul = GETWORD16(LocalFlags(
+ HLOCAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalFree(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALFREE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALFREE16), parg16);
+
+ ul = GETHLOCAL16(LocalFree(
+ HLOCAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalHandle(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALHANDLE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALHANDLE16), parg16);
+
+ ul = GETHLOCAL16(LocalHandle(
+ (LPSTR) WORD32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalInit(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALINIT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALINIT16), parg16);
+
+#ifdef API16
+ ul = GETBOOL16(LocalInit(
+ WORD32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3)
+ ));
+#else
+ ul = 0;
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalLock(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALLOCK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALLOCK16), parg16);
+
+ ul = GETNPSTRBOGUS(LocalLock(
+ HLOCAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalNotify(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALNOTIFY16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALNOTIFY16), parg16);
+
+#ifdef API16
+ ul = GETPROC16(LocalNotify(
+ PROC32(parg16->f1)
+ ));
+#else
+ ul = 0;
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalReAlloc(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALREALLOC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALREALLOC16), parg16);
+
+ ul = GETHLOCAL16(LocalReAlloc(
+ HLOCAL32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalShrink(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALSHRINK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALSHRINK16), parg16);
+
+ ul = GETWORD16(LocalShrink(
+ HLOCAL32(parg16->f1),
+ WORD32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalSize(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALSIZE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALSIZE16), parg16);
+
+ ul = GETWORD16(LocalSize(
+ HLOCAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WK32LocalUnlock(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCALUNLOCK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCALUNLOCK16), parg16);
+
+ ul = GETBOOL16(LocalUnlock(
+ HLOCAL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wklocal.h b/private/mvdm/wow32/wklocal.h
new file mode 100644
index 000000000..22232b44a
--- /dev/null
+++ b/private/mvdm/wow32/wklocal.h
@@ -0,0 +1,27 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKLOCAL.C
+ * WOW32 16-bit Kernel API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WK32LocalAlloc(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalCompact(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalFlags(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalFree(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalInit(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalLock(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalNotify(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalReAlloc(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalShrink(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalSize(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LocalUnlock(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wkman.c b/private/mvdm/wow32/wkman.c
new file mode 100644
index 000000000..bba2d4bc4
--- /dev/null
+++ b/private/mvdm/wow32/wkman.c
@@ -0,0 +1,4970 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKMAN.C
+ * WOW32 16-bit Kernel API support (manually-coded thunks)
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * 20-Apr-91 Matt Felton (mattfe) Added WK32CheckLoadModuleDrv
+ * 28-Jan-92 Matt Felton (mattfe) Added Wk32GetNextVdmCommand + MIPS build
+ * 10-Feb-92 Matt Felton (mattfe) Removed WK32CheckLoadModuleDRV
+ * 10-Feb-92 Matt Felton (mattfe) cleanup and task creation
+ * 4-mar-92 mattfe add killprocess
+ * 11-mar-92 mattfe added W32NotifyThread
+ * 12-mar-92 mattfe added WowRegisterShellWindowHandle
+ * 17-apr-92 daveh changed to use host_CreateThread and host_ExitThread
+ * 11-jun-92 mattfe hung app support W32HungAppNotifyThread, W32EndTask
+ *
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+#include <ntexapi.h>
+#include <sharewow.h>
+#include <vdmdbg.h>
+#include <ntseapi.h>
+#include "wowfax.h"
+
+extern void UnloadNetworkFonts( UINT id );
+
+MODNAME(wkman.c);
+
+BOOL GetWOWShortCutInfo (PULONG Bufsize, PVOID Buf);
+extern void FreeTaskFormFeedHacks(HAND16 h16);
+
+// Global DATA
+
+//
+// The 5 variables below are used to hold STARTUPINFO fields between
+// WowExec's GetNextVdmComand call and the InitTask call of the new
+// app. We pass them on to user32's InitTask.
+//
+
+DWORD dwLastHotkey = 0;
+DWORD dwLastX = (DWORD) CW_USEDEFAULT;
+DWORD dwLastY = (DWORD) CW_USEDEFAULT;
+DWORD dwLastXSize = (DWORD) CW_USEDEFAULT;
+DWORD dwLastYSize = (DWORD) CW_USEDEFAULT;
+
+HWND ghwndShell = (HWND)0; // WOWEXEC Window Handle
+HANDLE ghInstanceUser32 = (HANDLE)0;
+
+HAND16 ghShellTDB = 0; // WOWEXEC TDB
+HANDLE ghevWowExecMsgWait = (HANDLE)0;
+HANDLE ghevWaitHungAppNotifyThread = (HANDLE)-1; // Syncronize App Termination to Hung App NotifyThread
+HANDLE ghNotifyThread = (HANDLE)-1; // Notification Thread Handle
+HANDLE ghHungAppNotifyThread = (HANDLE)-1; // HungAppNotification ThreadHandle
+PTD gptdTaskHead = NULL; // Linked List of TDs
+CRITICAL_SECTION gcsWOW; // WOW Critical Section used when updating task linked list
+CRITICAL_SECTION gcsHungApp; // HungApp Critical Section used when VDM_WOWHUNGAPP bit
+
+HMODCACHE ghModCache[CHMODCACHE]= { 0 }; // avoid callbacks to get 16-bit hMods
+
+HANDLE ghTaskCreation = NULL; // hThread from task creation (see Yield)
+
+VPVOID vpnum_tasks; // Pointer to KDATA variables (KDATA.ASM)
+PWORD16 pCurTDB; // Pointer to KDATA variables
+PWORD16 pCurDirOwner; // Pointer to KDATA variables
+VPVOID vpDebugWOW = 0; // Pointer to KDATA variables
+VPVOID vpLockTDB; // Pointer to KDATA variables
+VPVOID vptopPDB = 0; // KRNL PDB
+DOSWOWDATA DosWowData; // structure that keeps linear pointer to
+ // DOS internal variables.
+
+
+
+//
+// List of known DLLs used by WK32WowIsKnownDLL, called by 16-bit LoadModule.
+// This causes known DLLs to be forced to load from the 32-bit system
+// directory, since these are "special" binaries that should not be
+// overwritten by unwitting 16-bit setup programs.
+//
+// This list is initialized from the registry value
+// ...\CurrentControlSet\Control\WOW\KnownDLLs REG_SZ (space separated list)
+//
+
+#define MAX_KNOWN_DLLS 64
+PSZ apszKnownDLL[MAX_KNOWN_DLLS];
+
+//
+// Fully-qualified path to %windir%\control.exe for PM5 setup fix.
+// Setup by WK32InitWowIsKnownDll, used by WK32WowIsKnownDll.
+//
+CHAR szBackslashControlExe[] = "\\control.exe";
+PSZ pszControlExeWinDirPath; // "c:\winnt\control.exe"
+PSZ pszControlExeSysDirPath; // "c:\winnt\system32\control.exe"
+CHAR szBackslashProgmanExe[] = "\\progman.exe";
+PSZ pszProgmanExeWinDirPath; // "c:\winnt\progman.exe"
+PSZ pszProgmanExeSysDirPath; // "c:\winnt\system32\progman.exe"
+
+char szWOAWOW32[] = "-WoAWoW32";
+
+//
+// String that represents section in win.ini which we notify the shell
+// of having been changed if setup ran
+//
+char szExtensions[] = "Extensions";
+
+//
+// WOW GDI/CSR batching limit.
+//
+
+DWORD dwWOWBatchLimit = 0;
+
+
+UINT GetWOWTaskId(void);
+
+#define TOOLONGLIMIT _MAX_PATH
+#define WARNINGMSGLENGTH 255
+
+static char szCaption[TOOLONGLIMIT + WARNINGMSGLENGTH];
+static char szMsgBoxText[TOOLONGLIMIT + WARNINGMSGLENGTH];
+
+extern HANDLE hmodWOW32;
+
+
+/* WK32WaitEvent - First API called by app, courtesy the C runtimes
+ *
+ * ENTRY
+ *
+ * EXIT
+ * Returns TRUE to indicate that a reschedule occurred
+ *
+ *
+ */
+
+ULONG FASTCALL WK32WaitEvent(PVDMFRAME pFrame)
+{
+ UNREFERENCED_PARAMETER(pFrame);
+ return TRUE;
+}
+
+
+/* WK32KernelTrace - Trace 16Bit Kernel API Calls
+ *
+ * ENTRY
+ *
+ * EXIT
+ *
+ *
+ */
+
+ULONG FASTCALL WK32KernelTrace(PVDMFRAME pFrame)
+{
+#ifdef DEBUG
+PBYTE pb1;
+PBYTE pb2;
+register PKERNELTRACE16 parg16;
+
+ // Check Filtering - Trace Correct TaskID and Kernel Tracing Enabled
+
+ if (((WORD)(pFrame->wTDB & fLogTaskFilter) == pFrame->wTDB) &&
+ ((fLogFilter & FILTER_KERNEL16) != 0 )) {
+
+ GETARGPTR(pFrame, sizeof(KERNELTRACE16), parg16);
+ GETVDMPTR(parg16->lpRoutineName, 50, pb1);
+ GETVDMPTR(parg16->lpUserArgs, parg16->cParms, pb2);
+ if ((fLogFilter & FILTER_VERBOSE) == 0 ) {
+ LOGDEBUG(12, ("%s(", pb1));
+ } else {
+ LOGDEBUG(12, ("%04X %08X %04X %s:%s(",pFrame->wTDB, pb2, pFrame->wAppDS, (LPSZ)"Kernel16", pb1));
+ }
+
+ pb2 += 2*sizeof(WORD); // point past callers CS:IP
+
+ pb2 += parg16->cParms;
+
+ while (parg16->cParms > 0) {
+ pb2 -= sizeof(WORD);
+ parg16->cParms -= sizeof(WORD);
+ LOGDEBUG(12,( "%04x", *(PWORD)pb2));
+ if (parg16->cParms > 0) {
+ LOGDEBUG(12,( ","));
+ }
+ }
+
+ LOGDEBUG(12,( ")\n"));
+ if (fDebugWait != 0) {
+ DbgPrint("WOWSingle Step\n");
+ DbgBreakPoint();
+ }
+
+ FREEVDMPTR(pb1);
+ FREEVDMPTR(pb2);
+ FREEARGPTR(parg16);
+ }
+#else
+ UNREFERENCED_PARAMETER(pFrame);
+#endif
+ return TRUE;
+}
+
+
+DWORD ParseHotkeyReserved(
+ CHAR *pchReserved)
+{
+ ULONG dw;
+ CHAR *pch;
+
+ if (!pchReserved || !*pchReserved)
+ return 0;
+
+ dw = 0;
+
+ if ((pch = strstr(pchReserved, "hotkey")) != NULL) {
+ pch += strlen("hotkey");
+ pch++;
+ dw = atoi(pch);
+ }
+
+ return dw;
+}
+
+
+/* WK32WowGetNextVdmCommand - Get Next App Name to Exec
+ *
+ *
+ * Entry - lpReturnedString - Pointer to String Buffer
+ * nSize - Size of Buffer
+ *
+ * Exit
+ * SUCCESS
+ * if (!pWowInfo->CmdLineSize) {
+ * // no apps queued
+ * } else {
+ * Buffer Has Next App Name to Exec
+ * and new environment
+ * }
+ *
+ * FAILURE
+ * Buffer Size too Small or Environment is too small
+ * pWowInfo->EnvSize - required size
+ * pWowInfo->CmdLineSize - required size
+ *
+ *
+ */
+
+ULONG FASTCALL WK32WowGetNextVdmCommand (PVDMFRAME pFrame)
+{
+
+ ULONG ul;
+ PSZ pszEnv16, pszEnv, pszCurDir, pszCmd, pszAppName, pszEnv32, pszTemp;
+ register PWOWGETNEXTVDMCOMMAND16 parg16;
+ PWOWINFO pWowInfo;
+ VDMINFO VDMInfo;
+ PCHAR pTemp;
+ WORD w;
+ CHAR szSiReservedBuf[128];
+
+ GETARGPTR(pFrame, sizeof(WOWGETNEXTVDMCOMMAND16), parg16);
+ GETVDMPTR(parg16->lpWowInfo, sizeof(WOWINFO), pWowInfo);
+ GETVDMPTR(pWowInfo->lpCmdLine, pWowInfo->CmdLineSize, pszCmd);
+ GETVDMPTR(pWowInfo->lpAppName, pWowInfo->AppNameSize, pszAppName);
+ GETVDMPTR(pWowInfo->lpEnv, pWowInfo->EnvSize, pszEnv);
+ GETVDMPTR(pWowInfo->lpCurDir, pWowInfo->CurDirSize, pszCurDir);
+
+ pszEnv16 = pszEnv;
+
+ // if we have a real environment pointer and size then
+ // malloc a 32 bit buffer. Note that the 16 bit buffer should
+ // be twice the size.
+
+ VDMInfo.Enviornment = pszEnv;
+ pszEnv32 = NULL;
+
+ if (pWowInfo->EnvSize != 0) {
+ if (pszEnv32 = malloc_w(pWowInfo->EnvSize)) {
+ VDMInfo.Enviornment = pszEnv32;
+ }
+ }
+
+
+SkipWowExec:
+
+ VDMInfo.CmdLine = pszCmd;
+ VDMInfo.CmdSize = pWowInfo->CmdLineSize;
+ VDMInfo.AppName = pszAppName;
+ VDMInfo.AppLen = pWowInfo->AppNameSize;
+ VDMInfo.PifFile = NULL;
+ VDMInfo.PifLen = 0;
+ VDMInfo.CurDrive = 0;
+ VDMInfo.EnviornmentSize = pWowInfo->EnvSize;
+ VDMInfo.ErrorCode = TRUE;
+ VDMInfo.VDMState = fSeparateWow ? ASKING_FOR_SEPWOW_BINARY : ASKING_FOR_WOW_BINARY;
+ VDMInfo.iTask = 0;
+ VDMInfo.StdIn = 0;
+ VDMInfo.StdOut = 0;
+ VDMInfo.StdErr = 0;
+ VDMInfo.CodePage = 0;
+ VDMInfo.TitleLen = 0;
+ VDMInfo.DesktopLen = 0;
+ VDMInfo.CurDirectory = pszCurDir;
+ VDMInfo.CurDirectoryLen = pWowInfo->CurDirSize;
+ VDMInfo.Reserved = szSiReservedBuf;
+ VDMInfo.ReservedLen = sizeof(szSiReservedBuf);
+
+ ul = GetNextVDMCommand (&VDMInfo);
+
+ if (ul) {
+
+ //
+ // BaseSrv will return TRUE with CmdSize == 0 if no more commands
+ //
+ if (VDMInfo.CmdSize == 0) {
+ pWowInfo->CmdLineSize = 0;
+ goto CleanUp;
+ }
+
+ //
+ // If wowexec is the appname then we don't want to pass it back to
+ // the existing instance of wowexec in a shared VDM since it will
+ // basically do nothing but load and exit. Since it is not run we
+ // need call ExitVDM to cleanup. Next we go back to look for more
+ // commands.
+ //
+ if ((! fSeparateWow) && strstr(VDMInfo.AppName, "wowexec.exe")) {
+ ExitVDM(WOWVDM, VDMInfo.iTask);
+ goto SkipWowExec;
+ }
+
+ }
+
+
+ //
+ // WOWEXEC will initially call with a guess of the correct environment
+ // size. If he did not allocate enough then we will return the appropriate
+ // size so that he can try again. WOWEXEC knows that we will require a
+ // buffer twice the size specified. The environment can be up to 64k since
+ // 16 bit LoadModule can only take a selector pointer to the environment.
+ //
+
+ if ( VDMInfo.EnviornmentSize > pWowInfo->EnvSize ||
+ VDMInfo.CmdSize > (USHORT)pWowInfo->CmdLineSize ||
+ VDMInfo.AppLen > (USHORT)pWowInfo->AppNameSize ||
+ VDMInfo.CurDirectoryLen > (ULONG)pWowInfo->CurDirSize )
+ {
+
+ // We return the size specified, but assume that WOWEXEC will double
+ // it when allocating memory to allow for the string conversion/
+ // expansion that might happen for international versions of NT.
+ // See below where we uppercase and convert to OEM characters.
+
+ w = 2*(WORD)VDMInfo.EnviornmentSize;
+ if ( (DWORD)w == 2*(VDMInfo.EnviornmentSize) ) {
+ // Fit in a Word!
+ pWowInfo->EnvSize = (WORD)VDMInfo.EnviornmentSize;
+ } else {
+ // Make it the max size (see 16 bit globalrealloc)
+ pWowInfo->EnvSize = (65536-17)/2;
+ }
+
+ // Pass back other correct sizes required
+ pWowInfo->CmdLineSize = VDMInfo.CmdSize;
+ pWowInfo->AppNameSize = VDMInfo.AppLen;
+ pWowInfo->CurDirSize = (USHORT)VDMInfo.CurDirectoryLen;
+ ul = FALSE;
+ }
+
+ if ( ul ) {
+
+ //
+ // Boost the hour glass
+ //
+
+ ShowStartGlass (10000);
+
+ //
+ // Save away wShowWindow, hotkey and startup window position from
+ // the STARTUPINFO structure. We'll pass them over to UserSrv during
+ // the new app's InitTask call. The assumption here is that this
+ // will be the last GetNextVDMCommand call before the call to InitTask
+ // by the newly-created task.
+ //
+
+ dwLastHotkey = ParseHotkeyReserved(VDMInfo.Reserved);
+
+ if (VDMInfo.StartupInfo.dwFlags & STARTF_USESHOWWINDOW) {
+ pWowInfo->wShowWindow =
+ (VDMInfo.StartupInfo.wShowWindow == SW_SHOWDEFAULT)
+ ? SW_SHOW : VDMInfo.StartupInfo.wShowWindow ;
+ } else {
+ pWowInfo->wShowWindow = SW_SHOW;
+ }
+
+ if (VDMInfo.StartupInfo.dwFlags & STARTF_USEPOSITION) {
+ dwLastX = VDMInfo.StartupInfo.dwX;
+ dwLastY = VDMInfo.StartupInfo.dwY;
+ } else {
+ dwLastX = dwLastY = (DWORD) CW_USEDEFAULT;
+ }
+
+ if (VDMInfo.StartupInfo.dwFlags & STARTF_USESIZE) {
+ dwLastXSize = VDMInfo.StartupInfo.dwXSize;
+ dwLastYSize = VDMInfo.StartupInfo.dwYSize;
+ } else {
+ dwLastXSize = dwLastYSize = (DWORD) CW_USEDEFAULT;
+ }
+
+ LOGDEBUG(4, ("WK32WowGetNextVdmCommand: HotKey: %u\n"
+ " Window Pos: (%u,%u)\n"
+ " Window Size: (%u,%u)\n",
+ dwLastHotkey, dwLastX, dwLastY, dwLastXSize, dwLastYSize));
+
+
+ // 20-Jan-1994 sudeepb
+ // Following callout is for inheriting the directories for the new
+ // task. After this we mark the CDS's to be invalid which will force
+ // new directories to be pickedup on need basis. See bug#1995 for
+ // details.
+
+ W32RefreshCurrentDirectories (pszEnv32);
+
+ // Save iTask
+ // When Server16 does the Exec Call we can put this Id into task
+ // Structure. When the WOW app dies we can notify Win32 using this
+ // taskid so if any apps are waiting they will get notified.
+
+ iW32ExecTaskId = VDMInfo.iTask;
+
+ //
+ // krnl expects ANSI strings!
+ //
+
+ OemToChar(pszCmd, pszCmd);
+ OemToChar(pszAppName, pszAppName);
+
+ //
+ // So should the current directory be OEM or Ansi?
+ //
+
+
+ pWowInfo->iTask = VDMInfo.iTask;
+ pWowInfo->CurDrive = VDMInfo.CurDrive;
+ pWowInfo->EnvSize = (USHORT)VDMInfo.EnviornmentSize;
+
+
+ // Uppercase the Environment KeyNames but leave the environment
+ // variables in mixed case - to be compatible with MS-DOS
+ // Also convert environment to OEM character set
+
+ if (pszEnv32) {
+
+ for (pszTemp = pszEnv32;*pszTemp;pszTemp += (strlen(pszTemp) + 1)) {
+
+ // The MS-DOS Environment is OEM
+
+ CharToOem(pszTemp,pszEnv);
+
+ // Ignore the NT specific Environment variables that start ==
+
+ if (*pszEnv != '=') {
+ if (pTemp = strchr(pszEnv,'=')) {
+ *pTemp = '\0';
+
+ // don't uppercase "windir" as it is lowercase for
+ // Win 3.1 and MS-DOS apps.
+
+ if (pTemp-pszEnv != 6 || strncmp(pszEnv, "windir", 6))
+ _strupr(pszEnv);
+ *pTemp = '=';
+ }
+ }
+ pszEnv += (strlen(pszEnv) + 1);
+ }
+
+ // Environment is Double NULL terminated
+ *pszEnv = '\0';
+ }
+ }
+
+ CleanUp:
+ if (pszEnv32) {
+ free_w(pszEnv32);
+ }
+
+ FLUSHVDMPTR(parg16->lpWowInfo, sizeof(WOWINFO), pWowInfo);
+ FLUSHVDMPTR((ULONG)pWowInfo->lpCmdLine, pWowInfo->CmdLineSize, pszCmd);
+
+ FREEVDMPTR(pszCmd);
+ FREEVDMPTR(pszEnv);
+ FREEVDMPTR(pszCurDir);
+ FREEVDMPTR(pWowInfo);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/*++
+
+ WK32WOWInitTask - API Used to Create a New Task + Thread
+
+ Routine Description:
+
+ All the 16 bit initialization is completed, the app is loaded in memory and ready to go
+ we come here to create a thread for this task.
+
+ The current thread impersonates the new task, its running on the new tasks stack and it
+ has its wTDB, this makes it easy for us to get a pointer to the new tasks stack and for it
+ to have the correct 16 bit stack frame. In order for the creator to continue correctly
+ we set RET_TASKSTARTED on the stack. Kernel16 will then not return to the new task
+ but will know to restart the creator and put his thread ID and stack back.
+
+ We ResetEvent so we can wait for the new thread to get going, this is important since
+ we want the first YIELD call from the creator to yield to the newly created task.
+
+ Special Case During Boot
+ During the boot process the kernel will load the first app into memory on the main thread
+ using the regular LoadModule. We don't want the first app to start running until the kernel
+ boot is completed so we can reuse the first thread.
+
+ Arguments:
+ pFrame - Points to the New Tasks Stack Frame
+
+ Return Value:
+ TRUE - Successfully Created a Thread
+ FALSE - Failed to Create a New Task
+
+--*/
+
+ULONG FASTCALL WK32WOWInitTask(PVDMFRAME pFrame)
+{
+ VPVOID vpStack;
+ DWORD dwThreadId;
+ HANDLE hThread;
+
+#if FASTBOPPING
+ vpStack = FASTVDMSTACK();
+#else
+ vpStack = VDMSTACK();
+#endif
+
+
+ pFrame->wRetID = RET_TASKSTARTED;
+
+ /*
+ * Suspend the timer thread on the startup of every task
+ * To allow resyncing of the dos time to the system time.
+ * When wowexec is the only task running the timer thread
+ * will remain suspended. When the new task actually intializes
+ * it will resume the timer thread, provided it is not wowexec.
+ */
+ if (nWOWTasks != 1)
+ SuspendTimerThread(); // turns timer thread off
+
+ if (fBoot) {
+ W32Thread((LPVOID)vpStack); // SHOULD NEVER RETURN
+
+ WOW32ASSERTMSG(FALSE, "\nWOW32: WK32WOWInitTask ERROR - Main Thread Returning - Contact DaveHart\n");
+ ExitVDM(WOWVDM, ALL_TASKS);
+ ExitProcess(EXIT_FAILURE);
+ }
+
+ hThread = host_CreateThread(NULL,
+ 8192,
+ W32Thread,
+ (LPVOID)vpStack,
+ CREATE_SUSPENDED,
+ &dwThreadId);
+
+ ((PTDB)SEGPTR(pFrame->wTDB,0))->TDB_hThread = (DWORD) hThread;
+ ((PTDB)SEGPTR(pFrame->wTDB,0))->TDB_ThreadID = dwThreadId;
+
+ if ( hThread ) {
+ ghTaskCreation = hThread;
+ }
+
+#ifdef DEBUG
+ {
+ char szModName[9];
+
+ RtlCopyMemory(szModName, ((PTDB)SEGPTR(pFrame->wTDB,0))->TDB_ModName, 8);
+ szModName[8] = 0;
+
+ LOGDEBUG( hThread ? LOG_IMPORTANT : LOG_ALWAYS,
+ ("\nWK32WOWInitTask: %s task %04x %s\n",
+ hThread ? "created" : "ERROR failed to create",
+ pFrame->wTDB,
+ szModName
+ ));
+ }
+#endif
+
+ return hThread ? TRUE : FALSE;
+}
+
+
+/*++
+ WK32YIELD - Yield to the Next Task
+
+ Routine Description:
+
+ Normal Case - A 16 bit task is running and wants to give up the CPU to any higher priority
+ task that might want to run. Since we are running with a non-preemptive scheduler apps
+ have to cooperate.
+
+ ENTRY
+ pFrame - Not used
+
+ EXIT
+ Nothing
+
+--*/
+
+ULONG FASTCALL WK32Yield(PVDMFRAME pFrame)
+{
+ //
+ // WARNING: wkgthunk.c's WOWYield16 export (part of the Generic Thunk
+ // interface) calls this thunk with a NULL pFrame. If you
+ // change this function to use pFrame change WOWYield16 as
+ // well.
+ //
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ if (ghTaskCreation) {
+ DWORD dw;
+ HANDLE ThreadEvents[2];
+
+ ResumeThread(ghTaskCreation);
+ ThreadEvents[1] = ghTaskCreation;
+ ghTaskCreation = NULL;
+ ThreadEvents[0] = ghevWaitCreatorThread;
+
+ dw = WaitForMultipleObjects(2, ThreadEvents, FALSE, INFINITE);
+ if (dw != WAIT_OBJECT_0) {
+ if (dw == -1 && GetLastError() == ERROR_INVALID_HANDLE) {
+
+ //
+ // The new task managed to go away before we entered
+ // WaitForMultipleObjects. No problem. Wait on the
+ // auto-reset ghevWaitCreatorThread event to reset
+ // it.
+ //
+
+ WOW32VERIFY(WAIT_OBJECT_0 ==
+ WaitForSingleObject(ghevWaitCreatorThread, INFINITE));
+
+ } else {
+ WOW32ASSERTMSGF(TRUE,
+ ("\nWK32Yield: ERROR WaitInitTask %08X error %08X\n\n", dw, GetLastError()));
+ ResetEvent(ghevWaitCreatorThread);
+ }
+
+ }
+
+ LOGDEBUG(2,("WK32Yield: Creator thread %04X now yielding\n", pFrame->wTDB));
+ }
+
+
+ BlockWOWIdle(TRUE);
+
+ (pfnOut.pfnYieldTask)();
+
+ BlockWOWIdle(FALSE);
+
+
+ RETURN(0);
+}
+
+
+
+
+ULONG FASTCALL WK32OldYield(PVDMFRAME pFrame)
+{
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ BlockWOWIdle(TRUE);
+
+ (pfnOut.pfnDirectedYield)(DY_OLDYIELD);
+
+ BlockWOWIdle(FALSE);
+
+
+ RETURN(0);
+}
+
+
+
+
+
+/*++
+ WK32ForegroundIdleHook - Supply WMU_FOREGROUNDIDLE message when system
+ (foreground "task") goes idle; support for int 2f
+
+ Routine Description:
+
+ This is the hook procedure for idle detection. When the
+ foregorund task goes idle, if the int 2f is hooked, then
+ we will get control here and we call Wow16 to issue
+ the int 2f:1689 to signal the idle condition to the hooker.
+
+ ENTRY
+ normal hook parameters: ignored
+
+ EXIT
+ Nothing
+
+--*/
+
+LRESULT CALLBACK WK32ForegroundIdleHook(int code, WPARAM wParam, LPARAM lParam)
+{
+ PARM16 Parm16;
+
+ UNREFERENCED_PARAMETER(code);
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+
+ CallBack16(RET_FOREGROUNDIDLE, &Parm16, 0, 0);
+
+ RETURN(0);
+}
+
+
+/*++
+ WK32WowSetIdleHook - Set the hook so we will get notified when the
+ (foreground "task") goes idle; support for int 2f
+
+ Routine Description:
+
+ This sets the hook procedure for idle detection. When the
+ foregorund task goes idle, if the int 2f is hooked, then
+ we will get control above and send a message to WOW so it can issue
+ the int 2f:1689 to signal the idle condition to the hooker.
+
+ ENTRY
+ pFrame - not used
+
+ EXIT
+ The hook is set and it's handle is placed in to the per thread
+ data ptd->hIdleHook. 0 is returned. On
+ failure, the hook is just not set (sorry), but a debug call is
+ made.
+
+--*/
+
+ULONG FASTCALL WK32WowSetIdleHook(PVDMFRAME pFrame)
+{
+ PTD ptd;
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ptd = CURRENTPTD();
+
+ if (ptd->hIdleHook == NULL) {
+
+ // If there is no hook already set then set a GlobaHook
+ // It is important to set a GlobalHook otherwise we will not
+ // Get accurate timing results with a LocalHook.
+
+ ptd->hIdleHook = SetWindowsHookEx(WH_FOREGROUNDIDLE,
+ WK32ForegroundIdleHook,
+ hmodWOW32,
+ 0);
+
+ if (ptd->hIdleHook == NULL) {
+ OutputDebugString("\nWK32WowSetIdleHook : ERROR failed to Set Idle Hook Proc\n\n");
+ }
+ }
+ RETURN(0);
+}
+
+
+
+/*++
+
+ W32Thread - New Thread Starts Here
+
+ Routine Description:
+
+ A newly created thread starts here. We Allocated the Per Task Data from
+ the Threads Stack and point NtCurrentTeb()->WOW32Reserved at it, so that
+ we can find it quickly when we dispatch an api or recieve a message from
+ Win 32.
+
+ NOTE - The Call to Win32 InitTask() does NOT return until we are in sync
+ with the other 16 bit tasks in the non-preemptive scheduler.
+
+ Once We have everything initialized we SetEvent to wake our Creator thread
+ and then call Win32 to get in sync with the other tasks running in the
+ non-preemptive scheduler.
+
+ Special Case - BOOT
+ We return (host_simulate) to the caller - kernel16, so he can complete
+ his initialization and then reuse the same thread to start the first app
+ (usually wowexec the wow shell).
+
+ The second host_simulate call doesn't return until the app exits
+ (see tasking.asm - ExitSchedule) at which point we tidy up the task and
+ then kill this thread. Win32 Non-Preemptive Scheduler will detect the
+ thread going away and will then schedule another task.
+
+ ENTRY
+ 16:16 to New Task Stack
+
+ EXIT
+ NEVER RETURNS - Thread Exits
+
+--*/
+
+DWORD W32Thread(LPVOID vpInitialSSSP)
+{
+ TD td;
+ UNICODE_STRING uImageName;
+ WCHAR wcImageName[MAX_VDMFILENAME];
+ RTL_PERTHREAD_CURDIR rptc;
+ PVDMFRAME pFrame;
+ PWOWINITTASK16 pArg16;
+ PTDB ptdb;
+#if FASTBOPPING
+#else
+ USHORT SaveIp;
+#endif
+
+ td.hThread = NULL;
+
+
+ if (gptdShell == NULL) {
+
+ //
+ // This is the initial thread, free the temporary TD we used during
+ // boot.
+ //
+
+ free_w( (PVOID) CURRENTPTD() );
+ gptdShell = &td;
+
+ } else if (pptdWOA) {
+
+ //
+ // See WK32ILoadModule32
+ //
+
+ *pptdWOA = &td;
+ pptdWOA = NULL;
+ }
+
+ CURRENTPTD() = &td;
+
+ td.dwFlags = TDF_INITCALLBACKSTACK;
+ if (fBoot) {
+ td.htask16 = 0;
+ td.hInst16 = 0;
+ td.hMod16 = 0;
+
+ {
+ VPVOID vpStack;
+
+#if FASTBOPPING
+ vpStack = FASTVDMSTACK();
+#else
+ vpStack = VDMSTACK();
+#endif
+
+ GETFRAMEPTR(vpStack, pFrame);
+
+ pFrame->wAX = 1;
+
+ }
+
+#if FASTBOPPING
+ CurrentMonitorTeb = NtCurrentTeb();
+ FastWOWCallbackCall();
+#else
+ SaveIp = getIP();
+ host_simulate();
+ setIP(SaveIp);
+#endif
+
+ }
+
+ //
+ // Initialize Per Task Data
+ //
+
+ GETFRAMEPTR((VPVOID)vpInitialSSSP, pFrame);
+ td.htask16 = pFrame->wTDB;
+ ptdb = (PTDB)SEGPTR(td.htask16,0);
+ td.VDMInfoiTaskID = iW32ExecTaskId;
+ iW32ExecTaskId = (UINT)-1;
+ td.vpStack = (VPVOID)vpInitialSSSP;
+ td.dwThreadID = GetCurrentThreadId();
+ if (THREADID32(td.htask16) == 0) {
+ ptdb->TDB_ThreadID = td.dwThreadID;
+ }
+
+ td.CommDlgTd = NULL;
+ EnterCriticalSection(&gcsWOW);
+ td.ptdNext = gptdTaskHead;
+ gptdTaskHead = &td;
+ LeaveCriticalSection(&gcsWOW);
+ td.hrgnClip = (HRGN)NULL;
+
+ td.ulLastDesktophDC = 0;
+ td.pWOAList = NULL;
+
+ //
+ // NOTE - Add YOUR Per Task Init Code HERE
+ //
+
+ //
+ // Initialize WOW compatibility flags from registry.
+ //
+
+ td.dwWOWCompatFlags = W32ReadWOWCompatFlags(td.htask16, &td.dwWOWCompatFlagsEx);
+
+//
+// We now inherit the WOW compatibility flags from the parent's TDB. Right
+// now We are only interested in inheriting the WOWCF_UNIQUEHDCHWND flag
+// in order to really fix a bug with MS Publisher. Each Wizard and Cue Cards
+// that ship with mspub is its own task and would require MANY new
+// compatibility flag entries in the registry. This mechanism allows anything
+// spawned from an app that has WOWCF_UNIQUEHDCHWND to have
+// WOWCF_UNIQUEHDCHWND.
+ if (ptdb->TDB_WOWCompatFlags & LOWORD(WOWCF_UNIQUEHDCHWND)) {
+ td.dwWOWCompatFlags |= LOWORD(WOWCF_UNIQUEHDCHWND);
+ }
+
+ ptdb->TDB_WOWCompatFlags = LOWORD(td.dwWOWCompatFlags);
+ ptdb->TDB_WOWCompatFlags2 = HIWORD(td.dwWOWCompatFlags);
+ ptdb->TDB_WOWCompatFlagsEx = LOWORD(td.dwWOWCompatFlagsEx);
+ ptdb->TDB_WOWCompatFlagsEx2 = HIWORD(td.dwWOWCompatFlagsEx);
+
+#ifndef i386
+ // Enable the special VDMAllocateVirtualMemory strategy in NTVDM.
+ if (td.dwWOWCompatFlagsEx & WOWCFEX_FORCEINCDPMI) {
+ SetWOWforceIncrAlloc(TRUE);
+ }
+#endif
+
+ td.hIdleHook = NULL;
+
+ //
+ // Set the CSR batching limit to whatever was specified in
+ // win.ini [WOW] BatchLimit= line, which we read into
+ // dwWOWBatchLimit during WOW startup in W32Init.
+ //
+ // This code allows the performance people to benchmark
+ // WOW on an API for API basis without having to use
+ // a private CSRSRV.DLL with a hardcoded batch limit of 1.
+ //
+ // Note: This is a per-thread attribute, so we must call
+ // ==== GdiSetBatchLimit during the initialization of
+ // each thread that could call GDI on behalf of
+ // 16-bit code.
+ //
+
+ if (dwWOWBatchLimit) {
+
+ DWORD dwOldBatchLimit;
+
+ dwOldBatchLimit = GdiSetBatchLimit(dwWOWBatchLimit);
+
+ LOGDEBUG(LOG_ALWAYS,("WOW W32Thread: Changed thread %d GDI batch limit from %u to %u.\n",
+ nWOWTasks+1, dwOldBatchLimit, dwWOWBatchLimit));
+ }
+
+
+ nWOWTasks++;
+
+
+ //
+ // Inittask: requires ExpWinVer and Modulename
+ //
+
+ {
+ DWORD dwExpWinVer;
+ BYTE lpFileName[9]; // modname = 8bytes + nullchar
+ CHAR szFilePath[256];
+ LPBYTE lpModule;
+ PWOWINITTASK16 pArg16;
+ PTDB ptdb;
+ WORD wPathOffset;
+ BYTE bImageNameLength;
+ ULONG ulLength;
+ BOOL bRet;
+ DWORD dw;
+ HANDLE hThread;
+
+ GETARGPTR(pFrame, sizeof(WOWINITTASK16), pArg16);
+ ptdb = (PTDB)SEGPTR(td.htask16,0);
+ td.hInst16 = ptdb->TDB_Module;
+ td.hMod16 = ptdb->TDB_pModule;
+ hThread = (HANDLE)ptdb->TDB_hThread;
+ dwExpWinVer = FETCHDWORD(pArg16->dwExpWinVer);
+ RtlCopyMemory(lpFileName, ptdb->TDB_ModName, 8);
+ FREEVDMPTR(ptdb);
+ lpFileName[8] = (BYTE)0;
+
+#define NE_PATHOFFSET 10 // Offset to file path stuff
+
+ dw = MAKELONG(0,td.hMod16);
+ GETMISCPTR( dw, lpModule );
+
+ wPathOffset = *((LPWORD)(lpModule+NE_PATHOFFSET));
+
+ bImageNameLength = *(lpModule+wPathOffset);
+
+ bImageNameLength -= 8; // 7 bytes of trash at the start
+ wPathOffset += 8;
+
+ RtlCopyMemory(szFilePath, lpModule + wPathOffset, bImageNameLength);
+ szFilePath[bImageNameLength] = 0;
+
+ RtlMultiByteToUnicodeN( wcImageName,
+ sizeof(wcImageName),
+ &ulLength,
+ szFilePath,
+ bImageNameLength );
+
+ RtlInitUnicodeString(&uImageName, wcImageName);
+
+ LOGDEBUG(2,("WOW W32Thread: setting image name to %ws\n",
+ uImageName.Buffer));
+
+ RtlAssociatePerThreadCurdir( &rptc, NULL, &uImageName, NULL );
+
+ FREEMISCPTR( lpModule );
+
+ //
+ // Add this task to the list of 16-bit tasks
+ //
+
+ AddTaskSharedList(td.htask16, td.hMod16, lpFileName, szFilePath);
+
+ // At this point we know both the module and the filename,
+ // check that against known setup names
+
+ if (W32IsSetupProgram(lpFileName, szFilePath)) {
+ LOGDEBUG(2, ("Running known setup program %s\n", szFilePath));
+ td.dwFlags |= TDF_SETUPAPPLICATION;
+ }
+
+
+ // Init task forces us to the active task in USER
+ // and does ShowStartGlass, so new app gets focus correctly
+ dw = 0;
+ do {
+ if (dw) {
+ Sleep(dw * 50);
+ }
+
+ bRet = (pfnOut.pfnInitTask)(dwExpWinVer,
+ lpFileName,
+ td.htask16,
+ dwLastHotkey,
+ fSeparateWow ? 0 : td.VDMInfoiTaskID,
+ dwLastX,
+ dwLastY,
+ dwLastXSize,
+ dwLastYSize,
+ SW_SHOW /* unused */
+ );
+ } while (dw++ < 6 && !bRet);
+
+
+ if (!bRet) {
+ LOGDEBUG(LOG_ALWAYS,
+ ("\n%04X task, PTD address %08X InitTaskFailed\n",
+ td.htask16,
+ &td)
+ );
+
+ W32DestroyTask(&td);
+ host_ExitThread(EXIT_FAILURE);
+ }
+
+
+ dwLastHotkey = 0;
+ dwLastX = dwLastY = dwLastXSize = dwLastYSize = (DWORD) CW_USEDEFAULT;
+
+ if (fBoot) {
+
+ fBoot = FALSE;
+
+ //
+ // This call needs to happen after WOWExec's InitTask call so that
+ // USER sees us as expecting Windows version 3.10 -- otherwise they
+ // will fail some of the LoadCursor calls.
+ //
+
+ InitStdCursorIconAlias();
+
+ } else {
+
+ //
+ // Syncronize the new thread with the creator thread.
+ // Wake our creator thread
+ //
+
+ WOW32VERIFY(SetEvent(ghevWaitCreatorThread));
+ }
+
+ td.hThread = hThread;
+ LOGDEBUG(2,("WOW W32Thread: New thread ready for execution\n"));
+
+ // turn the timer thread on if its not for the first task
+ // which we presume to be wowexec
+ if (nWOWTasks != 1) {
+ ResumeTimerThread();
+ }
+
+ FREEARGPTR(pArg16);
+ }
+
+ FREEVDMPTR(pFrame);
+ GETFRAMEPTR((VPVOID)vpInitialSSSP, pFrame);
+ WOW32ASSERT(pFrame->wTDB == td.htask16);
+
+#if FASTBOPPING
+ SETFASTVDMSTACK((VPVOID)vpInitialSSSP);
+#else
+ SETVDMSTACK(vpInitialSSSP);
+#endif
+ pFrame->wRetID = RET_RETURN;
+
+
+ //
+ // Let user set breakpoints before Starting App
+ //
+
+ if ( IsDebuggerAttached() ) {
+
+ GETARGPTR(pFrame, sizeof(WOWINITTASK16), pArg16);
+ DBGNotifyNewTask((LPVOID)pArg16, OFFSETOF(VDMFRAME,bArgs) );
+ FREEARGPTR(pArg16);
+
+ if (flOptions & OPT_BREAKONNEWTASK) {
+
+ LOGDEBUG(
+ LOG_ALWAYS,
+ ("\n%04X %08X task is starting, PTD address %08X, type g to continue\n\n",
+ td.htask16,
+ pFrame->vpCSIP,
+ &td));
+
+ DebugBreak();
+ }
+ }
+
+
+ //
+ // Start APP
+ //
+ BlockWOWIdle(FALSE);
+
+#ifdef DEBUG
+ // BUGBUG: HACK ALERT
+ // This code has been added to aid in debugging a problem that only
+ // seems to occur on MIPS chk
+ // What appears to be happening is that the SS:SP is set correctly
+ // above, but sometime later, perhaps during the "BlockWOWIdle" call,
+ // the emulator's flat stack pointer ends up getting reset to WOWEXEC's
+ // stack. The SETVDMSTACK call below will reset the values we want so
+ // that the user can continue normally.
+ WOW32ASSERTMSG(LOWORD(vpInitialSSSP)==getSP(), "WOW32: W32Thread Error - SP is invalid!\n");
+ SETVDMSTACK(vpInitialSSSP);
+#endif
+
+#if NO_W32TRYCALL
+ {
+ extern INT W32FilterException(INT, PEXCEPTION_POINTERS);
+ }
+ try {
+#endif
+#if FASTBOPPING
+ CurrentMonitorTeb = NtCurrentTeb();
+ FastWOWCallbackCall();
+#else
+ SaveIp = getIP();
+ host_simulate();
+ setIP(SaveIp);
+#endif
+#if NO_W32TRYCALL
+ } except (W32FilterException(GetExceptionCode(),
+ GetExceptionInformation())) {
+ }
+#endif
+ //
+ // We should Never Come Here, an app should get terminated via calling wk32killtask thunk
+ // not by doing an unsimulate call.
+ //
+
+#ifdef DEBUG
+ WOW32ASSERTMSG(FALSE, "WOW32: W32Thread Error - Too many unsimulate calls\n");
+#else
+ if (IsDebuggerAttached() && (flOptions & OPT_DEBUG)) {
+ DbgBreakPoint();
+ }
+#endif
+
+ W32DestroyTask(&td);
+ host_ExitThread(EXIT_SUCCESS);
+ return 0;
+}
+
+
+/* WK32KillTask - Force the Distruction of the Current Thread
+ *
+ * Called When App Does an Exit
+ * If there is another active Win16 app then USER32 will schedule another
+ * task.
+ *
+ * ENTRY
+ *
+ * EXIT
+ * Never Returns - We kill the process
+ *
+ */
+
+VOID FASTCALL WK32KillTask(PVDMFRAME pFrame)
+{
+ UNREFERENCED_PARAMETER(pFrame);
+
+ CURRENTPTD()->dwFlags &= ~TDF_FORCETASKEXIT;
+ W32DestroyTask(CURRENTPTD());
+ RemoveTaskSharedList();
+ host_ExitThread(EXIT_SUCCESS);
+}
+
+
+/*++
+
+ W32RemoteThread - New Remote Thread Starts Here
+
+ Routine Description:
+
+ The debugger needs to be able to call back into 16-bit code to
+ execute some toolhelp functions. This function is provided as a remote
+ interface to calling 16-bit functions.
+
+ ENTRY
+ 16:16 to New Task Stack
+
+ EXIT
+ NEVER RETURNS - Thread Exits
+
+--*/
+
+VDMCONTEXT vcRemote;
+VDMCONTEXT vcSave;
+VPVOID vpRemoteBlock = (DWORD)0;
+WORD wPrevTDB = 0;
+DWORD dwPrevEBP = 0;
+
+DWORD W32RemoteThread(VOID)
+{
+ TD td;
+ PVDMFRAME pFrame;
+ HANDLE hThread;
+ NTSTATUS Status;
+ THREAD_BASIC_INFORMATION ThreadInfo;
+ OBJECT_ATTRIBUTES obja;
+ VPVOID vpStack;
+
+ // turn the timer thread off to resync dos time
+ if (nWOWTasks != 1)
+ SuspendTimerThread();
+
+ Status = NtQueryInformationThread(
+ NtCurrentThread(),
+ ThreadBasicInformation,
+ (PVOID)&ThreadInfo,
+ sizeof(THREAD_BASIC_INFORMATION),
+ NULL
+ );
+ if ( !NT_SUCCESS(Status) ) {
+#if DBG
+ DbgPrint("NTVDM: Could not get thread information\n");
+ DbgBreakPoint();
+#endif
+ return( 0 );
+ }
+
+ InitializeObjectAttributes(
+ &obja,
+ NULL,
+ 0,
+ NULL,
+ 0 );
+
+
+ Status = NtOpenThread(
+ &hThread,
+ THREAD_SET_CONTEXT
+ | THREAD_GET_CONTEXT
+ | THREAD_QUERY_INFORMATION,
+ &obja,
+ &ThreadInfo.ClientId );
+
+ if ( !NT_SUCCESS(Status) ) {
+#if DBG
+ DbgPrint("NTVDM: Could not get open thread handle\n");
+ DbgBreakPoint();
+#endif
+ return( 0 );
+ }
+
+ cpu_createthread( hThread );
+
+ Status = NtClose( hThread );
+ if ( !NT_SUCCESS(Status) ) {
+#if DBG
+ DbgPrint("NTVDM: Could not close thread handle\n");
+ DbgBreakPoint();
+#endif
+ return( 0 );
+ }
+
+ CURRENTPTD() = &td;
+
+ //
+ // Save the current state (for future callbacks)
+ //
+ vcSave.SegSs = getSS();
+ vcSave.SegCs = getCS();
+ vcSave.SegDs = getDS();
+ vcSave.SegEs = getES();
+ vcSave.Eax = getAX();
+ vcSave.Ebx = getBX();
+ vcSave.Ecx = getCX();
+ vcSave.Edx = getDX();
+ vcSave.Esi = getSI();
+ vcSave.Edi = getDI();
+ vcSave.Ebp = getBP();
+ vcSave.Eip = getIP();
+ vcSave.Esp = getSP();
+#if FASTBOPPING
+ {
+ extern DWORD saveebp32;
+
+ dwPrevEBP = saveebp32;
+ }
+#endif
+
+ wPrevTDB = *pCurTDB;
+
+ td.dwFlags = TDF_INITCALLBACKSTACK;
+
+ //
+ // Now prepare for the callback. Set the registers such that it looks
+ // like we are returning from the WOWKillRemoteTask call.
+ //
+ setDS( (WORD)vcRemote.SegDs );
+ setES( (WORD)vcRemote.SegEs );
+ setAX( (WORD)vcRemote.Eax );
+ setBX( (WORD)vcRemote.Ebx );
+ setCX( (WORD)vcRemote.Ecx );
+ setDX( (WORD)vcRemote.Edx );
+ setSI( (WORD)vcRemote.Esi );
+ setDI( (WORD)vcRemote.Edi );
+ setBP( (WORD)vcRemote.Ebp );
+#if FASTBOPPING
+
+ vpStack = MAKELONG( LOWORD(vcRemote.Esp), LOWORD(vcRemote.SegSs) );
+
+ SETFASTVDMSTACK( vpStack );
+
+#else
+ setIP( (WORD)vcRemote.Eip );
+ setSP( (WORD)vcRemote.Esp );
+ setSS( (WORD)vcRemote.SegSs );
+ setCS( (WORD)vcRemote.SegCs );
+ vpStack = VDMSTACK();
+#endif
+
+ //
+ // Initialize Per Task Data
+ //
+ GETFRAMEPTR(vpStack, pFrame);
+
+ td.htask16 = pFrame->wTDB;
+ td.VDMInfoiTaskID = -1;
+ td.vpStack = vpStack;
+ td.pWOAList = NULL;
+
+ //
+ // NOTE - Add YOUR Per Task Init Code HERE
+ //
+
+ nWOWTasks++;
+
+ // turn the timer thread on
+ if (nWOWTasks != 1)
+ ResumeTimerThread();
+
+
+ pFrame->wRetID = RET_RETURN;
+
+ pFrame->wAX = (WORD)TRUE;
+ pFrame->wDX = (WORD)0;
+
+ //
+ // Start Callback
+ //
+#if FASTBOPPING
+ CurrentMonitorTeb = NtCurrentTeb();
+ FastWOWCallbackCall();
+#else
+ host_simulate();
+ setIP((WORD)vcSave.Eip);
+#endif
+
+ //
+ // We should Never Come Here, an app should get terminated via calling wk32killtask thunk
+ // not by doing an unsimulate call.
+ //
+
+#ifdef DEBUG
+ WOW32ASSERTMSG(FALSE, "WOW32: W32RemoteThread Error - Too many unsimulate calls");
+#else
+ if (IsDebuggerAttached() && (flOptions & OPT_DEBUG)) {
+ DbgBreakPoint();
+ }
+#endif
+
+ W32DestroyTask(&td);
+ host_ExitThread(EXIT_SUCCESS);
+ return 0;
+}
+
+/* W32FreeTask - Per Task Cleanup
+ *
+ * Put any 16-bit task clean-up code here. The remote thread for debugging
+ * is a 16-bit task, but has no real 32-bit thread associated with it, until
+ * the debugger creates it. Then it is created and destroyed in special
+ * ways, see W32RemoteThread and W32KillRemoteThread.
+ *
+ * ENTRY
+ * Per Task Pointer
+ *
+ * EXIT
+ * None
+ *
+ */
+VOID W32FreeTask( PTD ptd )
+{
+ PWOAINST pWOA, pWOANext;
+
+ nWOWTasks--;
+
+ if (nWOWTasks < 2)
+ SuspendTimerThread();
+
+#ifndef i386
+ // Disable the special VDMAllocateVirtualMemory strategy in NTVDM.
+ if (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_FORCEINCDPMI) {
+ SetWOWforceIncrAlloc(FALSE);
+ }
+#endif
+
+ // Free all DCs owned by the current task
+
+ FreeCachedDCs(ptd->htask16);
+
+ // Unload network fonts
+
+ if( CURRENTPTD()->dwWOWCompatFlags & WOWCF_UNLOADNETFONTS )
+ {
+ UnloadNetworkFonts( (UINT)CURRENTPTD() );
+ }
+
+ // Free all timers owned by the current task
+
+ DestroyTimers16(ptd->htask16);
+
+ // clean up comm support
+
+ FreeCommSupportResources(ptd->dwThreadID);
+
+ // remove the hacks for this task from the FormFeedHackList (see wgdi.c)
+ FreeTaskFormFeedHacks(ptd->htask16);
+
+ // Cleanup WinSock support.
+
+ if (WWS32IsThreadInitialized) {
+ WWS32TaskCleanup();
+ }
+
+ // Free all local resource info owned by the current task
+
+ DestroyRes16(ptd->htask16);
+
+ // Unhook all hooks and reset their state.
+
+ W32FreeOwnedHooks(ptd->htask16);
+
+ // Free all the resources of this task
+
+ FreeCursorIconAlias(ptd->htask16,CIALIAS_HTASK | CIALIAS_TASKISGONE);
+
+ // Free accelerator aliases
+
+ DestroyAccelAlias(ptd->htask16);
+
+ // Remove idle hook, if any has been installed.
+
+ if (ptd->hIdleHook != NULL) {
+ UnhookWindowsHookEx(ptd->hIdleHook);
+ ptd->hIdleHook = NULL;
+ }
+
+ // Free Special thunking list for this task (wparam.c)
+
+ FreeParamMap(ptd->htask16);
+
+ // Free WinOldAp tracking structures for this thread.
+
+ pWOA = ptd->pWOAList;
+ while (pWOA) {
+ pWOANext = pWOA->pNext;
+ free_w(pWOA);
+ pWOA = pWOANext;
+ }
+
+ // if this was a setup application - notify shell to resync win.ini
+ // with registry settings
+
+ if (ptd->dwFlags & TDF_SETUPAPPLICATION) {
+ HWND hwndShell = GetShellWindow();
+
+ LOGDEBUG(2, ("Setup Application is done, notifying shell\n"));
+
+ if (hwndShell) {
+ SendMessage(hwndShell, WM_WININICHANGE, 0, (LPARAM)(LPVOID)szExtensions);
+ }
+ }
+}
+
+
+
+/* WK32KillRemoteTask - Force the Distruction of the Current Thread
+ *
+ * Called When App Does an Exit
+ * If there is another active Win16 app then USER32 will schedule another
+ * task.
+ *
+ * ENTRY
+ *
+ * EXIT
+ * Never Returns - We kill the process
+ *
+ */
+
+VOID FASTCALL WK32KillRemoteTask(PVDMFRAME pFrame)
+{
+ PWOWKILLREMOTETASK16 pArg16;
+ WORD wSavedTDB;
+ PTD ptd = CURRENTPTD();
+ LPBYTE lpNum_Tasks;
+
+ //
+ // Save the current state (for future callbacks)
+ //
+ vcRemote.SegDs = getDS();
+ vcRemote.SegEs = getES();
+ vcRemote.Eax = getAX();
+ vcRemote.Ebx = getBX();
+ vcRemote.Ecx = getCX();
+ vcRemote.Edx = getDX();
+ vcRemote.Esi = getSI();
+ vcRemote.Edi = getDI();
+ vcRemote.Ebp = getBP();
+#if FASTBOPPING
+ {
+ extern DWORD saveip16;
+ extern DWORD savecs16;
+ VPVOID vpStack;
+
+ vcRemote.Eip = saveip16;
+ vcRemote.SegCs = savecs16;
+ vpStack = FASTVDMSTACK();
+
+ vcRemote.SegSs = HIWORD(vpStack);
+ vcRemote.Esp = LOWORD(vpStack);
+ }
+#else
+ vcRemote.Eip = getIP();
+ vcRemote.Esp = getSP();
+ vcRemote.SegSs = getSS();
+ vcRemote.SegCs = getCS();
+#endif
+
+ W32FreeTask(CURRENTPTD());
+
+ if ( vpRemoteBlock ) {
+
+ wSavedTDB = ptd->htask16;
+ ptd->htask16 = wPrevTDB;
+ pFrame->wTDB = wPrevTDB;
+
+ // This is a nop callback just to make sure that we switch tasks
+ // back for the one we were on originally.
+ GlobalUnlockFree16( 0 );
+
+ GETFRAMEPTR(ptd->vpStack, pFrame);
+
+ pFrame->wTDB = ptd->htask16 = wSavedTDB;
+
+ //
+ // We must be returning from a callback, restore the previous
+ // context info. Don't worry about flags, they aren't needed.
+ //
+ setSS( (WORD)vcSave.SegSs );
+ setCS( (WORD)vcSave.SegCs );
+ setDS( (WORD)vcSave.SegDs );
+ setES( (WORD)vcSave.SegEs );
+ setAX( (WORD)vcSave.Eax );
+ setBX( (WORD)vcSave.Ebx );
+ setCX( (WORD)vcSave.Ecx );
+ setDX( (WORD)vcSave.Edx );
+ setSI( (WORD)vcSave.Esi );
+ setDI( (WORD)vcSave.Edi );
+ setBP( (WORD)vcSave.Ebp );
+ setIP( (WORD)vcSave.Eip );
+ setSP( (WORD)vcSave.Esp );
+#if FASTBOPPING
+ {
+ extern DWORD saveebp32;
+
+ saveebp32 = dwPrevEBP;
+ }
+#endif
+ } else {
+ //
+ // Decrement the count of 16-bit tasks so that the last one,
+ // excluding the remote handler (WOWDEB.EXE) will remember to
+ // call ExitKernel when done.
+ //
+ GETVDMPTR(vpnum_tasks, 1, lpNum_Tasks);
+
+ *lpNum_Tasks -= 1;
+
+ FREEVDMPTR(lpNum_Tasks);
+
+ //
+ // Remove this 32-bit thread from the list of tasks as well.
+ //
+ WK32DeleteTask( CURRENTPTD() );
+ }
+
+ GETARGPTR(pFrame, sizeof(WOWKILLREMOTETASK16), pArg16);
+
+ //
+ // Save the current state (for future callbacks)
+ //
+ vpRemoteBlock = FETCHDWORD(pArg16->lpBuffer);
+
+ // Notify DBG that we have a remote thread address
+ DBGNotifyRemoteThreadAddress( W32RemoteThread, vpRemoteBlock );
+
+ FREEARGPTR(pArg16);
+
+ host_ExitThread(EXIT_SUCCESS);
+}
+
+
+/* W32DestroyTask - Per Task Cleanup
+ *
+ * Task destruction code here. Put any 32-bit task cleanup code here
+ *
+ * ENTRY
+ * Per Task Pointer
+ *
+ * EXIT
+ * None
+ *
+ */
+
+VOID W32DestroyTask( PTD ptd)
+{
+
+ LOGDEBUG(LOG_IMPORTANT,("W32DestroyTask: destroying task %04X\n", ptd->htask16));
+
+ // Inform Hung App Support
+
+ SetEvent(ghevWaitHungAppNotifyThread);
+
+ // Free all information pertinant to this 32-bit thread
+ W32FreeTask( ptd );
+
+ // delete the cliprgn used by GetClipRgn if it exists
+
+ if (ptd->hrgnClip != NULL)
+ {
+ DeleteObject(ptd->hrgnClip);
+ ptd->hrgnClip = NULL;
+ }
+
+ // Report task termination to Win32 - incase someone is waiting for us
+ // LATER - fix Win32 so we don't have to report it.
+
+
+ if (nWOWTasks == 0) { // If we're the last one out, turn out the lights & tell Win32 WOWVDM is history.
+ ptd->VDMInfoiTaskID = -1;
+ ExitVDM(WOWVDM, ALL_TASKS); // Tell Win32 All Tasks are gone.
+ }
+ else if (ptd->VDMInfoiTaskID != -1 ) { // If 32 bit app is waiting for us - then signal we are done
+ ExitVDM(WOWVDM, ptd->VDMInfoiTaskID);
+ }
+ ptd->dwFlags &= ~TDF_IGNOREINPUT;
+
+ if (!(ptd->dwFlags & TDF_TASKCLEANUPDONE)) {
+ (pfnOut.pfnWOWCleanup)(HINSTRES32(ptd->hInst16), (DWORD) ptd->htask16, NULL, 0);
+ }
+
+
+ // Remove this task from the linked list of tasks
+
+ WK32DeleteTask(ptd);
+
+ // Close This Apps Thread Handle
+
+ if (ptd->hThread)
+ CloseHandle( ptd->hThread );
+
+}
+
+/***************************************************************************\
+* WK32DeleteTask
+*
+* This function removes a task from the task list.
+*
+* History:
+* Borrowed From User32 taskman.c - mattfe aug 5 92
+\***************************************************************************/
+
+void WK32DeleteTask(
+ PTD ptdDelete)
+{
+ PTD ptd, ptdPrev;
+
+ EnterCriticalSection(&gcsWOW);
+ ptd = gptdTaskHead;
+ ptdPrev = NULL;
+
+ /*
+ * Find the task to delete
+ */
+ while ((ptd != NULL) && (ptd != ptdDelete)) {
+ ptdPrev = ptd;
+ ptd = ptd->ptdNext;
+ }
+
+ /*
+ * Error if we didn't find it. If we did find it, remove it
+ * from the chain. If this was the head of the list, set it
+ * to point to our next guy.
+ */
+ if (ptd == NULL) {
+ LOGDEBUG(LOG_ALWAYS,("WK32DeleteTask:Task not found.\n"));
+ } else if (ptdPrev != NULL) {
+ ptdPrev->ptdNext = ptd->ptdNext;
+ } else {
+ gptdTaskHead = ptd->ptdNext;
+ }
+ LeaveCriticalSection(&gcsWOW);
+}
+
+
+/*++
+ WK32RegisterShellWindowHandle - 16 Bit Shell Registers is Hanle
+
+ Routine Description:
+ This routines saves the 32 bit hwnd for the 16 bit shell
+
+ When WOWEXEC (16 bit shell) has sucessfully created its window it calls us to
+ register its window handle. If this is the shared WOW VDM, we register the
+ handle with BaseSrv, which posts WM_WOWEXECSTARTAPP messages when Win16 apps
+ are started.
+
+ ENTRY
+ pFrame -> hwndShell, 16 bit hwnd for shell (WOWEXEC)
+
+ EXIT
+ TRUE - This is the shared WOW VDM
+ FALSE - This is a separate WOW VDM
+
+--*/
+
+ULONG FASTCALL WK32RegisterShellWindowHandle(PVDMFRAME pFrame)
+{
+ register PWOWREGISTERSHELLWINDOWHANDLE16 parg16;
+ WNDCLASS wc;
+
+ GETARGPTR(pFrame, sizeof(WOWREGISTERSHELLWINDOWHANDLE16), parg16);
+
+// gwFirstCmdShow is no longer used, and is available.
+#if 0
+ GETVDMPTR(parg16->lpwCmdShow, sizeof(WORD), pwCmdShow);
+#endif
+
+ ghwndShell = HWND32(parg16->hwndShell);
+ ghShellTDB = pFrame->wTDB;
+
+ //
+ // Save away the hInstance for User32
+ //
+
+ GetClassInfo(0, (LPCSTR)0x8000, &wc);
+ ghInstanceUser32 = wc.hInstance;
+
+ // Fritz, when you get called about this it means that the GetClassInfo()
+ // call above is returning with lpWC->hInstance == 0 instead of hModuser32.
+ WOW32ASSERTMSGF((ghInstanceUser32),
+ ("WOW Error ghInstanceUser32 == NULL! Call FritzS\n"));
+
+ //
+ // If this is the shared WOW VDM, register the WowExec window handle
+ // with BaseSrv so it can post WM_WOWEXECSTARTAPP messages.
+ //
+
+ if (!fSeparateWow) {
+ RegisterWowExec(ghwndShell);
+ }
+
+ WOW32FaxHandler(WM_DDRV_SUBCLASS, (LPSTR)(HWND32(parg16->hwndFax)));
+
+ FREEARGPTR(parg16);
+
+
+ //
+ // Return value is TRUE if this is the shared WOW VDM,
+ // FALSE if this is a separate WOW VDM.
+ //
+
+ return fSeparateWow ? FALSE : TRUE;
+}
+
+
+//
+// Worker routine for WK32LoadModule32
+//
+
+VOID FASTCALL CleanupWOAList(HANDLE hProcess)
+{
+ PTD ptd;
+ PWOAINST *ppWOA, pWOAToFree;
+
+ ptd = gptdTaskHead;
+
+ while (ptd) {
+
+ ppWOA = &(ptd->pWOAList);
+ while (*ppWOA && (*ppWOA)->hChildProcess != hProcess) {
+ ppWOA = &( (*ppWOA)->pNext );
+ }
+
+ if (*ppWOA) {
+
+ //
+ // We found the WOAINST structure to clean up.
+ //
+
+ pWOAToFree = *ppWOA;
+
+ //
+ // Remove this entry from the list
+ //
+
+ *ppWOA = pWOAToFree->pNext;
+
+ free_w(pWOAToFree);
+
+ return;
+
+ }
+
+ ptd = ptd->ptdNext;
+ }
+}
+
+
+/*++
+ WK32LoadModule32
+
+ Routine Description:
+ Exec a 32 bit Process
+ This routine is called by the 16 bit kernel when it fails to load a 16 bit task
+ with error codes 11 - invalid exe, 12 - os2, 13 - DOS 4.0, 14 - Unknown.
+
+ ENTRY
+ pFrame -> lpCmdLine Input\output buffer for winoldapp cmd line
+ pFrame -> lpParameterBlock (see win 3.x apis) Parameter Block if NULL
+ winoldap calling
+ pFrame -> lpModuleName (see win 3.x apis) App Name
+
+ EXIT
+ 32 - Sucess
+ Error code
+
+ History:
+ rewrote to call CreateProcess() instead of LoadModule - barryb 29sep92
+
+--*/
+
+
+ULONG FASTCALL WK32LoadModule32(PVDMFRAME pFrame)
+{
+ static PSZ pszExplorerFullPathUpper = NULL; // "C:\WINNT\EXPLORER.EXE"
+
+ ULONG ulRet;
+ int i;
+ char *pch, *pSrc;
+ PSZ pszModuleName;
+ PSZ pszWinOldAppCmd;
+ PBYTE pbCmdLine;
+ BOOL CreateProcessStatus;
+ PPARAMETERBLOCK16 pParmBlock16;
+ PWORD16 pCmdShow = NULL;
+ BOOL fProgman = FALSE;
+ PROCESS_INFORMATION ProcessInformation;
+ STARTUPINFO StartupInfo;
+ char CmdLine[2*MAX_PATH];
+ register PWOWLOADMODULE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(WOWLOADMODULE16), parg16);
+ GETPSZPTR(parg16->lpWinOldAppCmd, pszWinOldAppCmd);
+ if (parg16->lpParameterBlock) {
+ GETVDMPTR(parg16->lpParameterBlock,sizeof(PARAMETERBLOCK16), pParmBlock16);
+ GETPSZPTR(pParmBlock16->lpCmdLine, pbCmdLine);
+ } else {
+ pParmBlock16 = NULL;
+ pbCmdLine = NULL;
+ }
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT); // update current dir
+
+
+ /*
+ * if ModuleName == NULL, called by winoldap, or LM_NTLOADMODULE
+ * to deal with the process handle.
+ *
+ * if lpParameterBlock == NULL
+ * winoldap calling to wait on the process handle
+ * else
+ * LM_NTLoadModule calling to clean up process handle
+ * because an error ocurred loading winoldap.
+ */
+ if (!parg16->lpModuleName) {
+ HANDLE hProcess;
+ MSG msg;
+
+ pszModuleName = NULL;
+
+ if (pszWinOldAppCmd &&
+ *pszWinOldAppCmd &&
+ RtlEqualMemory(pszWinOldAppCmd, szWOAWOW32, sizeof(szWOAWOW32)-1))
+ {
+ hProcess = (HANDLE)strtoul(pszWinOldAppCmd + sizeof(szWOAWOW32) - 1,
+ NULL,
+ 16
+ );
+ if (hProcess == (HANDLE)-1) { // ULONG_MAX
+ hProcess = NULL;
+ }
+
+ if (parg16->lpParameterBlock && hProcess) {
+
+ //
+ // Error loading winoldap.mod
+ //
+
+ pptdWOA = NULL;
+ CleanupWOAList(hProcess);
+ CloseHandle(hProcess);
+ hProcess = NULL;
+ }
+ } else {
+ hProcess = NULL;
+ }
+
+ BlockWOWIdle(TRUE);
+
+ if (hProcess) {
+ while (MsgWaitForMultipleObjects(1, &hProcess, FALSE, INFINITE, QS_ALLINPUT)
+ == WAIT_OBJECT_0 + 1)
+ {
+ PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE);
+ }
+
+ if (!GetExitCodeProcess(hProcess, &ulRet)) {
+ ulRet = 0;
+ }
+
+ CleanupWOAList(hProcess);
+ CloseHandle(hProcess);
+ } else {
+ (pfnOut.pfnYieldTask)();
+ ulRet = 0;
+ }
+
+ BlockWOWIdle(FALSE);
+
+ goto lm32Exit;
+
+
+ /*
+ * if ModuleName == -1, uses traditional style winoldap cmdline
+ * and is called to spawn a non win16 app.
+ *
+ * "<cbWord><CmdLineParameters>CR<ModulePathName>LF"
+ *
+ * Extract the ModuleName from the command line
+ *
+ */
+ } else if (parg16->lpModuleName == -1) {
+ pszModuleName = NULL;
+
+ pSrc = pbCmdLine + 2;
+ pch = strchr(pSrc, '\r');
+ if (!pch || (i = pch - pSrc) >= MAX_PATH) {
+ ulRet = 23;
+ goto lm32Exit;
+ }
+
+ pSrc = pch + 1;
+ pch = strchr(pSrc, '\n');
+ if (!pch || (i = pch - pSrc) >= MAX_PATH) {
+ ulRet = 23;
+ goto lm32Exit;
+ }
+
+ pch = CmdLine;
+ while (*pSrc != '\n' && *pSrc) {
+ *pch++ = *pSrc++;
+ }
+ *pch++ = ' ';
+
+
+ pSrc = pbCmdLine + 2;
+ while (*pSrc != '\r' && *pSrc) {
+ *pch++ = *pSrc++;
+ }
+ *pch = '\0';
+
+ /*
+ * lpModuleName contains Application Path Name
+ * pbCmdLIne contains Command Tail
+ */
+ } else {
+ GETPSZPTR(parg16->lpModuleName, pszModuleName);
+ if (pszModuleName) {
+ //
+ // 2nd part of control.exe/progman.exe implemented here. In the
+ // first part, in WK32WowIsKnownDll, forced the 16-bit loader to
+ // load c:\winnt\system32\control.exe(progman.exe) if the app
+ // tries to load c:\winnt\control.exe(progman.exe). 16-bit
+ // LoadModule tries and eventually discovers its a PE module
+ // and returns LME_PE, which causes this function to get called.
+ // Unfortunately, the scope of the WK32WowIsKnownDLL modified
+ // path is LMLoadExeFile, so by the time we get here, the path is
+ // once again c:\winnt\control.exe(progman.exe). Fix that.
+ //
+
+ if (!_stricmp(pszModuleName, pszControlExeWinDirPath) ||
+ (fProgman = TRUE,
+ !_stricmp(pszModuleName, pszProgmanExeWinDirPath))) {
+
+ strcpy(CmdLine, fProgman
+ ? pszProgmanExeSysDirPath
+ : pszControlExeSysDirPath);
+ } else {
+ strcpy(CmdLine, pszModuleName);
+ }
+
+ FREEPSZPTR(pszModuleName);
+ }
+ else {
+ ulRet = 2; // LME_FNF
+ goto lm32Exit;
+ }
+
+
+ pch = CmdLine + strlen(CmdLine);
+ *pch++ = ' ';
+
+ //
+ // The cmdline is a Pascal-style string: a count byte followed by
+ // characters followed by a terminating CR character. If this string is
+ // not well formed we will still try to reconstruct the command line in
+ // a similar manner that the c startup code does so using the following
+ // assumptions:
+ //
+ // 1. The command line can be no greater that 128 characters including
+ // the length byte and the terminator.
+ //
+ // 2. The valid terminators for a command line are CR or 0.
+ //
+ //
+
+ i = 0;
+ pSrc = pbCmdLine+1;
+ while (*pSrc != '\r' && *pSrc && i < 0x80 - 2) {
+ *pch++ = *pSrc++;
+ }
+ *pch = '\0';
+ }
+
+
+ RtlZeroMemory((PVOID)&StartupInfo, (DWORD)sizeof(StartupInfo));
+ StartupInfo.cb = sizeof(StartupInfo);
+ StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
+
+ //
+ // pCmdShow is documented as a pointer to an array of two WORDs,
+ // the first of which must be 2, and the second of which is
+ // the nCmdShow to use. It turns out that Win3.1 ignores
+ // the second word (uses SW_NORMAL) if the first word isn't 2.
+ // Pixie 2.0 passes an array of 2 zeros, which on Win 3.1 works
+ // because the nCmdShow of 0 (== SW_HIDE) is ignored since the
+ // first word isn't 2.
+ //
+ // Our logic, then, is to use SW_NORMAL unless pCmdShow is
+ // valid and points to a WORD value 2, in which case we use
+ // the next word as nCmdShow.
+ //
+ // DaveHart 27 June 1993.
+ //
+
+ GETVDMPTR(pParmBlock16->lpCmdShow, 4, pCmdShow);
+ if (pCmdShow && 2 == pCmdShow[0]) {
+ StartupInfo.wShowWindow = pCmdShow[1];
+ } else {
+ StartupInfo.wShowWindow = SW_NORMAL;
+ }
+
+ if (pCmdShow)
+ FREEVDMPTR(pCmdShow);
+
+
+ CreateProcessStatus = CreateProcess(
+ NULL,
+ CmdLine,
+ NULL, // security
+ NULL, // security
+ FALSE, // inherit handles
+ CREATE_NEW_CONSOLE | CREATE_DEFAULT_ERROR_MODE,
+ NULL, // environment strings
+ NULL, // current directory
+ &StartupInfo,
+ &ProcessInformation
+ );
+
+
+ if (CreateProcessStatus) {
+ DWORD WaitStatus;
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_SYNCHRONOUSDOSAPP) {
+ LPBYTE lpT;
+
+ // This is for supporting BeyondMail installation. It uses
+ // 40:72 as shared memory when it execs DOS programs. The windows
+ // part of installation program loops till the byte at 40:72 is
+ // non-zero. The DOS program ORs in 0x80 into this location which
+ // effectively signals the completion of the DOS task. On NT
+ // Windows and Dos programs are different processes and thus this
+ // 'sharing' business doesn't work. Hence this compatibility stuff.
+ // - nanduri
+
+ WaitStatus = WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
+ lpT = GetRModeVDMPointer(0x400072);
+ *lpT |= 0x80;
+ }
+ else if (!(CURRENTPTD()->dwWOWCompatFlags & WOWCF_NOWAITFORINPUTIDLE)) {
+
+ DWORD dw;
+ int i = 20;
+
+ //
+ // Wait for the started process to go idle.
+ //
+ do {
+ dw = WaitForInputIdle(ProcessInformation.hProcess, 5000);
+ WaitStatus = WaitForSingleObject(ProcessInformation.hProcess, 0);
+ } while (dw == WAIT_TIMEOUT && WaitStatus == WAIT_TIMEOUT && i--);
+ }
+
+ CloseHandle(ProcessInformation.hThread);
+
+ if (ProcessInformation.hProcess) {
+
+ PWOAINST pWOAInst;
+ DWORD cb;
+
+ //
+ // We're returning a process handle to winoldap, so
+ // build up a WOAINST structure add add it to this
+ // task's list of child WinOldAp instances.
+ //
+
+ if (parg16->lpModuleName && -1 != parg16->lpModuleName) {
+
+ GETPSZPTR(parg16->lpModuleName, pszModuleName);
+ cb = strlen(pszModuleName)+1;
+
+ } else {
+
+ cb = 1; // null terminator
+ pszModuleName = NULL;
+
+ }
+
+ //
+ // WOAINST includes one byte of szModuleName in its
+ // size, allocate enough room for the full string.
+ //
+
+ pWOAInst = malloc_w( (sizeof *pWOAInst) + cb - 1 );
+ WOW32ASSERT(pWOAInst);
+
+ if (pWOAInst) {
+ pWOAInst->pNext = CURRENTPTD()->pWOAList;
+ CURRENTPTD()->pWOAList = pWOAInst;
+ pWOAInst->dwChildProcessID = ProcessInformation.dwProcessId;
+ pWOAInst->hChildProcess = ProcessInformation.hProcess;
+
+ //
+ // point pptdWOA at pWOAInst->ptdWOA so that
+ // W32Thread can fill in the pointer to the
+ // WinOldAp TD.
+ //
+
+ pWOAInst->ptdWOA = NULL;
+ pptdWOA = &(pWOAInst->ptdWOA);
+
+ if (pszModuleName == NULL) {
+
+ pWOAInst->szModuleName[0] = 0;
+
+ } else {
+
+ RtlCopyMemory(
+ pWOAInst->szModuleName,
+ pszModuleName,
+ cb
+ );
+
+ //
+ // We are storing pszModuleName for comparison
+ // later in WowGetModuleHandle, called by
+ // Win16 GetModuleHandle. The latter always
+ // uppercases the paths involved, so we do
+ // as well so that we can do a case-insensitive
+ // comparison.
+ //
+
+ _strupr(pWOAInst->szModuleName);
+
+ //
+ // HACK -- PackRat can't run Explorer in one
+ // of its "Application Windows", because the
+ // spawned explorer.exe process goes away
+ // after asking the existing explorer to put
+ // up a window.
+ //
+ // If we're starting Explorer, close the
+ // process handle find the "real" shell
+ // explorer.exe process and put its handle
+ // and ID in this WOAINST structure. This
+ // fixes PackRat, but means that the
+ // winoldap task never goes away because
+ // the shell never goes away.
+ //
+
+ if (! pszExplorerFullPathUpper) {
+
+ int nLenWin = strlen(pszWindowsDirectory);
+ int nLenExpl = strlen(szExplorerDotExe);
+
+ //
+ // pszExplorerFullPathUpper looks like "C:\WINNT\EXPLORER.EXE"
+ //
+
+ pszExplorerFullPathUpper =
+ malloc_w(nLenWin + // strlen(pszWindowsDirectory)
+ 1 + // backslash
+ nLenExpl + // strlen("explorer.exe")
+ 1 // null terminator
+ );
+
+ if (pszExplorerFullPathUpper) {
+ RtlCopyMemory(pszExplorerFullPathUpper, pszWindowsDirectory, nLenWin);
+ pszExplorerFullPathUpper[nLenWin] = '\\';
+ RtlCopyMemory(&pszExplorerFullPathUpper[nLenWin+1], szExplorerDotExe, nLenExpl+1);
+ _strupr(pszExplorerFullPathUpper);
+ }
+
+ }
+
+ if (pszExplorerFullPathUpper &&
+ ! strcmp(pWOAInst->szModuleName, pszExplorerFullPathUpper)) {
+
+ GetWindowThreadProcessId(
+ GetShellWindow(),
+ &pWOAInst->dwChildProcessID
+ );
+
+ CloseHandle(pWOAInst->hChildProcess);
+ pWOAInst->hChildProcess = ProcessInformation.hProcess =
+ OpenProcess(
+ PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
+ FALSE,
+ pWOAInst->dwChildProcessID
+ );
+ }
+
+ }
+
+ }
+
+ if (pszModuleName) {
+ FREEPSZPTR(pszModuleName);
+ }
+ }
+
+ ulRet = 33;
+ pch = pszWinOldAppCmd + 2;
+ sprintf(pch, "%s%x\r", szWOAWOW32, ProcessInformation.hProcess);
+ *pszWinOldAppCmd = (char) strlen(pch);
+ *(pszWinOldAppCmd+1) = '\0';
+
+ } else {
+ //
+ // CreateProcess failed, map the most common error codes
+ //
+ switch (GetLastError()) {
+ case ERROR_FILE_NOT_FOUND:
+ ulRet = 2;
+ break;
+
+ case ERROR_PATH_NOT_FOUND:
+ ulRet = 3;
+ break;
+
+ case ERROR_BAD_EXE_FORMAT:
+ ulRet = 11;
+ break;
+
+ default:
+ ulRet = 0; // no memory
+ break;
+ }
+
+ }
+
+
+lm32Exit:
+ FREEARGPTR(parg16);
+ FREEPSZPTR(pbCmdLine);
+ FREEPSZPTR(pszWinOldAppCmd);
+ if (pParmBlock16)
+ FREEVDMPTR(pParmBlock16);
+
+ RETURN(ulRet);
+}
+
+
+/*++
+ WK32WOWQueryPerformanceCounter
+
+ Routine Description:
+ Calls NTQueryPerformanceCounter
+ Implemented for Performance Group
+
+ ENTRY
+ pFrame -> lpPerformanceFrequency points to location for storing Frequency
+ pFrame -> lpPerformanceCounter points to location for storing Counter
+
+ EXIT
+ NTStatus Code
+
+--*/
+
+ULONG FASTCALL WK32WOWQueryPerformanceCounter(PVDMFRAME pFrame)
+{
+ PLARGE_INTEGER pPerfCount16;
+ PLARGE_INTEGER pPerfFreq16;
+ LARGE_INTEGER PerformanceCounter;
+ LARGE_INTEGER PerformanceFrequency;
+ register PWOWQUERYPERFORMANCECOUNTER16 parg16;
+
+ GETARGPTR(pFrame, sizeof(WOWQUERYPERFORMANCECOUNTER16), parg16);
+
+ if (parg16->lpPerformanceCounter != 0) {
+ GETVDMPTR(parg16->lpPerformanceCounter, 8, pPerfCount16);
+ }
+ if (parg16->lpPerformanceFrequency != 0) {
+ GETVDMPTR(parg16->lpPerformanceFrequency, 8, pPerfFreq16);
+ }
+
+ NtQueryPerformanceCounter ( &PerformanceCounter, &PerformanceFrequency );
+
+ if (parg16->lpPerformanceCounter != 0) {
+ STOREDWORD(pPerfCount16->LowPart,PerformanceCounter.LowPart);
+ STOREDWORD(pPerfCount16->HighPart,PerformanceCounter.HighPart);
+ }
+
+ if (parg16->lpPerformanceFrequency != 0) {
+ STOREDWORD(pPerfFreq16->LowPart,PerformanceFrequency.LowPart);
+ STOREDWORD(pPerfFreq16->HighPart,PerformanceFrequency.HighPart);
+ }
+
+ FREEVDMPTR(pPerfCount16);
+ FREEVDMPTR(pPerfFreq16);
+ FREEARGPTR(parg16);
+ RETURN(TRUE);
+}
+
+/*++
+ WK32WOWOutputDebugString - Write a String to the debugger
+
+ The 16 bit kernel OutputDebugString calls this thunk to actually output the string to the
+ debugger. The 16 bit kernel routine does all the parameter validation etc before calling
+ this routine. Note also that all 16 bit kernel trace output also uses this routine, so
+ it not just the app which calls this function.
+
+ If this is a checked build the the output is send via LOGDEBUG so that it gets mingled with
+ the WOW trace information, this is useful when running the 16 bit logger tool.
+
+
+ Entry
+ pFrame->vpString Pointer to NULL terminated string to output to the debugger.
+
+ EXIT
+ ZERO
+
+--*/
+
+ULONG FASTCALL WK32WOWOutputDebugString(PVDMFRAME pFrame)
+{
+ PSZ psz1;
+ register POUTPUTDEBUGSTRING16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OUTPUTDEBUGSTRING16), parg16);
+ GETPSZPTRNOLOG(parg16->vpString, psz1);
+
+#ifdef DEBUG // So we can intermingle LOGGER output & WOW Logging
+ if ( !(flOptions & OPT_DEBUG) ) {
+ OutputDebugString(psz1);
+ } else {
+ INT length;
+ char text[TMP_LINE_LEN];
+ PSZ pszTemp;
+
+ length = strlen(psz1);
+ if ( length > TMP_LINE_LEN-1 ) {
+ strncpy( text, psz1, TMP_LINE_LEN );
+ text[TMP_LINE_LEN-2] = '\n';
+ text[TMP_LINE_LEN-1] = '\0';
+ pszTemp = text;
+ } else {
+ pszTemp = psz1;
+ }
+
+ LOGDEBUG(LOG_ALWAYS, ("%s", pszTemp)); // in debug version
+ }
+#else
+ OutputDebugString(psz1);
+#endif
+ FREEPSZPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+
+/* WK32WowFailedExec - WOWExec Failed to Exec Application
+ *
+ *
+ * Entry - Global Variable iW32ExecTaskId
+ *
+ *
+ * Exit
+ * SUCCESS TRUE
+ *
+ */
+
+ULONG FASTCALL WK32WowFailedExec(PVDMFRAME pFrame)
+{
+ UNREFERENCED_PARAMETER(pFrame);
+ if(iW32ExecTaskId != -1) {
+ ExitVDM(WOWVDM,iW32ExecTaskId);
+ iW32ExecTaskId = (UINT)-1;
+ ShowStartGlass (0);
+ }
+ FlushMapFileCaches();
+ return TRUE;
+}
+
+
+/*++
+
+ Hung App Support
+ ================
+
+ There are many levels at which hung app support works. The User will
+ bring up the Task List and hit the End Task Button. USER32 will post
+ a WM_ENDSESSION message to the app. If the app does not exit after a specified
+ timeout them USER will call W32HunAppThread, provided that the task is at the
+ client/server boundary. If the app is looping (ie not at the client/server
+ boundary) then it will use the HungAppNotifyThread to alter WOW to kill
+ the currently running task. For the case of W32EndTask we simply
+ return back to the 16 bit kernel and force it to perform and Int 21 4C Exit
+ call. For the case of the HungAppNotifyThread we have to somehow grab
+ the apps thread - at a point which is "safe". On non x86 platforms this
+ means that the emulator must be at a know safe state - ie not actively emulating
+ instructions. The worst case is if the app is spinning with interrupts
+ disabled.
+
+ Notify Thread will
+ Force Interrupts to be Enabled SetMSW()
+ Set global flag for heartbeatthread so it knows there is work to do
+ wait for the app to exit
+ timeout - terminate thread() reduce # of tasks
+
+ Alter Global Flag in 16 bit Kernel, that is checked on TimerTick Routines,
+ that routine will:-
+
+ Tidy the stack if on the DOSX stack during h/w interrupt simulation
+ Force Int 21 4C exit - might have to patch return address of h/w interrupt
+ and then do it at simulated TaskTime.
+
+ Worst Case
+ If we don't kill the app in the timeout specified the WOW will put up a dialog
+ and then ExitProcess to kill itself.
+
+ Suggestions - if we don't managed to cleanly kill a task we should reduce
+ the app count by 2 - (ie the task and WOWExec, so when the last 16 bit app
+ goes away we will shutdown WOW). Also in the case put up a dialog box
+ stating you should save your work for 16 bit apps too.
+
+--*/
+
+
+/*++
+
+ InitializeHungAppSupport - Setup Necessary Threads and Callbacks
+
+ Routine Description
+ Create a HungAppNotification Thread
+ Register CallBack Handlers With SoftPC Base which are called when
+ interrupt simulation is required.
+
+ Entry
+ NONE
+
+ EXIT
+ TRUE - Success
+ FALSE - Faled
+
+--*/
+BOOL WK32InitializeHungAppSupport(VOID)
+{
+
+ // Register Interrupt Idle Routine with SoftPC
+ ghevWowExecMsgWait = RegisterWOWIdle();
+
+
+ // Create HungAppNotify Thread
+
+ InitializeCriticalSection(&gcsWOW);
+ InitializeCriticalSection(&gcsHungApp); // protects VDM_WOWHUNGAPP bit
+
+ if(!(pfnOut.pfnRegisterUserHungAppHandlers)((PFNW32ET)W32HungAppNotifyThread,
+ ghevWowExecMsgWait))
+ {
+ LOGDEBUG(LOG_ALWAYS,("W32HungAppNotifyThread: Error Failed to RegisterUserHungAppHandlers\n"));
+ return FALSE;
+ }
+
+ if (!(ghevWaitHungAppNotifyThread = CreateEvent(NULL, TRUE, FALSE, NULL))) {
+ LOGDEBUG(LOG_ALWAYS,("WK32InitializeHungAppSupport ERROR: event allocation failure\n"));
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+
+
+
+/*++
+ WK32WowWaitForMsgAndEvent
+
+ Routine Description:
+ Calls USER32 WowWaitForMsgAndEvent
+ Called by WOWEXEC (interrupt dispatch optimization)
+
+ ENTRY
+ pFrame->hwnd must be WOWExec's hwnd
+
+ EXIT
+ FALSE - A message has arrived, WOWExec must call GetMessage
+ TRUE - The interrupt event was toggled, no work for WOWExec
+
+--*/
+
+ULONG FASTCALL WK32WowWaitForMsgAndEvent(PVDMFRAME pFrame)
+{
+ register PWOWWAITFORMSGANDEVENT16 parg16;
+ BOOL RetVal;
+
+ GETARGPTR(pFrame, sizeof(WOWWAITFORMSGANDEVENT16), parg16);
+
+ //
+ // This is a private api so lets make sure it is wowexec
+ //
+ if (ghwndShell != HWND32(parg16->hwnd)) {
+ FREEARGPTR(parg16);
+ return FALSE;
+ }
+
+ //
+ // WowExec will set VDM_TIMECHANGE bit in the pntvdmstate
+ // when it receives a WM_TIMECHANGE message. It is now safe
+ // to Reinit the Virtual Timer Hardware as wowexec is the currently
+ // scheduled task, and we expect no one to be polling on
+ // timer hardware\Bios tic count.
+ //
+ if (*pNtVDMState & VDM_TIMECHANGE) {
+ SuspendTimerThread();
+ ResumeTimerThread();
+ }
+
+ BlockWOWIdle(TRUE);
+
+ RetVal = (ULONG) (pfnOut.pfnWowWaitForMsgAndEvent)(ghevWowExecMsgWait);
+
+ BlockWOWIdle(FALSE);
+
+ FREEARGPTR(parg16);
+ return RetVal;
+}
+
+
+/*++
+ WowMsgBoxThread
+
+ Routine Description:
+ Worker Thread routine which does all of the msg box work for
+ Wk32WowMsgBox (See below)
+
+ ENTRY
+
+ EXIT
+ VOID
+
+--*/
+DWORD WowMsgBoxThread(VOID *pv)
+{
+ PWOWMSGBOX16 pWowMsgBox16 = (PWOWMSGBOX16)pv;
+ PSZ pszMsg, pszTitle;
+ char szMsg[MAX_PATH*2];
+ char szTitle[MAX_PATH];
+ UINT Style;
+
+
+ if (pWowMsgBox16->pszMsg) {
+ GETPSZPTR(pWowMsgBox16->pszMsg, pszMsg);
+ szMsg[MAX_PATH*2 - 1] = '\0';
+ strncpy(szMsg, pszMsg, MAX_PATH*2 - 1);
+ FREEPSZPTR(pszMsg);
+ } else {
+ szMsg[0] = '\0';
+ }
+
+ if (pWowMsgBox16->pszTitle) {
+ GETPSZPTR(pWowMsgBox16->pszTitle, pszTitle);
+ szTitle[MAX_PATH - 1] = '\0';
+ strncpy(szTitle, pszTitle, MAX_PATH);
+ FREEPSZPTR(pszTitle);
+ } else {
+ szTitle[0] = '\0';
+ }
+
+ Style = pWowMsgBox16->dwOptionalStyle | MB_OK | MB_SYSTEMMODAL;
+
+ pWowMsgBox16->dwOptionalStyle = 0xffffffff;
+
+ MessageBox (NULL, szMsg, szTitle, Style);
+
+ return 1;
+}
+
+
+
+/*++
+ WK32WowMsgBox
+
+ Routine Description:
+ Creates an asynchronous msg box and returns immediately
+ without waiting for the msg box to be dismissed. Provided
+ for WowExec as WowExec must use its special WowWaitForMsgAndEvent
+ api for hardware interrupt dispatching.
+
+ Called by WOWEXEC (interrupt dispatch optimization)
+
+ ENTRY
+ pszMsg - Message for MessageBox
+ pszTitle - Caption for MessageBox
+ dwOptionalStyle - MessageBox style bits additional to
+ MB_OK | MB_SYSTEMMODAL
+
+ EXIT
+ VOID - nothing is returned as we do not wait for a reply from
+ the user.
+
+--*/
+
+VOID FASTCALL WK32WowMsgBox(PVDMFRAME pFrame)
+{
+ PWOWMSGBOX16 pWowMsgBox16;
+ DWORD Tid;
+ HANDLE hThread;
+
+ GETARGPTR(pFrame, sizeof(WOWMSGBOX16), pWowMsgBox16);
+ hThread = CreateThread(NULL, 0, WowMsgBoxThread, (PVOID)pWowMsgBox16, 0, &Tid);
+ if (hThread) {
+ do {
+ if (WaitForSingleObject(hThread, 15) != WAIT_TIMEOUT)
+ break;
+ } while (pWowMsgBox16->dwOptionalStyle != 0xffffffff);
+
+ CloseHandle(hThread);
+ }
+ else {
+ WowMsgBoxThread((PVOID)pWowMsgBox16);
+ }
+
+ FREEARGPTR(pWowMsgBox16);
+ return;
+}
+
+
+
+/*++
+
+ W32HungAppNotifyThread
+
+ USER32 Calls this routine:
+ 1 - if the App Agreed to the End Task (from Task List)
+ 2 - if the app didn't respond to the End Task
+ 3 - shutdown
+
+ NTVDM Calls this routine:
+ 1 - if an app has touched some h/w that it shouldn't and the user
+ requiested to terminate the app (passed NULL for current task)
+
+ WOW32 Calls this routine:
+ 1 - when WowExec receives a WM_WOWEXECKILLTASK message.
+
+ ENTRY
+ hKillUniqueID - TASK ID of task to kill or NULL for current Task
+
+ EXIT
+ NEVER RETURNS - Goes away when WOW is killed
+
+--*/
+DWORD W32HungAppNotifyThread(UINT htaskKill)
+{
+ PTD ptd;
+ LPWORD pLockTDB;
+ DWORD dwThreadId;
+ int nMsgBoxChoice;
+ PTDB pTDB;
+ char szModName[9];
+ char szErrorMessage[200];
+ DWORD dwResult;
+ BOOL fSuccess;
+
+
+ if (!ResetEvent(ghevWaitHungAppNotifyThread)) {
+ LOGDEBUG(LOG_ALWAYS,("W32HungAppNotifyThread: ERROR failed to ResetEvent\n"));
+ }
+
+ ptd = NULL;
+
+ if (htaskKill) {
+
+ EnterCriticalSection(&gcsWOW);
+
+ ptd = gptdTaskHead;
+
+ /*
+ * See if the Task is still alive
+ */
+ while ((ptd != NULL) && (ptd->htask16 != htaskKill)) {
+ ptd = ptd->ptdNext;
+ }
+
+ LeaveCriticalSection(&gcsWOW);
+
+ }
+
+ // point to LockTDB
+
+ GETVDMPTR(vpLockTDB, 2, pLockTDB);
+
+ // If the task is alive then attempt to kill it
+
+ if ( ( ptd != NULL ) || ( htaskKill == 0 ) ) {
+
+ // Set LockTDB == The app we are trying to kill
+ // (see \kernel31\TASKING.ASM)
+ // and then try to cause a task switch by posting WOWEXEC a message
+ // and then posting a message to the app we want to kill
+
+ if ( ptd != NULL) {
+ *pLockTDB = ptd->htask16;
+ }
+ else {
+ // htaskKill == 0
+ // Kill the Active Task
+ *pLockTDB = *pCurTDB;
+ }
+
+ pTDB = (PTDB)SEGPTR(*pLockTDB, 0);
+
+ WOW32ASSERTMSGF( pTDB && pTDB->TDB_sig == TDB_SIGNATURE,
+ ("W32HungAppNotifyThread: TDB sig doesn't match, TDB %x htaskKill %x pTDB %x.\n",
+ *pLockTDB, htaskKill, pTDB));
+
+ dwThreadId = pTDB->TDB_ThreadID;
+
+ SendMessageTimeout(ghwndShell, WM_WOWEXECHEARTBEAT, 0, 0, SMTO_BLOCK,1*1000,&dwResult);
+
+ //
+ // terminate any pending named pipe operations for this thread (ie app)
+ //
+
+ VrCancelPipeIo(dwThreadId);
+
+ PostThreadMessage(dwThreadId, WM_KEYDOWN, VK_ESCAPE, 0x1B000A);
+ PostThreadMessage(dwThreadId, WM_KEYUP, VK_ESCAPE, 0x1B0001);
+
+ if (WaitForSingleObject(ghevWaitHungAppNotifyThread,
+ CMS_WAITTASKEXIT) == 0) {
+ LOGDEBUG(2,("W32HungAppNotifyThread: Success with forced task switch\n"));
+ ExitThread(EXIT_SUCCESS);
+ }
+
+ // Failed
+ //
+ // Probably means the current App is looping in 16 bit land not
+ // responding to input.
+
+ // Warn the User if its a different App than the one he wants to kill
+
+
+ if (*pLockTDB != *pCurTDB && *pCurTDB) {
+
+ pTDB = (PTDB)SEGPTR(*pCurTDB, 0);
+
+ WOW32ASSERTMSGF( pTDB && pTDB->TDB_sig == TDB_SIGNATURE,
+ ("W32HungAppNotifyThread: Current TDB sig doesn't match, TDB %x htaskKill %x pTDB %x.\n",
+ *pCurTDB, htaskKill, pTDB));
+
+ RtlCopyMemory(szModName, pTDB->TDB_ModName, (sizeof szModName)-1);
+ szModName[(sizeof szModName) - 1] = 0;
+
+ fSuccess = LoadString(
+ hmodWOW32,
+ iszCantEndTask,
+ szMsgBoxText,
+ WARNINGMSGLENGTH
+ );
+ WOW32ASSERT(fSuccess);
+
+ fSuccess = LoadString(
+ hmodWOW32,
+ iszApplicationError,
+ szCaption,
+ WARNINGMSGLENGTH
+ );
+ WOW32ASSERT(fSuccess);
+
+ wsprintf(
+ szErrorMessage,
+ szMsgBoxText,
+ szModName,
+ szModName
+ );
+
+ nMsgBoxChoice =
+ MessageBox(
+ NULL,
+ szErrorMessage,
+ szCaption,
+ MB_TOPMOST | MB_SETFOREGROUND | MB_TASKMODAL |
+ MB_ICONSTOP | MB_OKCANCEL
+ );
+
+ if (nMsgBoxChoice == IDCANCEL) {
+ ExitThread(0);
+ }
+ }
+
+ //
+ // See code in \mvdm\wow16\drivers\keyboard\keyboard.asm
+ // where keyb_int where it handles this interrupt and forces an
+ // int 21 function 4c - Exit. It only does this if VDM_WOWHUNGAPP
+ // is turned on in NtVDMState, and it clears that bit. We wait for
+ // the bit to be clear if it's already set, indicating another instance
+ // of this thread has already initiated an INT 9 to kill a task. By
+ // waiting we avoid screwing up the count of threads active on the
+ // 16-bit side (bThreadsIn16Bit).
+ //
+ // LATER shouldn't allow user to kill WOWEXEC
+ //
+ // LATER should enable h/w interrupt before doing this - use 40: area
+ // on x86. On MIPS we'd need to call CPU interface.
+ //
+
+ EnterCriticalSection(&gcsHungApp);
+
+ while (*pNtVDMState & VDM_WOWHUNGAPP) {
+ LeaveCriticalSection(&gcsHungApp);
+ LOGDEBUG(LOG_ALWAYS, ("WOW32 W32HungAppNotifyThread waiting for previous INT 9 to clear before dispatching another.\n"));
+ Sleep(1 * 1000);
+ EnterCriticalSection(&gcsHungApp);
+ }
+
+ *pNtVDMState |= VDM_WOWHUNGAPP;
+
+ LeaveCriticalSection(&gcsHungApp);
+
+ call_ica_hw_interrupt( KEYBOARD_ICA, KEYBOARD_LINE, 1 );
+
+ if (WaitForSingleObject(ghevWaitHungAppNotifyThread,
+ CMS_WAITTASKEXIT) != 0) {
+
+ LOGDEBUG(LOG_ALWAYS,("W32HungAppNotifyThread: Error, timeout waiting for task to terminate\n"));
+
+ fSuccess = LoadString(
+ hmodWOW32,
+ iszUnableToEndSelTask,
+ szMsgBoxText,
+ WARNINGMSGLENGTH);
+ WOW32ASSERT(fSuccess);
+
+ fSuccess = LoadString(
+ hmodWOW32,
+ iszSystemError,
+ szCaption,
+ WARNINGMSGLENGTH);
+ WOW32ASSERT(fSuccess);
+
+ nMsgBoxChoice =
+ MessageBox(
+ NULL,
+ szMsgBoxText,
+ szCaption,
+ MB_TOPMOST | MB_SETFOREGROUND | MB_TASKMODAL |
+ MB_ICONSTOP | MB_OKCANCEL | MB_DEFBUTTON1
+ );
+
+ if (nMsgBoxChoice == IDCANCEL) {
+ EnterCriticalSection(&gcsHungApp);
+ *pNtVDMState &= ~VDM_WOWHUNGAPP;
+ LeaveCriticalSection(&gcsHungApp);
+ ExitThread(0);
+ }
+
+ LOGDEBUG(LOG_ALWAYS, ("W32HungAppNotifyThread: Destroying WOW Process\n"));
+
+ ExitVDM(WOWVDM, ALL_TASKS);
+ ExitProcess(0);
+ }
+
+ LOGDEBUG(LOG_ALWAYS,("W32HungAppNotifyThread: Success with Keyboard Interrupt\n"));
+
+ } else { // task not found
+
+ LOGDEBUG(LOG_ALWAYS,("W32HungAppNotifyThread: Task already Terminated \n"));
+
+ }
+
+ ExitThread(EXIT_SUCCESS);
+ return 0; // remove compiler warning
+}
+
+
+
+/*++
+
+ W32EndTask - Cause Current Task to Exit (HUNG APP SUPPORT)
+
+ Routine Description:
+ This routine is called when unthunking WM_ENDSESSION to cause the current
+ task to terminate.
+
+ ENTRY
+ The apps thread that we want to kill
+
+ EXIT
+ DOES NOT RETURN - The task will exit and wind up in WK32KillTask which
+ will cause that thread to Exit.
+
+--*/
+
+VOID APIENTRY W32EndTask(VOID)
+{
+ PARM16 Parm16;
+ VPVOID vp = 0;
+
+ LOGDEBUG(LOG_WARNING,("W32EndTask: Forcing Task %04X to Exit\n",CURRENTPTD()->htask16));
+
+ CallBack16(RET_FORCETASKEXIT, &Parm16, 0, &vp);
+
+ //
+ // We should Never Come Here, an app should get terminated via calling wk32killtask thunk
+ // not by doing an unsimulate call
+ //
+
+ WOW32ASSERTMSG(FALSE, "W32EndTask: Error - Returned From ForceTaskExit callback - contact DaveHart");
+}
+
+
+ULONG FASTCALL WK32DirectedYield(PVDMFRAME pFrame)
+{
+ register PDIRECTEDYIELD16 parg16;
+
+ //
+ // This code is duplicated in wkgthunk.c by WOWDirectedYield16.
+ // The two must be kept synchronized.
+ //
+
+ GETARGPTR(pFrame, sizeof(DIRECTEDYIELD16), parg16);
+
+
+ BlockWOWIdle(TRUE);
+
+ (pfnOut.pfnDirectedYield)(THREADID32(parg16->hTask16));
+
+ BlockWOWIdle(FALSE);
+
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+/***************************************************************************\
+* EnablePrivilege
+*
+* Enables/disables the specified well-known privilege in the current thread
+* token if there is one, otherwise the current process token.
+*
+* Returns TRUE on success, FALSE on failure
+*
+* History:
+* 12-05-91 Davidc Created
+* 06-15-93 BobDay Stolen from WinLogon
+\***************************************************************************/
+BOOL
+EnablePrivilege(
+ ULONG Privilege,
+ BOOL Enable
+ )
+{
+ NTSTATUS Status;
+ BOOLEAN WasEnabled;
+
+ //
+ // Try the thread token first
+ //
+
+ Status = RtlAdjustPrivilege(Privilege,
+ (BOOLEAN)Enable,
+ TRUE,
+ &WasEnabled);
+
+ if (Status == STATUS_NO_TOKEN) {
+
+ //
+ // No thread token, use the process token
+ //
+
+ Status = RtlAdjustPrivilege(Privilege,
+ (BOOLEAN)Enable,
+ FALSE,
+ &WasEnabled);
+ }
+
+
+ if (!NT_SUCCESS(Status)) {
+ LOGDEBUG(LOG_ALWAYS,("WOW32: EnablePrivilege Failed to %s privilege : 0x%lx, status = 0x%lx\n", Enable ? "enable" : "disable", Privilege, Status));
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+//*****************************************************************************
+// W32GetAppCompatFlags -
+// Returns the Compatibility flags for the Current Task or of the
+// specified Task.
+// These are the 16-bit kernel's compatibility flags, not to be
+// confused with our separate WOW compatibility flags.
+//
+//*****************************************************************************
+
+ULONG W32GetAppCompatFlags(HTASK16 hTask16)
+{
+
+ PTDB ptdb;
+
+ if (hTask16 == (HAND16)NULL) {
+ hTask16 = CURRENTPTD()->htask16;
+ }
+
+ ptdb = (PTDB)SEGPTR((hTask16),0);
+
+ return (ULONG)MAKELONG(ptdb->TDB_CompatFlags, ptdb->TDB_CompatFlags2);
+}
+
+
+//
+// W32ReadWOWSetupNames -
+//
+// Reads names of the setup apps from the registry and remembers them
+// rgpszSetupPrograms is an array of up to 32 pointers to strings that
+// are parts of known setup program's names or module names.
+//
+// The registry key HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\SetupPrograms
+// contains value SetupProgramNames (Binary) in the format of double-0
+// terminated list of strings. This value is loaded and stored for the
+// length of time that wow is running.
+//
+
+#define MAX_SETUP_PROGRAMS 32
+PSZ rgpszSetupPrograms[MAX_SETUP_PROGRAMS];
+
+VOID W32InitWOWSetupNames(VOID)
+{
+ CHAR* pszSetupProgramsKey =
+ "Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\SetupPrograms";
+ CHAR* pszSetupProgramsValue = "SetupProgramNames";
+ HKEY hKey = 0;
+ LONG lError;
+ DWORD dwRegValueType;
+ ULONG ulSize = 0;
+ PSZ pszSetupPrograms = NULL;
+
+ lError = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ pszSetupProgramsKey,
+ 0,
+ KEY_QUERY_VALUE,
+ &hKey);
+ if (ERROR_SUCCESS != lError) {
+ LOGDEBUG(0, ("W32ReadWOWSetupNames: Unable to open key %s (%lx)", pszSetupProgramsKey, lError));
+ goto Cleanup;
+ }
+
+ lError = RegQueryValueEx(
+ hKey,
+ pszSetupProgramsValue,
+ NULL,
+ &dwRegValueType,
+ NULL,
+ &ulSize);
+ if (ERROR_SUCCESS != lError ||
+ (REG_BINARY != dwRegValueType && REG_MULTI_SZ != dwRegValueType)) {
+ LOGDEBUG(0, ("W32ReadWOWSetupNames: RegQueryValueEx failed %lx\n", lError));
+ goto Cleanup;
+ }
+
+ if (NULL == (pszSetupPrograms = malloc_w(ulSize))) {
+ LOGDEBUG(0, ("W32ReadWOWSetupNames: Failed to allocate memory for the list of names\n"));
+ goto Cleanup;
+ }
+
+ // if here, then memory was allocated and key exists
+ lError = RegQueryValueEx(
+ hKey,
+ pszSetupProgramsValue,
+ NULL,
+ &dwRegValueType,
+ pszSetupPrograms,
+ &ulSize);
+ if (ERROR_SUCCESS != lError) {
+ // free what we've got
+ free_w(pszSetupPrograms);
+ goto Cleanup;
+ }
+
+ //
+ // parse the setup programs list so that
+ // every string (up to max-1) is pointed to by rgpszSetupPrograms
+ //
+ {
+ register PSZ pch = pszSetupPrograms;
+ register INT nCount = 0;
+
+ while (*pch && nCount < (MAX_SETUP_PROGRAMS-1)) {
+ // all strings are converted to lower-case
+
+ rgpszSetupPrograms[nCount++] = _strlwr(pch);
+ pch += strlen(pch) + 1; // advance the string
+ }
+
+ // the entry at the end is NULL always as global vars are 0-filled
+ // by default
+
+ }
+
+Cleanup:
+
+ if (hKey) {
+ RegCloseKey(hKey);
+ }
+}
+
+
+// W32IsSetupProgram -
+//
+// Attempts to determine if current task is a setup program
+// by looking up name of the module or the filename against the
+// list of the known setup names.
+//
+//
+
+BOOL W32IsSetupProgram(PSZ pszModName, PSZ pszFileName)
+{
+ INT i;
+ CHAR szName[256];
+ PSZ rgArg[] = { pszModName, pszFileName };
+ INT iArg;
+
+ // loop through pszModName and pszFileName
+
+ // The rgArg is array of pointers to arguments which
+ // are searched for a matching setup name substring
+
+ for (iArg = 0; iArg < sizeof(rgArg)/sizeof(rgArg[0]); ++iArg) {
+
+ _strlwr(strcpy(szName, rgArg[iArg]));
+
+ for (i = 0; NULL != rgpszSetupPrograms[i]; ++i) {
+ if (NULL != strstr(szName, rgpszSetupPrograms[i])) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+//*****************************************************************************
+// W32ReadWOWCompatFlags -
+//
+// Returns the WOW-specific compatibility flags for the specified task.
+// Called during thread initialization to set td.dwWOWCompatFlags.
+// These are not to be confused with the 16-bit kernel's compatibility
+// flags.
+//
+// Flag values are defined in wow32.h.
+//
+//*****************************************************************************
+
+ULONG W32ReadWOWCompatFlags(HTASK16 htask16, DWORD *pdwWOWCompatFlagsEx)
+{
+ LONG lError;
+ HKEY hKey = 0;
+ char szModName[9];
+ char szHexAsciiFlags[22];
+ DWORD dwType = REG_SZ;
+ DWORD cbData = sizeof(szHexAsciiFlags);
+ ULONG ul = 0;
+ char *pch;
+
+ *pdwWOWCompatFlagsEx = 0;
+
+ lError = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\Compatibility",
+ 0,
+ KEY_QUERY_VALUE,
+ &hKey
+ );
+
+ if (ERROR_SUCCESS != lError) {
+ LOGDEBUG(0,("W32ReadWOWCompatFlags: RegOpenKeyEx failed, error %ld.\n", lError));
+ goto Cleanup;
+ }
+
+ //
+ // Fetch the EXE's module name into szModName, trimming trailing blanks.
+ //
+
+ RtlCopyMemory(
+ szModName,
+ ((PTDB)SEGPTR(CURRENTPTD()->htask16,0))->TDB_ModName,
+ 8
+ );
+ szModName[8] = 0;
+
+ pch = &szModName[8];
+ while (*(--pch) == ' ') {
+ *pch = 0;
+ }
+
+ lError = RegQueryValueEx(
+ hKey,
+ szModName,
+ 0,
+ &dwType,
+ szHexAsciiFlags,
+ &cbData
+ );
+
+ if (ERROR_SUCCESS != lError) {
+
+ //
+ // This module name doesn't have any compatibility flags.
+ //
+
+ goto Cleanup;
+ }
+
+ WOW32ASSERTMSGF(REG_SZ == dwType, ("W32ReadWOWCompatFlags(%s): RegQueryValueEx returned type %lx, must be REG_SZ.\n", szModName, dwType));
+ if (REG_SZ != dwType) {
+ goto Cleanup;
+ }
+
+ if (!(pch = strstr(szHexAsciiFlags, "0x"))) {
+ goto BadFormat;
+ }
+ pch += 2; // skip "0x"
+
+ if (!NT_SUCCESS(RtlCharToInteger(pch, 16, &ul))) {
+ goto BadFormat;
+ }
+
+ if (pch = strstr(pch, " 0x")) {
+ pch += 3; // skip " 0x"
+
+ if (!NT_SUCCESS(RtlCharToInteger(pch, 16, pdwWOWCompatFlagsEx))) {
+ goto BadFormat;
+ }
+ }
+
+ LOGDEBUG(0,("WOW: Compatibility flags for %s are %08x %08x\n", szModName, ul, *pdwWOWCompatFlagsEx));
+
+ goto Cleanup;
+
+BadFormat:
+ LOGDEBUG(0,("W32ReadWOWCompatFlags(%s): Unable to interpret '%s' as hex.\n", szModName, szHexAsciiFlags));
+
+Cleanup:
+ if (hKey) {
+ RegCloseKey(hKey);
+ }
+
+ return ul;
+}
+
+
+//*****************************************************************************
+// This is called from COMM.drv via WowCloseComPort in kernel16, whenever
+// a com port needs to be released.
+//
+// PortId 0 is COM1, 1 is COM2 etc.
+// - Nanduri
+//*****************************************************************************
+
+VOID FASTCALL WK32WowCloseComPort(PVDMFRAME pFrame)
+{
+ register PWOWCLOSECOMPORT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(WOWCLOSECOMPORT16), parg16);
+ host_com_close((INT)parg16->wPortId);
+ FREEARGPTR(parg16);
+}
+
+
+//*****************************************************************************
+// Some apps keep a file open and delete it. Then rename another file to
+// the old name. On NT since the orignal object is still open the second
+// rename fails.
+// To get around this problem we rename the file before deleteing it
+// this allows the second rename to work
+//*****************************************************************************
+
+DWORD FASTCALL WK32WowDelFile(PVDMFRAME pFrame)
+{
+ PSZ psz1;
+ PWOWDELFILE16 parg16;
+ CHAR wowtemp[MAX_PATH];
+ CHAR tmpfile[MAX_PATH];
+ PSZ pFileName;
+ DWORD retval = 0xffff;
+
+ GETARGPTR(pFrame, sizeof(WOWFILEDEL16), parg16);
+ GETVDMPTR(parg16->lpFile, 1, psz1);
+
+ // Rename the file to a temp name and then delete it
+
+ LOGDEBUG(fileoclevel,("WK32WOWDelFile: %s \n",psz1));
+
+ tmpfile[0] = '\0';
+
+ if( DeleteFileOem( psz1 ) ) {
+ //
+ // See if the file has really disappeared
+ //
+ if( GetFileAttributesOem( psz1 ) != 0xFFFFFFFF ) {
+
+ //
+ // The file didn't really go away, even though DeleteFileOem()
+ // returned success. This may be because a handle to the file
+ // is still open.
+ //
+ if (GetFullPathNameOem(psz1,MAX_PATH,wowtemp,&pFileName)) {
+ if ( pFileName )
+ *(pFileName) = 0;
+ if (GetTempFileNameOem(wowtemp,"WOW",0,tmpfile)) {
+ if (MoveFileExOem(psz1,tmpfile, MOVEFILE_REPLACE_EXISTING)) {
+ if(DeleteFileOem(tmpfile)) {
+ retval = 0;
+ } else {
+ MoveFileOem(tmpfile,psz1);
+ }
+ }
+ }
+ }
+
+ } else {
+ retval = 0;
+ }
+ }
+
+ if (retval != 0) {
+
+ if( tmpfile[0] ) {
+ DeleteFileOem(tmpfile);
+ }
+
+ // Some Windows Install Programs copy a .FON font file to a temp
+ // directory use the font during installation and then try to delete
+ // the font - without calling RemoveFontResource(); GDI32 Keeps the
+ // Font file open and thus the delete fails.
+
+ // What we attempt here is to assume that the file is a FONT file
+ // and try to remove it before deleting it, since the above delete
+ // has already failed.
+
+ if ( RemoveFontResourceOem(psz1) ) {
+ LOGDEBUG(fileoclevel,("WK32WOWDelFile: RemoveFontResource on %s \n",psz1));
+ SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
+ }
+
+ if(!DeleteFileOem(psz1)) {
+ retval = (GetLastError() | 0xffff0000 );
+ }else {
+ retval = 0;
+ }
+ }
+
+ FREEVDMPTR(psz1);
+ FREEARGPTR(parg16);
+ return retval;
+}
+
+
+//*****************************************************************************
+// This is called as soon as wow is initialized to notify the 32-bit world
+// what the addresses are of some key kernel variables.
+//
+//*****************************************************************************
+
+VOID FASTCALL WK32WOWNotifyWOW32(PVDMFRAME pFrame)
+{
+ register PWOWNOTIFYWOW3216 parg16;
+
+ GETARGPTR(pFrame, sizeof(WOWNOTIFYWOW3216), parg16);
+
+ vpDebugWOW = FETCHDWORD(parg16->lpDebugWOW);
+ GETVDMPTR(FETCHDWORD(parg16->lpcurTDB), 2, pCurTDB);
+ vpnum_tasks = FETCHDWORD(parg16->lpnum_tasks);
+ vpLockTDB = FETCHDWORD(parg16->lpLockTDB);
+ vptopPDB = FETCHDWORD(parg16->lptopPDB);
+ GETVDMPTR(FETCHDWORD(parg16->lpCurDirOwner), 2, pCurDirOwner);
+
+ //
+ // IsDebuggerAttached will tell the 16-bit kernel to generate
+ // debug events.
+ //
+ IsDebuggerAttached();
+
+ FREEARGPTR(parg16);
+}
+
+//*****************************************************************************
+// Currently, this routine is called very very soon after the 16-bit kernel.exe
+// has switched to protected mode. The variables set up here are used in the
+// file i/o routines.
+//*****************************************************************************
+
+
+ULONG FASTCALL WK32DosWowInit(PVDMFRAME pFrame)
+{
+ register PWOWDOSWOWINIT16 parg16;
+ PDOSWOWDATA pDosWowData;
+ PULONG pTemp;
+
+ GETARGPTR(pFrame, sizeof(WOWDOSWOWINIT16), parg16);
+
+ // covert all fixed DOS address to linear addresses for fast WOW thunks.
+ pDosWowData = GetRModeVDMPointer(FETCHDWORD(parg16->lpDosWowData));
+
+ DosWowData.lpCDSCount = (DWORD) GetRModeVDMPointer(
+ FETCHDWORD(pDosWowData->lpCDSCount));
+ pTemp = (PULONG)GetRModeVDMPointer(FETCHDWORD(pDosWowData->lpCDSFixedTable));
+ DosWowData.lpCDSFixedTable = (DWORD) GetRModeVDMPointer(FETCHDWORD(*pTemp));
+
+ DosWowData.lpCDSBuffer = (DWORD)GetRModeVDMPointer(
+ FETCHDWORD(pDosWowData->lpCDSBuffer));
+ DosWowData.lpCurDrv = (DWORD) GetRModeVDMPointer(
+ FETCHDWORD(pDosWowData->lpCurDrv));
+ DosWowData.lpCurPDB = (DWORD) GetRModeVDMPointer(
+ FETCHDWORD(pDosWowData->lpCurPDB));
+ DosWowData.lpDrvErr = (DWORD) GetRModeVDMPointer(
+ FETCHDWORD(pDosWowData->lpDrvErr));
+ DosWowData.lpExterrLocus = (DWORD) GetRModeVDMPointer(
+ FETCHDWORD(pDosWowData->lpExterrLocus));
+ DosWowData.lpSCS_ToSync = (DWORD) GetRModeVDMPointer(
+ FETCHDWORD(pDosWowData->lpSCS_ToSync));
+ DosWowData.lpSftAddr = (DWORD) GetRModeVDMPointer(
+ FETCHDWORD(pDosWowData->lpSftAddr));
+
+ FREEARGPTR(parg16);
+ return (0);
+}
+
+
+//*****************************************************************************
+//
+// WK32InitWowIsKnownDLL(HANDLE hKeyWow)
+//
+// Called by W32Init to read list of known DLLs from the registry.
+//
+// hKeyWow is an open handle to ...\CurrentControlSet\WOW, we use
+// the value REG_SZ value KnownDLLs which looks like "commdlg.dll mmsystem.dll
+// toolhelp.dll olecli.dll olesvr.dll".
+//
+//*****************************************************************************
+
+VOID WK32InitWowIsKnownDLL(HANDLE hKeyWow)
+{
+ CHAR sz[2048];
+ PSZ pszKnownDLL;
+ PCHAR pch;
+ ULONG ulSize = sizeof(sz);
+ int nCount;
+ DWORD dwRegValueType;
+ LONG lRegError;
+ ULONG ulAttrib;
+
+ //
+ // Get the list of known DLLs from the registry.
+ //
+
+ lRegError = RegQueryValueEx(
+ hKeyWow,
+ "KnownDLLs",
+ NULL,
+ &dwRegValueType,
+ sz,
+ &ulSize
+ );
+
+ if (ERROR_SUCCESS == lRegError && REG_SZ == dwRegValueType) {
+
+ //
+ // Allocate memory to hold a copy of this string to be
+ // used to hold the strings pointed to by
+ // apszKnownDLL[]. This memory won't be freed until
+ // WOW goes away.
+ //
+
+ pszKnownDLL = malloc_w_or_die(ulSize);
+
+ strcpy(pszKnownDLL, sz);
+
+ //
+ // Lowercase the entire value so that we can search these
+ // strings case-sensitive in WK32WowIsKnownDLL.
+ //
+
+ _strlwr(pszKnownDLL);
+
+ //
+ // Parse the KnownDLL string into apszKnownDLL array.
+ // strtok() does this quite handily.
+ //
+
+ nCount = 0;
+
+ pch = apszKnownDLL[0] = pszKnownDLL;
+
+ while (apszKnownDLL[nCount]) {
+ nCount++;
+ if (nCount >= MAX_KNOWN_DLLS) {
+ LOGDEBUG(0,("WOW32 Init: Too many known DLLs, must have %d or fewer.\n", MAX_KNOWN_DLLS-1));
+ apszKnownDLL[MAX_KNOWN_DLLS-1] = NULL;
+ break;
+ }
+ pch = strchr(pch, ' ');
+ if (!pch) {
+ break;
+ }
+ *pch = 0;
+ pch++;
+ if (0 == *pch) {
+ break;
+ }
+ while (' ' == *pch) {
+ pch++;
+ }
+ apszKnownDLL[nCount] = pch;
+ }
+
+ } else {
+ LOGDEBUG(0,("InitWowIsKnownDLL: RegQueryValueEx error %ld.\n", lRegError));
+ }
+
+ //
+ // The Known DLL list is ready, now build up a fully-qualified paths
+ // to %windir%\control.exe and %windir%\system32\control.exe
+ // for WOWCF_CONTROLEXEHACK below.
+ //
+
+ //
+ // pszControlExeWinDirPath looks like "c:\winnt\control.exe"
+ //
+
+ pszControlExeWinDirPath =
+ malloc_w_or_die(strlen(pszWindowsDirectory) +
+ sizeof(szBackslashControlExe)-1 + // strlen("\\control.exe")
+ 1 // null terminator
+ );
+
+ strcpy(pszControlExeWinDirPath, pszWindowsDirectory);
+ strcat(pszControlExeWinDirPath, szBackslashControlExe);
+
+
+ //
+ // pszProgmanExeWinDirPath looks like "c:\winnt\progman.exe"
+ //
+
+ pszProgmanExeWinDirPath =
+ malloc_w_or_die(strlen(pszWindowsDirectory) +
+ sizeof(szBackslashProgmanExe)-1 + // strlen("\\progman.exe")
+ 1 // null terminator
+ );
+
+ strcpy(pszProgmanExeWinDirPath, pszWindowsDirectory);
+ strcat(pszProgmanExeWinDirPath, szBackslashProgmanExe);
+
+
+ //
+ // pszControlExeSysDirPath looks like "c:\winnt\system32\control.exe"
+ //
+
+ pszControlExeSysDirPath =
+ malloc_w_or_die(strlen(pszSystemDirectory) +
+ sizeof(szBackslashControlExe)-1 + // strlen("\\control.exe")
+ 1 // null terminator
+ );
+
+ strcpy(pszControlExeSysDirPath, pszSystemDirectory);
+ strcat(pszControlExeSysDirPath, szBackslashControlExe);
+
+ //
+ // pszProgmanExeSysDirPath looks like "c:\winnt\system32\control.exe"
+ //
+
+ pszProgmanExeSysDirPath =
+ malloc_w_or_die(strlen(pszSystemDirectory) +
+ sizeof(szBackslashProgmanExe)-1 + // strlen("\\progman.exe")
+ 1 // null terminator
+ );
+
+ strcpy(pszProgmanExeSysDirPath, pszSystemDirectory);
+ strcat(pszProgmanExeSysDirPath, szBackslashProgmanExe);
+
+ // Make the KnownDLL, CTL3DV2.DLL, file attribute ReadOnly.
+ // Later we should do this for all WOW KnownDll's
+ strcpy(sz, pszSystemDirectory);
+ strcat(sz, "\\CTL3DV2.DLL");
+ ulAttrib = GetFileAttributesOem(sz);
+ if ((ulAttrib != 0xFFFFFFFF) && !(ulAttrib & FILE_ATTRIBUTE_READONLY)) {
+ ulAttrib |= FILE_ATTRIBUTE_READONLY;
+ SetFileAttributesOem(sz, ulAttrib);
+ }
+
+}
+
+
+//*****************************************************************************
+//
+// WK32WowIsKnownDLL -
+//
+// This routine is called from within LoadModule (actually MyOpenFile),
+// when kernel31 has determined that the module is not already loaded,
+// and is about to search for the DLL. If the base name of the passed
+// path is a known DLL, we allocate and pass back to the 16-bit side
+// a fully-qualified path to the DLL in the system32 directory.
+//
+//*****************************************************************************
+
+ULONG FASTCALL WK32WowIsKnownDLL(PVDMFRAME pFrame)
+{
+ register WOWISKNOWNDLL16 *parg16;
+ PSZ pszPath;
+ VPVOID UNALIGNED *pvpszKnownDLLPath;
+ PSZ pszKnownDLLPath;
+ size_t cbKnownDLLPath;
+ char **ppsz;
+ char szLowercasePath[13];
+ ULONG ul = 0;
+ BOOL fProgman = FALSE;
+
+ GETARGPTR(pFrame, sizeof(WOWISKNOWNDLL16), parg16);
+
+ GETPSZPTRNOLOG(parg16->lpszPath, pszPath);
+ GETVDMPTR(parg16->lplpszKnownDLLPath, sizeof(*pvpszKnownDLLPath), pvpszKnownDLLPath);
+
+ if (pszPath) {
+
+ //
+ // Special hack for apps which WinExec %windir%\control.exe or
+ // %windir%\progman.exe. This formerly was only done under a
+ // compatibility bit, but now is done for all apps. Both
+ // the 3.1[1] control panel and program manager binaries cannot
+ // work under WOW because of other shell conflicts, like different
+ // .GRP files and conflicting use of the control.ini file for both
+ // 16-bit and 32-bit CPLs.
+ //
+ // Compare the path passed in with the precomputed
+ // pszControlExeWinDirPath, which looks like "c:\winnt\control.exe".
+ // If it matches, pass back the "Known DLL path" of
+ // "c:\winnt\system32\control.exe". Same for progman.exe.
+ //
+
+ if (!_stricmp(pszPath, pszControlExeWinDirPath) ||
+ (fProgman = TRUE,
+ !_stricmp(pszPath, pszProgmanExeWinDirPath))) {
+
+ VPVOID vp;
+
+ cbKnownDLLPath = 1 + strlen(fProgman
+ ? pszProgmanExeSysDirPath
+ : pszControlExeSysDirPath);
+
+ vp = malloc16(cbKnownDLLPath);
+
+ // 16-bit memory may have moved - refresh flat pointers now
+
+ FREEVDMPTR(pvpszKnownDLLPath);
+ FREEPSZPTR(pszPath);
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(WOWISKNOWNDLL16), parg16);
+ GETPSZPTRNOLOG(parg16->lpszPath, pszPath);
+ GETVDMPTR(parg16->lplpszKnownDLLPath, sizeof(*pvpszKnownDLLPath), pvpszKnownDLLPath);
+
+ *pvpszKnownDLLPath = vp;
+
+ if (*pvpszKnownDLLPath) {
+
+ GETPSZPTRNOLOG(*pvpszKnownDLLPath, pszKnownDLLPath);
+
+ RtlCopyMemory(
+ pszKnownDLLPath,
+ fProgman
+ ? pszProgmanExeSysDirPath
+ : pszControlExeSysDirPath,
+ cbKnownDLLPath);
+
+ // LOGDEBUG(0,("WowIsKnownDLL: %s known(c) -=> %s\n", pszPath, pszKnownDLLPath));
+
+ FLUSHVDMPTR(*pvpszKnownDLLPath, cbKnownDLLPath, pszKnownDLLPath);
+ FREEPSZPTR(pszKnownDLLPath);
+
+ ul = 1; // return success, meaning is known dll
+ goto Cleanup;
+ }
+ }
+
+ //
+ // We don't mess with attempts to open that include a
+ // path.
+ //
+
+ if (strchr(pszPath, '\\') || strchr(pszPath, ':') || strlen(pszPath) > 12) {
+ // LOGDEBUG(0,("WowIsKnownDLL: %s has a path, not checking.\n", pszPath));
+ goto Cleanup;
+ }
+
+ //
+ // Make a lowercase copy of the path.
+ //
+
+ strncpy(szLowercasePath, pszPath, sizeof(szLowercasePath));
+ szLowercasePath[sizeof(szLowercasePath)-1] = 0;
+ _strlwr(szLowercasePath);
+
+
+ //
+ // Step through apszKnownDLL trying to find this DLL
+ // in the list.
+ //
+
+ for (ppsz = &apszKnownDLL[0]; *ppsz; ppsz++) {
+
+ //
+ // We compare case-sensitive for speed, since we're
+ // careful to lowercase the strings in apszKnownDLL
+ // and szLowercasePath.
+ //
+
+ if (!strcmp(szLowercasePath, *ppsz)) {
+
+ //
+ // We found the DLL in the list, now build up
+ // a buffer for the 16-bit side containing
+ // the full path to that DLL in the system32
+ // directory.
+ //
+
+ cbKnownDLLPath = strlen(pszSystemDirectory) +
+ 1 + // "\"
+ strlen(szLowercasePath) +
+ 1; // null
+
+ *pvpszKnownDLLPath = malloc16(cbKnownDLLPath);
+
+ if (*pvpszKnownDLLPath) {
+
+ GETPSZPTRNOLOG(*pvpszKnownDLLPath, pszKnownDLLPath);
+
+ strcpy(pszKnownDLLPath, pszSystemDirectory);
+ strcat(pszKnownDLLPath, "\\");
+ strcat(pszKnownDLLPath, szLowercasePath);
+
+ // LOGDEBUG(0,("WowIsKnownDLL: %s known -=> %s\n", pszPath, pszKnownDLLPath));
+
+ FLUSHVDMPTR(*pvpszKnownDLLPath, cbKnownDLLPath, pszKnownDLLPath);
+ FREEPSZPTR(pszKnownDLLPath);
+
+ ul = 1; // return success, meaning is known dll
+ goto Cleanup;
+ }
+ }
+ }
+
+ //
+ // We've checked the Known DLL list and come up empty, or
+ // malloc16 failed.
+ //
+
+ // LOGDEBUG(0,("WowIsKnownDLL: %s is not a known DLL.\n", szLowercasePath));
+
+ } else {
+
+ //
+ // pszPath is NULL, so free the 16-bit buffer pointed
+ // to by *pvpszKnownDLLPath.
+ //
+
+ if (*pvpszKnownDLLPath) {
+ free16(*pvpszKnownDLLPath);
+ ul = 1;
+ }
+ }
+
+ Cleanup:
+ FLUSHVDMPTR(parg16->lplpszKnownDLLPath, sizeof(*pvpszKnownDLLPath), pvpszKnownDLLPath);
+ FREEVDMPTR(pvpszKnownDLLPath);
+ FREEPSZPTR(pszPath);
+ FREEARGPTR(parg16);
+
+ return ul;
+}
+
+
+VOID RemoveHmodFromCache(HAND16 hmod16)
+{
+ INT i;
+
+ //
+ // blow this guy out of the hinst/hmod cache
+ // if we find it, slide the other entries up to overwrite it
+ // and then zero out the last entry
+ //
+
+ for (i = 0; i < CHMODCACHE; i++) {
+ if (ghModCache[i].hMod16 == hmod16) {
+
+ // if we're not at the last entry, slide the rest up 1
+
+ if (i != CHMODCACHE-1) {
+ RtlMoveMemory((PVOID)(ghModCache+i),
+ (CONST VOID *)(ghModCache+i+1),
+ sizeof(HMODCACHE)*(CHMODCACHE-i-1) );
+ }
+
+ // the last entry is now either a dup or the one going away
+
+ ghModCache[CHMODCACHE-1].hMod16 =
+ ghModCache[CHMODCACHE-1].hInst16 = 0;
+ }
+ }
+}
+
+//
+// Scans the share memory segment for wow processes which might have
+// been killed and removes them.
+//
+
+VOID
+CleanseSharedList(
+ VOID
+) {
+ LPSHAREDTASKMEM lpstm;
+ LPSHAREDMEMOBJECT lpsmo;
+ LPSHAREDPROCESS lpsp;
+ LPSHAREDPROCESS lpspPrev;
+ HANDLE hProcess;
+ DWORD dwOffset;
+
+ lpstm = LOCKSHAREWOW();
+ if ( !lpstm ) {
+ LOGDEBUG(0,("WOW32: CleanseSharedList failed to map in shared wow memory\n") );
+ return;
+ }
+
+ if ( !lpstm->fInitialized ) {
+ lpstm->fInitialized = TRUE;
+ lpstm->dwFirstProcess = 0;
+ }
+
+ lpsmo = (LPSHAREDMEMOBJECT)((CHAR *)lpstm + sizeof(SHAREDTASKMEM));
+
+ lpspPrev = NULL;
+ dwOffset = lpstm->dwFirstProcess;
+
+ while( dwOffset ) {
+ lpsp = (LPSHAREDPROCESS)((CHAR *)lpstm + dwOffset);
+
+ WOW32ASSERT(lpsp->dwType == SMO_PROCESS);
+
+ // Test this process to see if he is still around.
+
+ hProcess = OpenProcess( SYNCHRONIZE, FALSE, lpsp->dwProcessId );
+ if ( hProcess == NULL ) {
+ if ( lpspPrev ) {
+ lpspPrev->dwNextProcess = lpsp->dwNextProcess;
+ } else {
+ lpstm->dwFirstProcess = lpsp->dwNextProcess;
+ }
+ lpsp->dwType = SMO_AVAILABLE;
+ } else {
+ CloseHandle( hProcess );
+ lpspPrev = lpsp; // only update lpspPrev if lpsp is valid
+ }
+ dwOffset = lpsp->dwNextProcess;
+ }
+
+ UNLOCKSHAREWOW();
+}
+
+//
+// Add this process to the shared memory list of wow processes
+//
+VOID
+AddProcessSharedList(
+ VOID
+) {
+ LPSHAREDTASKMEM lpstm;
+ LPSHAREDMEMOBJECT lpsmo;
+ LPSHAREDPROCESS lpsp;
+ DWORD dwResult;
+ INT count;
+
+ lpstm = LOCKSHAREWOW();
+ if ( !lpstm ) {
+ LOGDEBUG(0,("WOW32: AddProcessSharedList failed to map in shared wow memory\n") );
+ return;
+ }
+
+ // Scan for available slot
+ count = 0;
+ dwResult = 0;
+
+ lpsmo = (LPSHAREDMEMOBJECT)((CHAR *)lpstm + sizeof(SHAREDTASKMEM));
+
+ while ( count < MAX_SHARED_OBJECTS ) {
+ if ( lpsmo->dwType == SMO_AVAILABLE ) {
+ lpsp = (LPSHAREDPROCESS)lpsmo;
+ dwResult = (DWORD)((CHAR *)lpsp - (CHAR *)lpstm);
+ lpsp->dwType = SMO_PROCESS;
+ lpsp->dwProcessId = GetCurrentProcessId();
+ lpsp->dwAttributes = fSeparateWow ? 0 : WOW_SYSTEM;
+ lpsp->pfnW32HungAppNotifyThread = (LPTHREAD_START_ROUTINE) W32HungAppNotifyThread;
+ lpsp->dwNextProcess = lpstm->dwFirstProcess;
+ lpsp->dwFirstTask = 0;
+ lpstm->dwFirstProcess = dwResult;
+ break;
+ }
+ lpsmo++;
+ count++;
+ }
+ if ( count == MAX_SHARED_OBJECTS ) {
+ LOGDEBUG(0, ("WOW32: AddProcessSharedList: Not enough room in WOW's Shared Memory\n") );
+ }
+ UNLOCKSHAREWOW();
+
+ dwSharedProcessOffset = dwResult;
+}
+
+//
+// Remove this process from the shared memory list of wow tasks
+//
+VOID
+RemoveProcessSharedList(
+ VOID
+) {
+ LPSHAREDTASKMEM lpstm;
+ LPSHAREDPROCESS lpsp;
+ LPSHAREDPROCESS lpspPrev;
+ DWORD dwOffset;
+ DWORD dwCurrentId;
+
+ lpstm = LOCKSHAREWOW();
+ if ( !lpstm ) {
+ LOGDEBUG(0,("WOW32: RemoveProcessSharedList failed to map in shared wow memory\n") );
+ return;
+ }
+
+ lpspPrev = NULL;
+ dwCurrentId = GetCurrentThreadId();
+ dwOffset = lpstm->dwFirstProcess;
+
+ while( dwOffset != 0 ) {
+ lpsp = (LPSHAREDPROCESS)((CHAR *)lpstm + dwOffset);
+ WOW32ASSERT(lpsp->dwType == SMO_PROCESS);
+
+ // Is this the guy to remove?
+
+ if ( lpsp->dwProcessId == dwCurrentId ) {
+ if ( lpspPrev ) {
+ lpspPrev->dwNextProcess = lpsp->dwNextProcess;
+ } else {
+ lpstm->dwFirstProcess = lpsp->dwNextProcess;
+ }
+ lpsp->dwType = SMO_AVAILABLE;
+ break;
+ }
+ lpspPrev = lpsp;
+ dwOffset = lpsp->dwNextProcess;
+ }
+
+ UNLOCKSHAREWOW();
+}
+
+//
+// AddTaskSharedList
+//
+// Add this thread to the shared memory list of wow tasks.
+// If hMod16 is zero, this call is to reserve the given
+// htask, another call will come later to really add the
+// task entry.
+//
+// When reserving an htask, a return of 0 means the htask
+// is in use in another VDM, a nonzero return means either
+// the shared memory is full or couldn't be accessed OR
+// the htask was reserved. This way the return is passed
+// directly back to krnl386's task.asm where 0 means try
+// again and nonzero means go with it.
+//
+
+WORD
+AddTaskSharedList(
+ HTASK16 hTask16,
+ HAND16 hMod16,
+ PSZ pszModName,
+ PSZ pszFilePath
+) {
+ LPSHAREDTASKMEM lpstm;
+ LPSHAREDPROCESS lpsp;
+ LPSHAREDTASK lpst;
+ LPSHAREDMEMOBJECT lpsmo;
+ INT count;
+ INT len;
+ WORD wRet;
+
+ lpstm = LOCKSHAREWOW();
+ if ( !lpstm ) {
+ LOGDEBUG(0,("WOW32: AddTaskSharedList failed to map in shared wow memory\n") );
+ wRet = hTask16;
+ goto Exit;
+ }
+
+ lpsp = (LPSHAREDPROCESS)((CHAR *)lpstm + dwSharedProcessOffset);
+
+ //
+ // Scan to see if this htask is already in use.
+ //
+
+ lpsmo = (LPSHAREDMEMOBJECT)((CHAR *)lpstm + sizeof(SHAREDTASKMEM));
+ count = 0;
+ while ( count < MAX_SHARED_OBJECTS ) {
+ if ( lpsmo->dwType == SMO_TASK ) {
+ lpst = (LPSHAREDTASK)lpsmo;
+ if (lpst->hTask16 == hTask16) {
+
+ //
+ // This htask is already in the table, if we're calling to fill in the
+ // details that's fine, if we are calling to reserve fail the call,
+ //
+
+ if (hMod16) {
+
+ lpst->dwThreadId = GetCurrentThreadId();
+ lpst->hMod16 = (WORD)hMod16;
+
+ strcpy(lpst->szModName, pszModName);
+
+ len = strlen(pszFilePath);
+ WOW32ASSERTMSGF(len <= (sizeof lpst->szFilePath) - 1,
+ ("WOW32: too-long EXE path truncated in shared memory: '%s'\n", pszFilePath));
+ len = min(len, (sizeof lpst->szFilePath) - 1);
+ RtlCopyMemory(lpst->szFilePath, pszFilePath, len);
+ lpst->szFilePath[len] = 0;
+
+ wRet = hTask16;
+ } else {
+ wRet = 0;
+ }
+ goto UnlockExit;
+ }
+ }
+ lpsmo++;
+ count++;
+ }
+
+ //
+ // We didn't find this htask, scan for available slot.
+ //
+
+ lpsmo = (LPSHAREDMEMOBJECT)((CHAR *)lpstm + sizeof(SHAREDTASKMEM));
+ count = 0;
+ while ( count < MAX_SHARED_OBJECTS ) {
+ if ( lpsmo->dwType == SMO_AVAILABLE ) {
+ lpst = (LPSHAREDTASK)lpsmo;
+ lpst->dwType = SMO_TASK;
+ lpst->hTask16 = (WORD)hTask16;
+ lpst->dwThreadId = 0;
+ lpst->hMod16 = 0;
+ lpst->szModName[0] = 0;
+ lpst->szFilePath[0] = 0;
+ lpst->dwNextTask = lpsp->dwFirstTask;
+ lpsp->dwFirstTask = (DWORD)((CHAR *)lpst - (CHAR *)lpstm);
+ break;
+ }
+ lpsmo++;
+ count++;
+ }
+ if ( count == MAX_SHARED_OBJECTS ) {
+ LOGDEBUG(0, ("WOW32: AddTaskSharedList: Not enough room in WOW's Shared Memory\n") );
+ }
+
+ wRet = hTask16;
+
+UnlockExit:
+ UNLOCKSHAREWOW();
+Exit:
+ return wRet;
+}
+
+
+//
+// Remove this thread from the shared memory list of wow tasks
+//
+VOID
+RemoveTaskSharedList(
+ VOID
+) {
+ LPSHAREDTASKMEM lpstm;
+ LPSHAREDPROCESS lpsp;
+ LPSHAREDTASK lpst;
+ LPSHAREDTASK lpstPrev;
+ DWORD dwCurrentId;
+ DWORD dwOffset;
+
+ lpstm = LOCKSHAREWOW();
+ if ( !lpstm ) {
+ LOGDEBUG(0,("WOW32: RemoveTaskSharedList failed to map in shared wow memory\n") );
+ return;
+ }
+
+ lpsp = (LPSHAREDPROCESS)((CHAR *)lpstm + dwSharedProcessOffset);
+
+ lpstPrev = NULL;
+ dwCurrentId = GetCurrentThreadId();
+ dwOffset = lpsp->dwFirstTask;
+
+ while( dwOffset != 0 ) {
+ lpst = (LPSHAREDTASK)((CHAR *)lpstm + dwOffset);
+
+ WOW32ASSERT(lpst->dwType == SMO_TASK);
+
+ // Is this the guy to remove?
+
+ if ( lpst->dwThreadId == dwCurrentId ) {
+ if ( lpstPrev ) {
+ lpstPrev->dwNextTask = lpst->dwNextTask;
+ } else {
+ lpsp->dwFirstTask = lpst->dwNextTask;
+ }
+ lpst->dwType = SMO_AVAILABLE;
+ break;
+ }
+ lpstPrev = lpst;
+ dwOffset = lpst->dwNextTask;
+ }
+
+ UNLOCKSHAREWOW();
+}
+
+
+VOID W32RefreshCurrentDirectories (PCHAR lpszzEnv)
+{
+LPSTR lpszVal;
+CHAR chDrive, achEnvDrive[] = "=?:";
+
+ if (lpszzEnv) {
+ while(*lpszzEnv) {
+ if(*lpszzEnv == '=' &&
+ (chDrive = toupper(*(lpszzEnv+1))) >= 'A' &&
+ chDrive <= 'Z' &&
+ (*(PCHAR)((ULONG)lpszzEnv+2) == ':')) {
+ lpszVal = (PCHAR)((ULONG)lpszzEnv + 4);
+ achEnvDrive[1] = chDrive;
+ SetEnvironmentVariable (achEnvDrive,lpszVal);
+ }
+ lpszzEnv = strchr(lpszzEnv,'\0');
+ lpszzEnv++;
+ }
+ *(PUCHAR)DosWowData.lpSCS_ToSync = (UCHAR)0xff;
+ }
+}
+
+
+/* WK32CheckUserGdi - hack routine to support Simcity. See the explanation
+ * in kernel31\3ginterf.asm routine HackCheck.
+ *
+ *
+ * Entry - pszPath Full Path of the file in the module table
+ *
+ * Exit
+ * SUCCESS
+ * 1
+ *
+ * FAILURE
+ * 0
+ *
+ */
+
+ULONG FASTCALL WK32CheckUserGdi(PVDMFRAME pFrame)
+{
+ PWOWCHECKUSERGDI16 parg16;
+ PSTR psz;
+ CHAR szPath[MAX_PATH+10];
+ UINT cb;
+ ULONG ul;
+
+ //
+ // Get arguments.
+ //
+
+ GETARGPTR(pFrame, sizeof(WOWCHECKUSERGDI16), parg16);
+ psz = SEGPTR(FETCHWORD(parg16->pszPathSegment),
+ FETCHWORD(parg16->pszPathOffset));
+
+ FREEARGPTR(parg16);
+
+ strcpy(szPath, pszSystemDirectory);
+ cb = strlen(szPath);
+
+ strcpy(szPath + cb, "\\GDI.EXE");
+
+ if (_stricmp(szPath, psz) == 0)
+ goto Success;
+
+ strcpy(szPath + cb, "\\USER.EXE");
+
+ if (_stricmp(szPath, psz) == 0)
+ goto Success;
+
+ ul = 0;
+ goto Done;
+
+Success:
+ ul = 1;
+
+Done:
+ return ul;
+}
+
+
+
+/* WK32ExitKernel - Force the Distruction of the WOW Process
+ * Formerly known as WK32KillProcess.
+ *
+ * Called when the 16 bit kernel exits and by KillWOW and
+ * checked WOWExec when the user wants to nuke the shared WOW.
+ *
+ * ENTRY
+ *
+ *
+ * EXIT
+ * Never Returns - The Process Goes Away
+ *
+ */
+
+ULONG FASTCALL WK32ExitKernel(PVDMFRAME pFrame)
+{
+ PEXITKERNEL16 parg16;
+
+ GETARGPTR(pFrame, sizeof(*parg16), parg16);
+
+ WOW32ASSERTMSG(
+ ! parg16->wExitCode,
+ "\n"
+ "WOW ERROR: ExitKernel called on 16-bit side with nonzero argument.\n"
+ "========== Please contact DaveHart or another WOW developer.\n"
+ "\n\n"
+ );
+
+ ExitVDM(WOWVDM, ALL_TASKS);
+ ExitProcess(parg16->wExitCode);
+
+ return 0; // Never executed, here to avoid compiler warning.
+}
+
+
+
+
+
+/* WK32FatalExit - Called as FatalExitThunk by kernel16 FatalExit
+ *
+ *
+ * parg16->f1 is FatalExit code
+ *
+ */
+
+ULONG FASTCALL WK32FatalExit(PVDMFRAME pFrame)
+{
+ PFATALEXIT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(*parg16), parg16);
+
+ WOW32ASSERTMSGF(
+ FALSE,
+ ("\n"
+ "WOW ERROR: FatalExit(0x%x) called by 16-bit WOW kernel.\n"
+ "========== Contact DaveHart or the doswow alias.\n"
+ "\n\n",
+ FETCHWORD(parg16->f1)
+ ));
+
+ // Sometimes we get this with no harm done (app bug)
+
+ ExitVDM(WOWVDM, ALL_TASKS);
+ ExitProcess(parg16->f1);
+
+ return 0; // Never executed, here to avoid compiler warning.
+}
+
+
+//
+// WowPartyByNumber is present on checked builds only as a convenience
+// to WOW developers who need a quick, temporary thunk for debugging.
+// The checked wowexec.exe has a menu item, Party By Number, which
+// collects a number and string parameter and calls this thunk.
+//
+
+#ifdef DEBUG
+
+ULONG FASTCALL WK32WowPartyByNumber(PVDMFRAME pFrame)
+{
+ PWOWPARTYBYNUMBER16 parg16;
+ PSZ psz;
+ ULONG ulRet = 0;
+
+ GETARGPTR(pFrame, sizeof(*parg16), parg16);
+ GETPSZPTR(parg16->psz, psz);
+
+ switch (parg16->dw) {
+
+ case 0: // Access violation
+ *(char *)0xa0000000 = 0;
+ break;
+
+ case 1: // Stack overflow
+ {
+ char EatStack[2048];
+
+ strcpy(EatStack, psz);
+ WK32WowPartyByNumber(pFrame);
+ strcpy(EatStack, psz);
+ }
+ break;
+
+ case 2: // Datatype misalignment
+ {
+ DWORD adw[2];
+ PDWORD pdw = (void *)((char *)adw + 2);
+
+ *pdw = (DWORD)-1;
+
+ //
+ // On some platforms the above will just work (hardware or
+ // emulation), so we force it with RaiseException.
+ //
+ RaiseException((DWORD)EXCEPTION_DATATYPE_MISALIGNMENT,
+ 0, 0, NULL);
+ }
+ break;
+
+ case 3: // Integer divide by zero
+ ulRet = 1 / (parg16->dw - 3);
+ break;
+
+ case 4: // Other exception
+ RaiseException((DWORD)EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
+ EXCEPTION_NONCONTINUABLE, 0, NULL);
+ break;
+
+ default:
+ {
+ char szMsg[255];
+
+ wsprintf(szMsg, "WOW Unhandled Party By Number (%d, '%s')", parg16->dw, psz);
+
+ MessageBeep(0);
+ MessageBox(NULL, szMsg, "WK32WowPartyByNumber", MB_OK | MB_ICONEXCLAMATION);
+ }
+ }
+
+ FREEPSZPTR(psz);
+ FREEARGPTR(parg16);
+ return ulRet;
+}
+
+#endif
+
+
+//
+// MyVerQueryValue checks several popular code page values for the given
+// string. This may need to be extended ala WinFile's wfdlgs2.c to search
+// the translation table. For now we only need a few.
+//
+
+BOOL
+FASTCALL
+MyVerQueryValue(
+ const LPVOID pBlock,
+ LPSTR lpName,
+ LPVOID * lplpBuffer,
+ PUINT puLen
+ )
+{
+#define SFILEN 25 // Length of apszSFI strings without null
+ static PSZ apszSFI[] = {
+ "\\StringFileInfo\\040904E4\\",
+ "\\StringFileInfo\\04090000\\"
+ };
+ char szSubBlock[128];
+ BOOL fRet;
+ int i;
+
+ strcpy(szSubBlock+SFILEN, lpName);
+
+ for (fRet = FALSE, i = 0;
+ i < (sizeof apszSFI / sizeof apszSFI[0]) && !fRet;
+ i++) {
+
+ RtlCopyMemory(szSubBlock, apszSFI[i], SFILEN);
+ fRet = VerQueryValue(pBlock, szSubBlock, lplpBuffer, puLen);
+ }
+
+ return fRet;
+}
+
+
+//
+// Utility routine to fetch the Product Name and Product Version strings
+// from a given EXE.
+//
+
+BOOL
+FASTCALL
+WowGetProductNameVersion(
+ PSZ pszExePath,
+ PSZ pszProductName,
+ DWORD cbProductName,
+ PSZ pszProductVersion,
+ DWORD cbProductVersion
+ )
+{
+ DWORD dwZeroMePlease;
+ DWORD cbVerInfo;
+ LPVOID lpVerInfo = NULL;
+ LPSTR pName;
+ DWORD cbName;
+ LPSTR pVersion;
+ DWORD cbVersion;
+ BOOL fRet;
+
+ fRet = (
+ (cbVerInfo = GetFileVersionInfoSize(pszExePath, &dwZeroMePlease)) &&
+ (lpVerInfo = malloc_w(cbVerInfo)) &&
+ GetFileVersionInfo(pszExePath, 0, cbVerInfo, lpVerInfo) &&
+ MyVerQueryValue(lpVerInfo, "ProductName", &pName, &cbName) &&
+ cbName <= cbProductName &&
+ MyVerQueryValue(lpVerInfo, "ProductVersion", &pVersion, &cbVersion) &&
+ cbVersion <= cbProductVersion
+ );
+
+ if (fRet) {
+ strcpy(pszProductName, pName);
+ strcpy(pszProductVersion, pVersion);
+ }
+
+ if (lpVerInfo) {
+ free_w(lpVerInfo);
+ }
+
+ return fRet;
+}
+
+//
+// This routine is simpler to use if you are doing an exact match
+// against a particular name/version pair.
+//
+
+BOOL
+FASTCALL
+WowDoNameVersionMatch(
+ PSZ pszExePath,
+ PSZ pszProductName,
+ PSZ pszProductVersion
+ )
+{
+ DWORD dwJunk;
+ DWORD cbVerInfo;
+ LPVOID lpVerInfo = NULL;
+ LPSTR pName;
+ LPSTR pVersion;
+ BOOL fRet;
+
+ fRet = (
+ (cbVerInfo = GetFileVersionInfoSize(pszExePath, &dwJunk)) &&
+ (lpVerInfo = malloc_w(cbVerInfo)) &&
+ GetFileVersionInfo(pszExePath, 0, cbVerInfo, lpVerInfo) &&
+ MyVerQueryValue(lpVerInfo, "ProductName", &pName, &dwJunk) &&
+ ! _stricmp(pszProductName, pName) &&
+ MyVerQueryValue(lpVerInfo, "ProductVersion", &pVersion, &dwJunk) &&
+ ! _stricmp(pszProductVersion, pVersion)
+ );
+
+ if (lpVerInfo) {
+ free_w(lpVerInfo);
+ }
+
+ return fRet;
+}
+
+
+//
+// WowShouldWeSayWin95 is called by 16-bit GetVersion when the caller's
+// has WOWCFEX_GETVERSIONHACK. GetVersion passes us the fully qualified path
+// to the EXE.
+//
+// This routine returns zero if the true (Win 3.1) version should be
+// returned, or it returns in the low word the value to be returned
+// in the low word from GetVersion.
+//
+// We look at the version resources of that EXE to see
+// if it's InstallSHIELD build 3.00.087.0 or earlier. If it is, we
+// lie and tell them the 16-bit Windows version is 3.95. We do this
+// because prior to build 3.00.088.0 of InstallSHIELD, the logic for
+// detecting a newshell (explorer) system was to check if the 16-bit
+// Windows version was 3.95, as it is for Win95. Thanks to Samir Metha
+// (samir@installshield.com), newer versions of InstallSHIELD work on
+// NT 4.0 without this hack. -- DaveHart
+//
+// Extended to allow Netscape PowerPack 1.0's SmartMarks setup to
+// get version 3.95 as well. Lovely. -- DaveHart 15-Nov-95
+//
+// Generalized to do different things based on module name, added
+// support for MS Ancient Lands, MS Dangerous Creatures, MS Complete
+// NBA Basketball 1994, and MS Complete Baseball 1995. Moved some
+// version resource code to worker routines above. -- DaveHart 8-Feb-96
+//
+
+ULONG FASTCALL WK32WowShouldWeSayWin95(PVDMFRAME pFrame)
+{
+ PWOWSHOULDWESAYWIN9516 parg16;
+ PSZ pszFilename;
+ ULONG ulRet = 0;
+ CHAR szModName[9];
+ PSZ pch;
+ static WORD wLastCallerDS = 0; // One entry cache.
+ static ULONG ulLastRet = 0;
+
+
+ GETARGPTR(pFrame, sizeof(*parg16), parg16);
+ GETPSZPTR(parg16->pszFilename, pszFilename);
+
+ //
+ // Our decision is based on calling module, so if this call
+ // is from the same module (as indicated by DS) as the last,
+ // we can return the same value as last time.
+ //
+
+ if (wLastCallerDS == parg16->wCallerDS) {
+ LOGDEBUG(LOG_WARNING,
+ ("WowShouldWeSayWin95 returning cached value 0x%x for DS %x",
+ ulLastRet, parg16->wCallerDS));
+ ulRet = ulLastRet;
+ goto Cleanup;
+ }
+
+ RtlCopyMemory(szModName, ((PTDB)SEGPTR(pFrame->wTDB,0))->TDB_ModName, 8);
+ szModName[8] = 0;
+ pch = &szModName[8];
+ while (*(--pch) == ' ') {
+ *pch = 0;
+ }
+
+ LOGDEBUG(LOG_WARNING,
+ ("WowShouldWeSayWin95 DS %x modname '%s' filename '%s'\n",
+ parg16->wCallerDS, szModName, pszFilename));
+
+ if (!strcmp(szModName, "ISSET_SE")) { // InstallShield setup kit
+
+ CHAR szName[16];
+ CHAR szVersion[16];
+ CHAR szVerSubstring[4];
+ DWORD dwSubVer;
+
+ if (! WowGetProductNameVersion(pszFilename, szName, sizeof szName,
+ szVersion, sizeof szVersion) ||
+ _stricmp(szName, "InstallSHIELD")) {
+
+ //
+ // Couldn't find version info
+ //
+
+ goto BeHonest;
+ }
+
+ //
+ // InstallShield _Setup SDK_ setup.exe shipped
+ // with VC++ 4.0 is stamped 2.20.903.0 but also
+ // needs to be lied to about it being Win95.
+ // According to samir@installshield.com versions
+ // 2.20.903.0 through 2.20.905.0 need this.
+ // We'll settle for 2.20.903* - 2.20.905*
+ // These are based on the 3.0 codebase but
+ // bear the 2.20.x version stamps.
+ //
+
+ if (RtlEqualMemory(szVersion, "2.20.90", 7) &&
+ ('3' == szVersion[7] ||
+ '4' == szVersion[7] ||
+ '5' == szVersion[7]) ) {
+
+ goto SayWin95;
+ }
+
+ //
+ // We want to lie in GetVersion if the version stamp on
+ // the InstallShield setup.exe is 3.00.xxx.0, where
+ // xxx is 000 through 087. Later versions know how
+ // to detect NT.
+ //
+
+ if (! RtlEqualMemory(szVersion, "3.00.", 5)) {
+
+ goto BeHonest;
+ }
+
+ RtlCopyMemory(szVerSubstring, &szVersion[5], 3);
+ szVerSubstring[3] = 0;
+ RtlCharToInteger(szVerSubstring, 10, &dwSubVer);
+
+ if (dwSubVer >= 88) {
+ goto BeHonest;
+ } else {
+ goto SayWin95;
+ }
+
+ } else if (!strcmp(szModName, "NCSETUP")) { // NetScape SmartMarks setup
+
+ //
+ // Check if it's Netscape PowerPack 1.0 setup by comparing
+ // the date and time with the faulty 1.0 version timestamps.
+ // Unfortunately there are no version stamps on this program.
+ // Fortunately the beta PowerPack 2.0/SmartMarks 2.0 has fixed
+ // the bug and doesn't need this hack.
+ //
+
+ HANDLE hfile;
+ FILETIME ftThisFile;
+
+ hfile = CreateFile(
+ pszFilename,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ 0
+ );
+
+ if (hfile) {
+
+ GetFileTime(hfile, NULL, NULL, &ftThisFile);
+ CloseHandle(hfile);
+
+ //
+ // The SmartMarks setup.exe included on the
+ // PowerPack 1.0 CD and downloadable from
+ // Netscape as SM10R2.EXE
+ // has the timestamp hard-coded below. The
+ // developers (actually at firstfloor.com)
+ // assure me that this is the only faulty
+ // version out there.
+ //
+ // The values below equate to 1-Sep-95 2:00:20pm
+ //
+
+ if (ftThisFile.dwHighDateTime == 0x1ba78ad &&
+ ftThisFile.dwLowDateTime == 0xf28b4a00) {
+
+ goto SayWin95;
+
+ }
+
+ }
+
+ goto BeHonest;
+
+ } else if (!strcmp(szModName, "EXPLORE")) { // MS Ancient Lands and
+ // Dangerous Creatures
+ if (WowDoNameVersionMatch(
+ pszFilename,
+ "Microsoft Exploration Series",
+ "1.0")) {
+
+ goto SayWin95;
+ } else {
+ goto BeHonest;
+ }
+
+ } else if (!strcmp(szModName, "BBALL")) { // MS Complete NBA Basketball 1994
+ // MS Complete Baseball 1995
+ if (WowDoNameVersionMatch(
+ pszFilename,
+ "Microsoft Complete NBA Basketball",
+ "1994") ||
+ WowDoNameVersionMatch(
+ pszFilename,
+ "Microsoft Complete Baseball",
+ "1995")) {
+
+ goto SayWin95;
+ } else {
+ goto BeHonest;
+ }
+
+ } else {
+
+ DWORD flOptionsSave;
+
+ //
+ // Since this hack has potential to break apps that depend on Win95 16-bit
+ // functionality we don't provide, specific version checks are included for
+ // the module names above. If you add the WOWCFEX_GETVERSIONHACK bit to
+ // the compatibility section for a new module name, you should also add
+ // a version check or other mechanism to be sure that only the intended
+ // app gets the hacked version returned.
+ //
+
+ flOptionsSave = flOptions;
+ flOptions |= OPT_DEBUG;
+ LOGDEBUG(LOG_ALWAYS, ("Should add version-resource checking to WK32WowShouldWeSayWin95 for %s.\n", szModName));
+ flOptions = flOptionsSave;
+ goto SayWin95;
+ }
+
+SayWin95:
+ ulRet = 0x5f03; // 3.95
+
+BeHonest:
+ wLastCallerDS = parg16->wCallerDS;
+ ulLastRet = ulRet;
+
+ LOGDEBUG(LOG_WARNING, ("WowShouldWeSayWin95 returning %x.\n", ulRet));
+
+Cleanup:
+ FREEPSZPTR(pszFilename);
+ FREEARGPTR(parg16);
+
+ return ulRet;
+}
+
+
+//
+// GetVersionEx is exported from the 16-bit kernel of Win95 for
+// convenience of 16-bit setup programs. It is simply a Win16
+// wrapper for the Win32 GetVersionEx.
+//
+
+ULONG FASTCALL WK32GetVersionEx(PVDMFRAME pFrame)
+{
+ PGETVERSIONEX16 parg16;
+ POSVERSIONINFO posvi;
+ ULONG ulRet;
+
+ GETARGPTR(pFrame, sizeof(*parg16), parg16);
+ GETMISCPTR(parg16->lpVersionInfo, posvi);
+
+ ulRet = GetVersionEx(posvi);
+
+ FREEMISCPTR(posvi);
+ FREEARGPTR(parg16);
+
+ return ulRet;
+}
+
+
+//
+// This thunk is called by kernel31's GetModuleHandle
+// when it cannot find a handle for given filename.
+//
+// We look to see if this task has any child apps
+// spawned via WinOldAp, and if so we look to see
+// if the module name matches for any of them.
+// If it does, we return the hmodule of the
+// associated WinOldAp. Otherwise we return 0
+//
+
+ULONG FASTCALL WK32WowGetModuleHandle(PVDMFRAME pFrame)
+{
+ PWOWGETMODULEHANDLE16 parg16;
+ ULONG ul;
+ PSZ pszModuleName;
+ PTD ptd;
+ PWOAINST pWOA;
+
+ GETARGPTR(pFrame, sizeof(*parg16), parg16);
+ GETPSZPTR(parg16->lpszModuleName, pszModuleName);
+
+ ptd = CURRENTPTD();
+ pWOA = ptd->pWOAList;
+ while (pWOA && strcmp(pszModuleName, pWOA->szModuleName)) {
+ pWOA = pWOA->pNext;
+ }
+
+ if (pWOA && pWOA->ptdWOA) {
+ ul = pWOA->ptdWOA->hMod16;
+ LOGDEBUG(LOG_ALWAYS, ("WK32WowGetModuleHandle(%s) returning %04x.\n",
+ pszModuleName, ul));
+ } else {
+ ul = 0;
+ }
+
+ return ul;
+}
+
+
+//
+// GetShortPathName is exported from the 16-bit kernel on NT to
+// support booting WOW with a long-named windows directory.
+// It is simply a Win16 wrapper for the Win32 GetShortPathName.
+// It may well be found useful by 16-bit setup programs, although
+// so far no effort has been made to document it, or for that
+// matter GetVersionEx, which at least exists in the same form
+// on Win95.
+//
+// -- DaveHart 15-Feb-96
+//
+
+ULONG FASTCALL WK32GetShortPathName(PVDMFRAME pFrame)
+{
+ PGETSHORTPATHNAME16 parg16;
+ PSZ pszLongPath, pszShortPath;
+ ULONG ul;
+
+ GETARGPTR(pFrame, sizeof(*parg16), parg16);
+ GETPSZPTR(parg16->pszLongPath, pszLongPath);
+ if (parg16->pszShortPath == parg16->pszLongPath) {
+ pszShortPath = pszLongPath;
+ } else {
+ GETVDMPTR(parg16->pszShortPath, parg16->cchShortPath, pszShortPath);
+ }
+
+ ul = GetShortPathName(pszLongPath, pszShortPath, parg16->cchShortPath);
+
+ FLUSHVDMPTR(parg16->pszShortPath, ul+1, pszShortPath);
+
+ FREEVDMPTR(pszShortPath); // Safe even if no GETVDMPTR
+ FREEPSZPTR(pszLongPath);
+ FREEARGPTR(parg16);
+
+ return ul;
+}
+
+//
+// This function is called by kernel31's CreateTask after it's
+// allocated memory for the TDB, the selector of which serves
+// as the htask. We want to enforce uniqueness of these htasks
+// across all WOW VDMs in the system, so this function attempts
+// to reserve the given htask in the shared memory structure.
+// If successful the htask is returned, if it's already in use
+// 0 is returned and CreateTask will allocate another selector
+// and try again.
+//
+// -- DaveHart 24-Apr-96
+//
+
+ULONG FASTCALL WK32WowReserveHtask(PVDMFRAME pFrame)
+{
+ PWOWRESERVEHTASK16 parg16;
+ ULONG ul;
+
+ GETARGPTR(pFrame, sizeof(*parg16), parg16);
+
+ ul = AddTaskSharedList(parg16->htask, 0, NULL, NULL);
+
+ FREEARGPTR(parg16);
+
+ return ul;
+}
diff --git a/private/mvdm/wow32/wkman.h b/private/mvdm/wow32/wkman.h
new file mode 100644
index 000000000..11a3aee0c
--- /dev/null
+++ b/private/mvdm/wow32/wkman.h
@@ -0,0 +1,140 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKMAN.H
+ * WOW32 16-bit Kernel API support (manually-coded thunks)
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * 30-Apr-91 mattfe added WK32CheckLoadModuleDrv
+ * 26-Aug-91 mattfe added FileIO routines
+ * 19-JAN-92 mattfe added getnextvdm routine
+ * 4-MAR-92 mattfe added KillProcess
+ * 12-mar-92 mattfe added w32notifythread
+ * 5-may-92 mattfe added HungAppSupport
+--*/
+
+ULONG FASTCALL WK32DirectedYield(PVDMFRAME pFrame);
+ULONG FASTCALL WK32InitTask(PVDMFRAME pFrame);
+ULONG FASTCALL WK32KernelTrace(PVDMFRAME pFrame);
+ULONG FASTCALL WK32ExitKernel(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FatalExit(PVDMFRAME pFrame);
+VOID FASTCALL WK32KillRemoteTask(PVDMFRAME pFrame);
+VOID FASTCALL WK32KillTask(PVDMFRAME pFrame);
+ULONG FASTCALL WK32LoadModule32(PVDMFRAME pFrame);
+ULONG FASTCALL WK32RegisterShellWindowHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WOWInitTask(PVDMFRAME pFrame);
+VOID FASTCALL WK32WOWNotifyWOW32(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WOWOutputDebugString(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WOWQueryPerformanceCounter(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WaitEvent(PVDMFRAME pFrame);
+VOID FASTCALL WK32WowCloseComPort(PVDMFRAME pFrame);
+DWORD FASTCALL WK32WowDelFile(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WowFailedExec(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WowFailedExec(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WowGetNextVdmCommand (PVDMFRAME pFrame);
+ULONG FASTCALL WK32WowIsKnownDLL(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WowSetIdleHook(PVDMFRAME pFrame);
+ULONG FASTCALL WK32Yield(PVDMFRAME pFrame);
+ULONG FASTCALL WK32OldYield(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WowWaitForMsgAndEvent(PVDMFRAME pFrame);
+VOID FASTCALL WK32WowMsgBox(PVDMFRAME pFrame);
+ULONG FASTCALL WK32DosWowInit(PVDMFRAME pFrame);
+ULONG FASTCALL WK32CheckUserGdi(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WowPartyByNumber(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WowShouldWeSayWin95(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetVersionEx(PVDMFRAME pFrame);
+ULONG FASTCALL WK32WowGetModuleHandle(PVDMFRAME pFrame);
+ULONG FASTCALL WK32GetShortPathName(PVDMFRAME pFrame);
+ULONG FASTCALL WK32FindAndReleaseDib(PVDMFRAME pvf); /* in wdib.c */
+ULONG FASTCALL WK32WowReserveHtask(PVDMFRAME pFrame);
+
+
+BOOL WK32InitializeHungAppSupport(VOID);
+DWORD W32HungAppNotifyThread(UINT hKillUniqueID);
+DWORD W32RemoteThread(VOID);
+DWORD W32Thread(LPVOID vpInitialSSSP);
+VOID W32DestroyTask( PTD ptd);
+VOID W32EndTask(VOID);
+ULONG W32GetAppCompatFlags(HTASK16 hTask16);
+ULONG W32ReadWOWCompatFlags(HTASK16 htask16, DWORD *pdwWOWXCompatFlagsEx);
+VOID WK32DeleteTask(PTD ptdDelete);
+VOID WK32InitWowIsKnownDLL(HANDLE hKeyWow);
+LRESULT CALLBACK WK32ForegroundIdleHook(int code, WPARAM wParam, LPARAM lParam);
+VOID W32RefreshCurrentDirectories (PCHAR lpszzEnv);
+BOOL FASTCALL WowGetProductNameVersion(PSZ pszExePath, PSZ pszProductName,
+ DWORD cbProductName, PSZ pszProductVersion,
+ DWORD cbProductVersion);
+BOOL FASTCALL WowDoNameVersionMatch(PSZ pszExePath, PSZ pszProductName,
+ PSZ pszProductVersion);
+
+VOID W32InitWOWSetupNames(VOID);
+BOOL W32IsSetupProgram(PSZ pszModName, PSZ pszFilePath);
+
+// SoftPC Routines
+HANDLE RegisterWOWIdle(void);
+VOID BlockWOWIdle(BOOL Blocking);
+
+// User32 Routines
+VOID ShowStartGlass (DWORD GLASSTIME);
+
+typedef struct _HMODCACHE { /* hmodcache */
+ HAND16 hInst16;
+ HAND16 hMod16;
+} HMODCACHE, *PHMODCACHE;
+
+extern HMODCACHE ghModCache[];
+#define CHMODCACHE 4 // size of cache table
+
+VOID RemoveHmodFromCache(HAND16 hmod16);
+
+typedef struct _CMDSHOW { /* cmdshow */
+ WORD nTwo;
+ WORD nCmdShow;
+} CMDSHOW, *PCMDSHOW;
+
+typedef struct _LOAD_MODULE_PARAMS { /* loadmoduleparms32 */
+ LPVOID lpEnvAddress;
+ LPSTR lpCmdLine;
+ PCMDSHOW lpCmdShow;
+ DWORD dwReserved;
+} LOAD_MODULE_PARAMS, *PLOAD_MODULE_PARAMS;
+
+typedef struct _WINOLDAP_THREAD_PARAMS {
+ HANDLE hProcess;
+ HWND hwndWinOldAp;
+} WINOLDAP_THREAD_PARAMS, *PWINOLDAP_THREAD_PARAMS;
+
+DWORD W32WinOldApThread(PWINOLDAP_THREAD_PARAMS pParams);
+
+// Globals
+
+extern INT busycount; // Used to detect if WOW is hung
+extern HAND16 gKillTaskID; // 16 bit tdb of task to kill
+extern HAND16 ghShellTDB; // TDB of WOWEXEC
+extern HWND ghwndShell; // Needed for ExitWindowsExec
+
+#define CMS_WAITWOWEXECTIMEOUT 60*1000 // Wait for WOWEXEC to respond
+#define CMS_WAITTASKEXIT 5*1000 // Hung App Wait TimeOut
+#define CMS_FOREVER 0xffffffff // wait for ever
+#define ALL_TASKS 0xffffffff // for exitvdm
+
+// IRQ: Interrupt: ICA: Line: Description:
+// -------------------------------------------------------------------
+// IRQ1 0x09 0 1 Keyboard service required.
+#define KEYBOARD_LINE 1
+#define KEYBOARD_ICA 0
+
+extern HANDLE hSharedTaskMemory;
+extern DWORD dwSharedProcessOffset;
+extern VPVOID vpDebugWOW;
+extern VPVOID vptopPDB;
+
+VOID CleanseSharedList( VOID );
+VOID AddProcessSharedList( VOID );
+VOID RemoveProcessSharedList( VOID );
+WORD AddTaskSharedList( HTASK16, HAND16, PSZ, PSZ );
+VOID RemoveTaskSharedList( VOID );
diff --git a/private/mvdm/wow32/wkmem.c b/private/mvdm/wow32/wkmem.c
new file mode 100644
index 000000000..351a4dba2
--- /dev/null
+++ b/private/mvdm/wow32/wkmem.c
@@ -0,0 +1,170 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1992, Microsoft Corporation
+ *
+ * WKMEM.C
+ * WOW32 KRNL386 Virtual Memory Management Functions
+ *
+ * History:
+ * Created 3-Dec-1992 by Matt Felton (mattfe)
+ *
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+#include "memapi.h"
+
+MODNAME(wkman.c);
+
+
+LPVOID FASTCALL WK32VirtualAlloc(PVDMFRAME pFrame)
+{
+ PVIRTUALALLOC16 parg16;
+ LPVOID lpBaseAddress;
+#ifndef i386
+ NTSTATUS Status;
+#endif
+
+ GETARGPTR(pFrame, sizeof(VIRTUALALLOC16), parg16);
+
+
+#ifndef i386
+ Status = VdmAllocateVirtualMemory((PULONG)&lpBaseAddress,
+ parg16->cbSize,
+ TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+
+ if (Status == STATUS_NOT_IMPLEMENTED) {
+#endif // i386
+
+ lpBaseAddress = VirtualAlloc((LPVOID)parg16->lpvAddress,
+ parg16->cbSize,
+ parg16->fdwAllocationType,
+ parg16->fdwProtect);
+
+
+#ifndef i386
+ } else {
+
+ lpBaseAddress = NULL;
+ }
+
+ }
+#endif // i386
+
+#ifdef i386
+//BUGBUG we need to either get this working on the new emulator, or
+// fix the problem the "other" way, by letting the app fault and
+// zap in just enough 'WOW's to avoid the problem.
+ if (lpBaseAddress) {
+ // Virtual alloc Zero's the allocated memory. We un-zero it by
+ // filling in with ' WOW'. This is required for Lotus Improv.
+ // When no printer is installed, Lotus Improv dies with divide
+ // by zero error (while opening the expenses.imp file) because
+ // it doesn't initialize a relevant portion of its data area.
+ //
+ // So we decided that this a convenient place to initialize
+ // the memory to a non-zero value.
+ // - Nanduri
+ //
+ // Dbase 5.0 for windows erroneously loops through (past its valid
+ // data) its data buffer till it finds a '\0' at some location -
+ // Most of the time the loop terminates before it reaches the segment
+ // limit. However if the block that was allocated is a 'fresh' block' ie
+ // the block is filled with ' WOW' it never finds a NULL in the buffer
+ // and thus loops past the segment limit to its death
+ //
+ // So we initialize the buffer with '\0WOW' instead of ' WOW'.
+ // - Nanduri
+
+ WOW32ASSERT((parg16->cbSize % 4) == 0); // DWORD aligned?
+ RtlFillMemoryUlong(lpBaseAddress, parg16->cbSize, (ULONG)'\0WOW');
+ }
+#endif
+
+ FREEARGPTR(parg16);
+ return (lpBaseAddress);
+}
+
+BOOL FASTCALL WK32VirtualFree(PVDMFRAME pFrame)
+{
+ PVIRTUALFREE16 parg16;
+ BOOL fResult;
+#ifndef i386
+ NTSTATUS Status;
+#endif
+
+ GETARGPTR(pFrame, sizeof(VIRTUALFREE16), parg16);
+
+#ifndef i386
+ Status = VdmFreeVirtualMemory((ULONG)parg16->lpvAddress);
+ fResult = NT_SUCCESS(Status);
+
+ if (Status == STATUS_NOT_IMPLEMENTED) {
+#endif // i386
+
+ fResult = VirtualFree((LPVOID)parg16->lpvAddress,
+ parg16->cbSize,
+ parg16->fdwFreeType);
+
+
+#ifndef i386
+ }
+#endif // i386
+
+ FREEARGPTR(parg16);
+ return (fResult);
+}
+
+
+#if 0
+BOOL FASTCALL WK32VirtualLock(PVDMFRAME pFrame)
+{
+ PVIRTUALLOCK16 parg16;
+ BOOL fResult;
+
+ WOW32ASSERT(FALSE); //BUGBUG we don't appear to ever use this function
+
+ GETARGPTR(pFrame, sizeof(VIRTUALLOCK16), parg16);
+
+ fResult = VirtualLock((LPVOID)parg16->lpvAddress,
+ parg16->cbSize);
+
+ FREEARGPTR(parg16);
+ return (fResult);
+}
+
+BOOL FASTCALL WK32VirtualUnLock(PVDMFRAME pFrame)
+{
+ PVIRTUALUNLOCK16 parg16;
+ BOOL fResult;
+
+ WOW32ASSERT(FALSE); //BUGBUG we don't appear to ever use this function
+
+ GETARGPTR(pFrame, sizeof(VIRTUALUNLOCK16), parg16);
+
+ fResult = VirtualUnlock((LPVOID)parg16->lpvAddress,
+ parg16->cbSize);
+
+ FREEARGPTR(parg16);
+ return (fResult);
+}
+#endif
+
+
+VOID FASTCALL WK32GlobalMemoryStatus(PVDMFRAME pFrame)
+{
+ PGLOBALMEMORYSTATUS16 parg16;
+ LPMEMORYSTATUS pMemStat;
+
+ GETARGPTR(pFrame, sizeof(GLOBALMEMORYSTATUS16), parg16);
+ GETVDMPTR(parg16->lpmstMemStat, 32, pMemStat);
+
+ GlobalMemoryStatus(pMemStat);
+
+ FREEVDMPTR(pMemStat);
+ FREEARGPTR(parg16);
+}
diff --git a/private/mvdm/wow32/wkmem.h b/private/mvdm/wow32/wkmem.h
new file mode 100644
index 000000000..6c3969838
--- /dev/null
+++ b/private/mvdm/wow32/wkmem.h
@@ -0,0 +1,20 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1992, Microsoft Corporation
+ *
+ * WKMEM.H
+ * WOW32 KRNL386 - Memory Management Functions
+ *
+ * History:
+ * Created 3-Dec-1992 by Matthew Felton (mattfe)
+--*/
+
+LPVOID FASTCALL WK32VirtualAlloc(PVDMFRAME pFrame);
+BOOL FASTCALL WK32VirtualFree(PVDMFRAME pFrame);
+#if 0
+BOOL FASTCALL WK32VirtualLock(PVDMFRAME pFrame);
+BOOL FASTCALL WK32VirtualUnLock(PVDMFRAME pFrame);
+#endif
+VOID FASTCALL WK32GlobalMemoryStatus(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wktbl.h b/private/mvdm/wow32/wktbl.h
new file mode 100644
index 000000000..b41bceb94
--- /dev/null
+++ b/private/mvdm/wow32/wktbl.h
@@ -0,0 +1,23 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKTBL.H
+ * WOW32 16-bit Kernel API tables
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* Kernel dispatch table
+ */
+extern W32 aw32Kernel[];
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iKernelMax;
+#endif
diff --git a/private/mvdm/wow32/wktbl2.h b/private/mvdm/wow32/wktbl2.h
new file mode 100644
index 000000000..bc1d6bafa
--- /dev/null
+++ b/private/mvdm/wow32/wktbl2.h
@@ -0,0 +1,383 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, 1992, 1993 Microsoft Corporation
+ *
+ * WKTBL2.h
+ * WOW32 kernel API thunks
+ *
+ * This file is included into the master thunk table.
+ *
+--*/
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_KERNEL, 0)},
+ {W32FUN(WK32FatalExit, "FATALEXIT", MOD_KERNEL, sizeof(FATALEXIT16))},
+ {W32FUN(WK32ExitKernel, "EXITKERNEL", MOD_KERNEL, sizeof(EXITKERNEL16))},
+ {W32FUN(LOCALAPI, "GETVERSION", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALINIT", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALALLOC", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALREALLOC", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALFREE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALLOCK", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALUNLOCK", MOD_KERNEL, 0)},
+
+ /*** 0010 ***/
+ {W32FUN(LOCALAPI, "LOCALSIZE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALHANDLE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALFLAGS", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALCOMPACT", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALNOTIFY", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALALLOC", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALREALLOC", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALFREE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALLOCK", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALUNLOCK", MOD_KERNEL, 0)},
+
+ /*** 0020 ***/
+ {W32FUN(LOCALAPI, "GLOBALSIZE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALHANDLE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALFLAGS", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCKSEGMENT", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "UNLOCKSEGMENT", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALCOMPACT", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GLOBALFREEALL", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GLOBALMASTERHANDLE", MOD_KERNEL, 0)},
+ {W32FUN(WK32Yield, "YIELD", MOD_KERNEL, 0)},
+
+ /*** 0030 ***/
+ {W32FUN(WK32WaitEvent, "WAITEVENT", MOD_KERNEL, sizeof(WAITEVENT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "POSTEVENT", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETPRIORITY", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOCKCURRENTTASK", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "SETTASKQUEUE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETTASKQUEUE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETCURRENTTASK", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETCURRENTPDB", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETTASKSIGNALPROC", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+
+ /*** 0040 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENABLEDOS", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DISABLEDOS", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOADMODULE", MOD_KERNEL, sizeof(LOADMODULE16))},
+ {W32FUN(LOCALAPI, "FREEMODULE", MOD_KERNEL, sizeof(FREEMODULE16))},
+ {W32FUN(WK32WowGetModuleHandle, "GETMODULEHANDLE", MOD_KERNEL, sizeof(WOWGETMODULEHANDLE16))},
+ {W32FUN(LOCALAPI, "GETMODULEUSAGE", MOD_KERNEL, sizeof(GETMODULEUSAGE16))},
+ {W32FUN(WK32GetModuleFileName, "GETMODULEFILENAME", MOD_KERNEL, sizeof(GETMODULEFILENAME16))},
+
+ /*** 0050 ***/
+ {W32FUN(LOCALAPI, "GETPROCADDRESS", MOD_KERNEL, sizeof(GETPROCADDRESS16))},
+ {W32FUN(LOCALAPI, "MAKEPROCINSTANCE", MOD_KERNEL, sizeof(MAKEPROCINSTANCE16))},
+ {W32FUN(LOCALAPI, "FREEPROCINSTANCE", MOD_KERNEL, sizeof(FREEPROCINSTANCE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "CALLPROCINSTANCE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETINSTANCEDATA", MOD_KERNEL, sizeof(GETINSTANCEDATA16))},
+ {W32FUN(LOCALAPI, "CATCH", MOD_KERNEL, sizeof(CATCH16))},
+ {W32FUN(LOCALAPI, "THROW", MOD_KERNEL, sizeof(THROW16))},
+ {W32FUN(WK32GetProfileInt, "GETPROFILEINT", MOD_KERNEL, sizeof(GETPROFILEINT16))},
+ {W32FUN(WK32GetProfileString, "GETPROFILESTRING", MOD_KERNEL, sizeof(GETPROFILESTRING16))},
+ {W32FUN(WK32WriteProfileString, "WRITEPROFILESTRING", MOD_KERNEL, sizeof(WRITEPROFILESTRING16))},
+
+ /*** 0060 ***/
+ {W32FUN(LOCALAPI, "FINDRESOURCE", MOD_KERNEL, sizeof(FINDRESOURCE16))},
+ {W32FUN(LOCALAPI, "LOADRESOURCE", MOD_KERNEL, sizeof(LOADRESOURCE16))},
+ {W32FUN(LOCALAPI, "LOCKRESOURCE", MOD_KERNEL, sizeof(LOCKRESOURCE16))},
+ {W32FUN(LOCALAPI, "FREERESOURCE", MOD_KERNEL, sizeof(FREERESOURCE16))},
+ {W32FUN(LOCALAPI, "ACCESSRESOURCE", MOD_KERNEL, sizeof(ACCESSRESOURCE16))},
+ {W32FUN(LOCALAPI, "SIZEOFRESOURCE", MOD_KERNEL, sizeof(SIZEOFRESOURCE16))},
+ {W32FUN(LOCALAPI, "ALLOCRESOURCE", MOD_KERNEL, sizeof(ALLOCRESOURCE16))},
+ {W32FUN(LOCALAPI, "SETRESOURCEHANDLER", MOD_KERNEL, sizeof(SETRESOURCEHANDLER16))},
+ {W32FUN(LOCALAPI, "INITATOMTABLE", MOD_KERNEL, sizeof(INITATOMTABLE16))},
+ {W32FUN(LOCALAPI, "FINDATOM", MOD_KERNEL, sizeof(FINDATOM16))},
+
+ /*** 0070 ***/
+ {W32FUN(LOCALAPI, "ADDATOM", MOD_KERNEL, sizeof(ADDATOM16))},
+ {W32FUN(LOCALAPI, "DELETEATOM", MOD_KERNEL, sizeof(DELETEATOM16))},
+ {W32FUN(LOCALAPI, "GETATOMNAME", MOD_KERNEL, sizeof(GETATOMNAME16))},
+ {W32FUN(LOCALAPI, "GETATOMHANDLE", MOD_KERNEL, sizeof(GETATOMHANDLE16))},
+ {W32FUN(LOCALAPI, "OPENFILE", MOD_KERNEL, sizeof(OPENFILE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "OPENPATHNAME", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DELETEPATHNAME", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "RESERVED1", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "RESERVED2", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "RESERVED3", MOD_KERNEL, 0)},
+
+ /*** 0080 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "RESERVED4", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "_LCLOSE", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "_LREAD", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "_LCREAT", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "_LLSEEK", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "_LOPEN", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "_LWRITE", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "RESERVED5", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LSTRCPY", MOD_KERNEL, sizeof(LSTRCPY16))},
+ {W32FUN(LOCALAPI, "LSTRCAT", MOD_KERNEL, sizeof(LSTRCAT16))},
+
+ /*** 0090 ***/
+ {W32FUN(LOCALAPI, "LSTRLEN", MOD_KERNEL, sizeof(LSTRLEN16))},
+ {W32FUN(LOCALAPI, "INITTASK", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETTEMPDRIVE", MOD_KERNEL, sizeof(GETTEMPDRIVE16))},
+ {W32FUN(LOCALAPI, "GETCODEHANDLE", MOD_KERNEL, sizeof(GETCODEHANDLE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "DEFINEHANDLETABLE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOADLIBRARY", MOD_KERNEL, sizeof(LOADLIBRARY16))},
+ {W32FUN(LOCALAPI, "FREELIBRARY", MOD_KERNEL, sizeof(FREELIBRARY16))},
+ {W32FUN(LOCALAPI, "GETTEMPFILENAME", MOD_KERNEL, sizeof(GETTEMPFILENAME16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETLASTDISKCHANGE", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETLPERRMODE", MOD_KERNEL, 0)},
+
+ /*** 0100 ***/
+ {W32FUN(LOCALAPI, "VALIDATECODESEGMENTS", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "NOHOOKDOSCALL", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DOS3CALL", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "NETBIOSCALL", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETCODEINFO", MOD_KERNEL, sizeof(GETCODEINFO16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETEXEVERSION", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "SETSWAPAREASIZE", MOD_KERNEL, sizeof(SETSWAPAREASIZE16))},
+ {W32FUN(LOCALAPI, "SETERRORMODE", MOD_KERNEL, sizeof(SETERRORMODE16))},
+ {W32FUN(LOCALAPI, "SWITCHSTACKTO", MOD_KERNEL, sizeof(SWITCHSTACKTO16))},
+ {W32FUN(LOCALAPI, "SWITCHSTACKBACK", MOD_KERNEL, 0)},
+
+ /*** 0110 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "PATCHCODEHANDLE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALWIRE", MOD_KERNEL, sizeof(GLOBALWIRE16))},
+ {W32FUN(LOCALAPI, "GLOBALUNWIRE", MOD_KERNEL, sizeof(GLOBALUNWIRE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "__AHSHIFT", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "__AHINCR", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "OUTPUTDEBUGSTRING", MOD_KERNEL, sizeof(OUTPUTDEBUGSTRING16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "INITLIB", MOD_KERNEL, 0)},
+ {W32FUN(WK32OldYield, "OLDYIELD", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETTASKQUEUEDS", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETTASKQUEUEES", MOD_KERNEL, 0)},
+
+ /*** 0120 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "UNDEFDYNLINK", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LOCALSHRINK", MOD_KERNEL, sizeof(LOCALSHRINK16))},
+ {W32FUN(LOCALAPI, "ISTASKLOCKED", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "KBDRST", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENABLEKERNEL", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DISABLEKERNEL", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "MEMORYFREED", MOD_KERNEL, 0)},
+ {W32FUN(WK32GetPrivateProfileInt, "GETPRIVATEPROFILEINT", MOD_KERNEL, sizeof(GETPRIVATEPROFILEINT16))},
+ {W32FUN(WK32GetPrivateProfileString, "GETPRIVATEPROFILESTRING", MOD_KERNEL, sizeof(GETPRIVATEPROFILESTRING16))},
+ {W32FUN(WK32WritePrivateProfileString, "WRITEPRIVATEPROFILESTRING",MOD_KERNEL, sizeof(WRITEPRIVATEPROFILESTRING16))},
+
+ /*** 0130 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "FILECDR", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETDOSENVIRONMENT", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETWINFLAGS", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETEXEPTR", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETWINDOWSDIRECTORY", MOD_KERNEL, sizeof(GETWINDOWSDIRECTORY16))},
+ {W32FUN(LOCALAPI, "GETSYSTEMDIRECTORY", MOD_KERNEL, sizeof(GETSYSTEMDIRECTORY16))},
+ {W32FUN(WK32GetDriveType, "GETDRIVETYPE", MOD_KERNEL, sizeof(GETDRIVETYPE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "FATALAPPEXIT", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETHEAPSPACES", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DOSIGNAL", MOD_KERNEL, 0)},
+
+ /*** 0140 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "SETSIGHANDLER", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "INITTASK1", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(WK32GetVersionEx, "GETVERSIONEX", MOD_KERNEL, sizeof(GETVERSIONEX16))},
+
+ /*** 0150 ***/
+ {W32FUN(WK32DirectedYield, "DIRECTEDYIELD", MOD_KERNEL, sizeof(DIRECTEDYIELD16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "WINOLDAPCALL", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETNUMTASKS", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALNOTIFY", MOD_KERNEL, sizeof(GLOBALNOTIFY16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETTASKDS", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "LIMITEMSPAGES", MOD_KERNEL, sizeof(LIMITEMSPAGES16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETCURPID", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "ISWINOLDAPTASK", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GLOBALHANDLENORIP", MOD_KERNEL, 0)},
+
+ /*** 0160 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "EMSCOPY", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOCALCOUNTFREE", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOCALHEAPSIZE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALLRUOLDEST", MOD_KERNEL, sizeof(GLOBALLRUOLDEST16))},
+ {W32FUN(LOCALAPI, "GLOBALLRUNEWEST", MOD_KERNEL, sizeof(GLOBALLRUNEWEST16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "A20PROC", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "WINEXEC", MOD_KERNEL, sizeof(WINEXEC16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETEXPWINVER", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DIRECTRESALLOC", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GETFREESPACE", MOD_KERNEL, sizeof(GETFREESPACE16))},
+
+ /*** 0170 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "ALLOCCSTODSALIAS", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "ALLOCDSTOCSALIAS", MOD_KERNEL, sizeof(ALLOCDSTOCSALIAS16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "ALLOCALIAS", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "__ROMBIOS", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "__A000h", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "ALLOCSELECTOR", MOD_KERNEL, sizeof(ALLOCSELECTOR16))},
+ {W32FUN(LOCALAPI, "FREESELECTOR", MOD_KERNEL, sizeof(FREESELECTOR16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "PRESTOCHANGOSELECTOR", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "__WINFLAGS", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "__D000h", MOD_KERNEL, 0)},
+
+ /*** 0180 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "LONGPTRADD", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "__B000h", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "__B800h", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "__0000h", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GLOBALDOSALLOC", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GLOBALDOSFREE", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETSELECTORBASE", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETSELECTORBASE", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETSELECTORLIMIT", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETSELECTORLIMIT", MOD_KERNEL, 0)},
+
+ /*** 0190 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "__E000h", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALPAGELOCK", MOD_KERNEL, sizeof(GLOBALPAGELOCK16))},
+ {W32FUN(LOCALAPI, "GLOBALPAGEUNLOCK", MOD_KERNEL, sizeof(GLOBALPAGEUNLOCK16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "__0040h", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "__F000h", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "__C000h", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SELECTORACCESSRIGHTS", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "GLOBALFIX", MOD_KERNEL,sizeof(GLOBALFIX16))},
+ {W32FUN(LOCALAPI, "GLOBALUNFIX", MOD_KERNEL,sizeof(GLOBALUNFIX16))},
+ {W32FUN(LOCALAPI, "SETHANDLECOUNT", MOD_KERNEL,sizeof(SETHANDLECOUNT16))},
+
+ /*** 0200 ***/
+ {W32FUN(LOCALAPI, "VALIDATEFREESPACES", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "REPLACEINST", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "REGISTERPTRACE", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "DEBUGBREAK", MOD_KERNEL, 0)},
+ {W32FUN(LOCALAPI, "SWAPRECORDING", MOD_KERNEL, sizeof(SWAPRECORDING16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "CVWBREAK", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ALLOCSELECTORARRAY", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ISDBCSLEADBYTE", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOCALHANDLEDELTA", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETSETKERNELDOSPROC", MOD_KERNEL, 0)},
+
+ /*** 0210 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "FARVALIDATEPOINTER", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETLASTCRITICALERROR", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "DEBUGDEFINESEGMENT", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "WRITEOUTPROFILES", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETFREEMEMINFO", MOD_KERNEL, 0)},
+ {W32FUN(WK32WowShouldWeSayWin95, "WowShouldWeSayWin95", MOD_KERNEL, sizeof(WOWSHOULDWESAYWIN9516))},
+ {W32FUN(WK32RegEnumKey32, "RegEnumKey32", MOD_KERNEL, sizeof(REGENUMKEY3216))},
+ {W32FUN(WK32RegOpenKey32, "RegOpenKey32", MOD_KERNEL, sizeof(REGOPENKEY3216))},
+ {W32FUN(WK32FreeResource, "FREERESOURCE", MOD_KERNEL, sizeof(FREERESOURCE16))},
+ {W32FUN(WK32FileRead, "WOWFileRead", MOD_KERNEL, sizeof(FILEIOREAD16))},
+
+ /*** 0220 ***/
+ {W32FUN(WK32RegCloseKey32, "RegCloseKey32", MOD_KERNEL,sizeof(REGCLOSEKEY3216))},
+ {W32FUN(WK32FileLSeek, "WOWFileLSeek", MOD_KERNEL,sizeof(FILEIOLSEEK16))},
+ {W32FUN(WK32KernelTrace, "WOWKernelTrace", MOD_KERNEL,sizeof(KERNELTRACE16))},
+ {W32FUN(WK32RegEnumValue32, "RegEnumValue32", MOD_KERNEL,sizeof(REGENUMVALUE3216))},
+ {W32FUN(WK32RegisterShellWindowHandle, "WOWRegisterShellWindowHandle",MOD_KERNEL,sizeof(WOWREGISTERSHELLWINDOWHANDLE16))},
+ {W32FUN(WK32LoadModule32, "WOWLoadModule", MOD_KERNEL,sizeof(WOWLOADMODULE16))},
+ {W32FUN(WK32WOWQueryPerformanceCounter, "WOWQueryPerformanceCounter", MOD_KERNEL,sizeof(WOWQUERYPERFORMANCECOUNTER16))},
+ {W32FUN(WK32WOWOutputDebugString, "WOWOUTPUTDEBUGSTRING", MOD_KERNEL,sizeof(OUTPUTDEBUGSTRING16))},
+ {W32FUN((LPFNW32)WK32WowCursorIconOp, "WowCursorIconOp", MOD_KERNEL,sizeof(WOWCURSORICONOP16))},
+ {W32FUN((LPFNW32)WK32WowFailedExec, "WOWFailedExec", MOD_KERNEL,0)},
+
+ /*** 0230 ***/
+ {W32FUN((LPFNW32)W32GetFastAddress, "WOWGetFastAddress", MOD_KERNEL,0)},
+ {W32FUN((LPFNW32)WK32WowCloseComPort, "WowCloseComPort", MOD_KERNEL,sizeof(WOWCLOSECOMPORT16))},
+ {W32FUN((LPFNW32)WK32WowDelFile, "WowDelFile", MOD_KERNEL,sizeof(WOWDELFILE16))},
+ {W32FUN((LPFNW32)WK32VirtualAlloc, "VirtualAlloc", MOD_KERNEL,sizeof(VIRTUALALLOC16))},
+ {W32FUN((LPFNW32)WK32VirtualFree, "VirtualFree", MOD_KERNEL,sizeof(VIRTUALFREE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "VirtualLock", MOD_KERNEL,sizeof(VIRTUALLOCK16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "VirtualUnLock", MOD_KERNEL,sizeof(VIRTUALUNLOCK16))},
+ {W32FUN((LPFNW32)WK32GlobalMemoryStatus,"GlobalMemoryStatus", MOD_KERNEL,sizeof(GLOBALMEMORYSTATUS16))},
+ {W32FUN((LPFNW32)W32GetFastCbRetAddress,"WOWGetFastCbRetAddress", MOD_KERNEL,0)},
+ {W32FUN((LPFNW32)W32GetTableOffsets, "WOWGetTableOffsets", MOD_KERNEL,sizeof(WOWGETTABLEOFFSETS16))},
+
+ /*** 0240 ***/
+ {W32FUN((LPFNW32)WK32KillRemoteTask, "WowKillRemoteTask", MOD_KERNEL,0)},
+ {W32FUN((LPFNW32)WK32WOWNotifyWOW32, "WOWNotifyWOW32", MOD_KERNEL,sizeof(WOWNOTIFYWOW3216))},
+ {W32FUN(WK32FileOpen, "WOWFileOpen", MOD_KERNEL,sizeof(FILEIOOPEN16))},
+ {W32FUN(WK32FileClose, "WOWFileClose", MOD_KERNEL,sizeof(FILEIOCLOSE16))},
+ {W32FUN((LPFNW32)WK32WowSetIdleHook, "WOWSetIdleHook", MOD_KERNEL,0)},
+ {W32FUN(WU32SysErrorBox, "SYSERRORBOX", MOD_KERNEL, sizeof(KSYSERRORBOX16))},
+ {W32FUN((LPFNW32)WK32WowIsKnownDLL, "WowIsKnownDLL", MOD_KERNEL, sizeof(WOWISKNOWNDLL16))},
+ {W32FUN((LPFNW32)W32WowDdeFreeHandle, "WowDdeFreeHandle", MOD_KERNEL,sizeof(WOWDDEFREEHANDLE16))},
+ {W32FUN(WK32FileGetAttributes, "WOWFileGetAttributes", MOD_KERNEL,sizeof(FILEIOGETATTRIBUTES16))},
+ {W32FUN(WK32FileGetDateTime, "WOWFileGetDateTime", MOD_KERNEL,sizeof(FILEIOGETDATETIME16))},
+
+ /*** 0250 ***/
+ {W32FUN(WK32FileLock, "WOWFileLock", MOD_KERNEL,sizeof(FILEIOLOCK16))},
+ {W32FUN((LPFNW32)WK32LoadLibraryEx32, "LoadLibraryEx32", MOD_KERNEL,sizeof(LOADLIBRARYEX32))},
+ {W32FUN((LPFNW32)WK32FreeLibrary32, "FreeLibrary32", MOD_KERNEL,sizeof(FREELIBRARY32))},
+ {W32FUN((LPFNW32)WK32GetProcAddress32, "GetProcAddress32", MOD_KERNEL,sizeof(GETPROCADDRESS32))},
+ {W32FUN((LPFNW32)WK32GetVDMPointer32, "GetVDMPointer32", MOD_KERNEL,sizeof(GETVDMPOINTER32))},
+ {W32FUN((LPFNW32)WK32ICallProc32, "ICallProc32", MOD_KERNEL,sizeof(ICALLPROC32))},
+ {W32FUN(UNIMPLEMENTEDAPI, "ExitWindowsExecContinue", MOD_KERNEL,0)},
+ {W32FUN(WK32FileFindFirst, "WOWFindFirst", MOD_KERNEL,sizeof(WOWFINDFIRST16))},
+ {W32FUN(WK32FileFindNext, "WOWFindNext", MOD_KERNEL,sizeof(WOWFINDNEXT16))},
+ {W32FUN(WK32SetDefaultDrive, "WOWSetDefaultDrive", MOD_KERNEL,0)},
+
+ /*** 0260 ***/
+ {W32FUN(WK32GetCurrentDirectory, "WOWGetCurrentDirectory", MOD_KERNEL,0)},
+ {W32FUN(WK32SetCurrentDirectory, "WOWSetCurrentDirectory", MOD_KERNEL,0)},
+ {W32FUN(WK32WowWaitForMsgAndEvent, "WOWWaitForMsgAndEvent", MOD_KERNEL,sizeof(WOWWAITFORMSGANDEVENT16))},
+ {W32FUN((LPFNW32)WK32WowMsgBox, "WOWMsgBox", MOD_KERNEL,sizeof(WOWMSGBOX16))},
+ {W32FUN((LPFNW32)W32GetFlatAddressArray,"WowGetFlatAddressArray", MOD_KERNEL,0)},
+ {W32FUN(WK32GetCurrentDate, "WOWGetCurrentDate", MOD_KERNEL,0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL,0)},
+ {W32FUN(WK32DeviceIOCTL, "WOWDeviceIOCTL", MOD_KERNEL,sizeof(WOWDEVICEIOCTL16))},
+ {W32FUN(WK32FileSetAttributes, "WOWFileSetAttributes", MOD_KERNEL,sizeof(WOWFILESETATTRIBUTES16))},
+ {W32FUN(WK32FileSetDateTime, "WOWFileSetDateTime", MOD_KERNEL,sizeof(WOWFILESETDATETIME16))},
+
+ /*** 0270 ***/
+ {W32FUN(WK32FileCreate, "WOWFileCreate", MOD_KERNEL,sizeof(WOWFILECREATE16))},
+ {W32FUN(WK32DosWowInit, "WOWDosWowInit", MOD_KERNEL,sizeof(WOWDOSWOWINIT16))},
+ {W32FUN(WK32CheckUserGdi, "WOWCheckUserGdi", MOD_KERNEL,sizeof(WOWCHECKUSERGDI16))},
+ {W32FUN(WK32WOWPARTYBYNUMBER, "WowPartyByNumber", MOD_KERNEL,sizeof(WOWPARTYBYNUMBER16))},
+ {W32FUN(WK32GetShortPathName, "GetShortPathName", MOD_KERNEL,sizeof(GETSHORTPATHNAME16))},
+ {W32FUN(WK32FindAndReleaseDib, "FindAndReleaseDib", MOD_KERNEL,sizeof(FINDANDRELEASEDIB16))},
+ {W32FUN(WK32WowReserveHtask, "WowReserveHtask", MOD_KERNEL,sizeof(WOWRESERVEHTASK16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+
+ /*** 0280 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(WK32WOWInitTask, "WOWInitTask", MOD_KERNEL, sizeof(WOWINITTASK16))},
+ {W32FUN((LPFNW32)WK32KillTask, "WOWKillTask", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+
+ /*** 0290 ***/
+ {W32FUN(WK32FileWrite, "WOWFileWrite", MOD_KERNEL,sizeof(FILEIOWRITE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(WK32WowGetNextVdmCommand, "WOWGetNextVDMCommand", MOD_KERNEL,sizeof(WOWGETNEXTVDMCOMMAND16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+
+ /*** 0300 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_KERNEL, 0)},
+
diff --git a/private/mvdm/wow32/wmdisp32.c b/private/mvdm/wow32/wmdisp32.c
new file mode 100644
index 000000000..e1d7d86fd
--- /dev/null
+++ b/private/mvdm/wow32/wmdisp32.c
@@ -0,0 +1,2602 @@
+/*++
+
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMDISP32.C
+ * WOW32 32-bit message thunks
+ *
+ * History:
+ * Created 19-Feb-1992 by Chandan S. Chauhan (ChandanC)
+ * Changed 12-May-1992 by Mike Tricker (MikeTri) Added MultiMedia thunks
+ * Changed 09-Jul-1992 by v-cjones Added msg profiling debugger extension
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wmdisp32.c);
+
+BOOL fThunkDDEmsg = TRUE;
+BOOL fDDEAckFree = FALSE;
+
+extern WORD msgFINDREPLACE; // see WCOMMDLG.C
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+INT fWMsgProfRT = 0;
+#endif
+
+LONG W32Win16WndProcEx(HWND hwnd, UINT uMsg, UINT uParam, LONG lParam,
+ VPWNDPROC vpWndProc16, // Next WndProc to call or NULL if default
+ PWW pww) // hwnd's PWW if already known or NULL
+{
+ BOOL fSuccess;
+ PWC pwc;
+ LONG ulReturn;
+ register PTD ptd;
+ WM32MSGPARAMEX wm32mpex;
+ BOOL fMessageNeedsThunking;
+#ifdef DEBUG
+ CHAR szClassName[80];
+#endif
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+ DWORD dwTics;
+#endif
+
+ ptd = CURRENTPTD();
+
+ vpWndProc16 &= WNDPROC_MASK;
+
+ //
+ // if the actual selector had the high bit on then we turned off
+ // bit 2 of the selector (the LDT bit, which will always be on)
+ //
+
+ if (!((DWORD)vpWndProc16 & WOWCLASS_VIRTUAL_NOT_BIT31)) {
+ vpWndProc16 |= (WNDPROC_WOW | WOWCLASS_VIRTUAL_NOT_BIT31);
+ }
+
+ // If the app has GP Faulted we don't want to pass it any more input
+ // This should be removed when USER32 does clean up on task death so
+ // it doesn't call us - mattfe june 24 92 HACK32
+
+ if (ptd->dwFlags & TDF_IGNOREINPUT) {
+ LOGDEBUG(6,(" W32Win16WndProc Ignoring Input Messsage %04X\n",uMsg));
+ WOW32ASSERTMSG(!gfIgnoreInputAssertGiven,
+ "WCD32CommonDialogProc: TDF_IGNOREINPUT hack was used, shouldn't be, "
+ "please email DaveHart with repro instructions. Hit 'g' to ignore this "
+ "and suppress this assertion from now on.\n");
+ gfIgnoreInputAssertGiven = TRUE;
+ goto SilentError;
+ }
+
+ //
+ // Figure out the class for this hwnd if we haven't seen it before
+ //
+
+ if (!pww) {
+ if (!(pww = (PWW) GetWindowLong(hwnd, GWL_WOWWORDS))) {
+ LOGDEBUG(LOG_ALWAYS,("WOW :: W32Win16WndProc ERROR: GetWindowLong(0x%x, GWL_WOWWORDS) fails\n", hwnd));
+ goto Error;
+ }
+ }
+
+ if (WOWCLASS_UNKNOWN == pww->iClass) {
+ if (pwc = FindPWC(hwnd)) {
+ SETWL(hwnd, GWL_WOWvpfnWndProc, pwc->vpfnWndProc);
+ SETWL(hwnd, GWL_WOWiClassAndflState,
+ MAKECLASSANDSTATE(WOWCLASS_WIN16, pww->flState | WWSTATE_ICLASSISSET));
+
+ LOGDEBUG(7,("Grovelled Class Name = %s\n",
+ (GetClassName(hwnd, szClassName, sizeof(szClassName)) ? szClassName : "Unknown")));
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS,("WOW :: W32Win16WndProc : FindPWC(0x%8.8x) fails\n", hwnd));
+ }
+ }
+
+ if (WOWCLASS_UNKNOWN == pww->iClass) {
+ LOGDEBUG(LOG_ALWAYS,("WOW :: W32Win16WndProc ERROR: cannot find 16-bit class for window %08lx\n", hwnd));
+ goto Error;
+ }
+
+ // This message is WIN32 only. It is sent by WOW32 during the processing
+ // of an EM_SETSEL in WU32Send/PostMessage. If an MLE is subclassed the
+ // message will come through here attempting to travel back to the 16-bit
+ // app's wndproc. Instead of sending back a message that the 16-bit app
+ // doesn't understand it will be intercepted here and sent directly to the
+ // standard EditWindowProc. I'm not adding a Thunk because it shouldn't
+ // go to the app.
+
+ if (uMsg == EM_SCROLLCARET) {
+ WNDPROC EditWndProc;
+
+ // find the 32-bit EditWindowProc
+ // We should only be in this state if the app has subclassed so this
+ // call should be safe.
+
+ EditWndProc = (WNDPROC)GetStdClassWndProc(WOWCLASS_EDIT);
+
+ if (EditWndProc) {
+ CallWindowProc(EditWndProc, hwnd, EM_SCROLLCARET, 0, 0);
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS,(" W32Win16WndProc ERROR: cannot find 32-bit EditWindowProc\n"));
+ }
+ return 0; // notification message, no return code
+ }
+
+ // Thunk this 32 bit message to 16 bit message
+
+ LOGDEBUG(6,(" Thunking window %x message %s\n", hwnd, GetWMMsgName(uMsg)));
+#ifdef DEBUG
+ if((uMsg & WOWPRIVATEMSG) && ((uMsg & ~WOWPRIVATEMSG) < 0x400)) {
+ LOGDEBUG(6,(" -- private WOW bit set for %s\n", GetWMMsgName(uMsg & ~WOWPRIVATEMSG)));
+ }
+#endif
+
+ wm32mpex.Parm16.WndProc.hwnd = GETHWND16(hwnd);
+ wm32mpex.Parm16.WndProc.wMsg = (WORD)uMsg;
+ wm32mpex.Parm16.WndProc.wParam = (WORD)uParam;
+ wm32mpex.Parm16.WndProc.lParam = (LONG)lParam;
+ wm32mpex.Parm16.WndProc.hInst = (WORD)pww->hInstance;
+
+ // An app can send one of its private class windows a message say 401.
+ // This message will not be thunked in WMSG16.C because the
+ // messages >= 0x400 and we did not want to thunk it in WMSG16.C
+ //
+
+ fMessageNeedsThunking = (uMsg < 0x400) &&
+ (aw32Msg[uMsg].lpfnM32 != WM32NoThunking);
+
+ if (fMessageNeedsThunking) {
+ LOGDEBUG(6,("%04X (%s)\n", ptd->htask16, (aw32Msg[uMsg].lpszW32)));
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+ dwTics = GetWOWTicDiff(0L);
+#endif
+ wm32mpex.fThunk = THUNKMSG;
+ wm32mpex.hwnd = hwnd;
+ wm32mpex.uMsg = uMsg;
+ wm32mpex.uParam = uParam;
+ wm32mpex.lParam = lParam;
+ wm32mpex.pww = pww;
+ wm32mpex.fFree = TRUE;
+ wm32mpex.lpfnM32 = aw32Msg[uMsg].lpfnM32;
+ ulReturn = (wm32mpex.lpfnM32)(&wm32mpex);
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+ if( !fWMsgProfRT ) { // only if not profiling round trip
+ aw32Msg[uMsg].cTics += GetWOWTicDiff(dwTics);
+ }
+#endif
+
+ if (!ulReturn) {
+ LOGDEBUG(LOG_ALWAYS,(" W32Win16WndProc ERROR: cannot thunk 32-bit message %s (%x)\n", GetWMMsgName(uMsg), uMsg));
+ goto Error;
+ }
+ }
+
+
+ if (!vpWndProc16)
+ vpWndProc16 = pww->vpfnWndProc;
+
+ if (vpWndProc16 == (VPVOID)NULL) {
+ WOW32ASSERT(vpWndProc16);
+ goto SilentError;
+ }
+
+ LOGDEBUG(6,("16-bit Window Proc = %08lX\n", vpWndProc16));
+
+ BlockWOWIdle(FALSE);
+
+ fSuccess = CallBack16(RET_WNDPROC, &wm32mpex.Parm16, vpWndProc16, (PVPVOID)&wm32mpex.lReturn);
+
+ BlockWOWIdle(TRUE);
+
+ // During CreateWindow some apps draw their own non-client area and don't
+ // pass WM_NCCALCSIZE to DefWindowProc which causes Win 95 and NT's user to
+ // not set some needed window flags. Mavis Beacon is an example. We'll pass
+ // the message for them.
+
+ if (uMsg == WM_NCCALCSIZE) {
+ if (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_DEFWNDPROCNCCALCSIZE) {
+ DefWindowProc(hwnd, uMsg, uParam, lParam);
+ }
+ }
+
+ // UnThunk this 32 bit message
+
+ LOGDEBUG(6,(" UnThunking window %x message %s\n", hwnd, (LPSZ)GetWMMsgName(uMsg)));
+#ifdef DEBUG
+ if((uMsg & WOWPRIVATEMSG) && ((uMsg - WOWPRIVATEMSG) < 0x400)) {
+ LOGDEBUG(6,(" -- private WOW bit set for %s\n", (LPSZ)GetWMMsgName(uMsg)));
+ }
+#endif
+
+ if (fMessageNeedsThunking) {
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+ if( !fWMsgProfRT ) { // only if not profiling round trip
+ dwTics = GetWOWTicDiff(0L);
+ }
+#endif
+
+ wm32mpex.fThunk = UNTHUNKMSG;
+ (wm32mpex.lpfnM32)(&wm32mpex);
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+ aw32Msg[uMsg].cTics += GetWOWTicDiff(dwTics);
+ aw32Msg[uMsg].cCalls++; // increment # times message passed
+#endif
+
+ }
+
+ if (!fSuccess) {
+ goto Error;
+ }
+
+ return (wm32mpex.lReturn);
+
+Error:
+ LOGDEBUG(LOG_ALWAYS,(" W32Win16WndProc ERROR: cannot call back, using default message handling\n"));
+SilentError:
+ return DefWindowProc(hwnd, uMsg, uParam, lParam);
+}
+
+
+
+// The following functions are used to "thunk" a 32 bit message to 16 bit
+// message.
+//
+// To add a thunk function for a 32 bit message,
+// - Modify the entry for the message in "aw32Msg" function array
+// (in wmtbl32.c) to point to the new thunk function.
+// - Define the new thunk function in this file.
+//
+
+
+// These messages do not require any thunking so just copy the 32 bit wParam
+// and lParam to 16 bit wParam and lParam.
+//
+//
+// WM_CANCELMODE
+// WM_CHAR
+// WM_CHILDACTIVATE
+// WM_CLEAR
+// WM_CLOSE
+// WM_COMMNOTIFY
+// WM_COMPACTING
+// WM_COPY
+// WM_CUT
+// WM_DEADCHAR
+// WM_DESTROY
+// WM_DRAWCLIPBOARD
+// WM_ENABLE
+// WM_ENDSESSION
+// WM_FONTCHANGE
+// WM_GETFONT
+// WM_GETTEXTLENGTH
+// WM_HOTKEY
+// WM_INPUTFOCUS
+// WM_ISACTIVEICON (undocumented)
+// WM_KEYDOWN
+// WM_KEYUP
+// WM_LBTRACKPOINT (undocumented)
+// WM_LBUTTONDBLCLK
+// WM_LBUTTONDOWN
+// WM_LBUTTONUP
+// WM_MBUTTONDBLCLK
+// WM_MBUTTONDOWN
+// WM_MBUTTONUP
+// WM_MDICASCADE
+// WM_MDIICONARRANGE
+// WM_MDINEXT
+// WM_MDITILE
+// WM_MOUSEENTER
+// WM_MOUSELEAVE
+// WM_MOUSEMOVE
+// WM_MOVE
+// WM_NCCALCRGN
+// WM_NCDESTROY
+// WM_NCHITTEST
+// WM_NCLBUTTONDBLCLK
+// WM_NCLBUTTONDOWN
+// WM_NCLBUTTONUP
+// WM_NCMBUTTONDBLCLK
+// WM_NCMBUTTONDOWN
+// WM_NCMBUTTONUP
+// WM_NCMOUSEMOVE
+// WM_NCRBUTTONDBLCLK
+// WM_NCRBUTTONDOWN
+// WM_NCRBUTTONUP
+// WM_PAINTICON
+// WM_PASTE
+// WM_POWER
+// WM_QUERYENDSESSION
+// WM_QUERYNEWPALETTE
+// WM_QUERYOPEN
+// WM_QUERYPARKICON (undocumented)
+// WM_QUEUESYNC
+// WM_QUIT
+// WM_RBUTTONDBLCLK
+// WM_RBUTTONDOWN
+// WM_RBUTTONUP
+// WM_RENDERALLFORMATS
+// WM_RENDERFORMAT
+// WM_SETREDRAW
+// WM_SHOWWINDOW
+// WM_SIZE
+// WM_SPOOLERSTATUS (double-check lParam conversion on this one -JTP)
+// WM_SYSCHAR
+// WM_SYSCOLORCHANGE
+// WM_SYSCOMMAND
+// WM_SYSDEADCHAR
+// WM_SYSKEYDOWN
+// WM_SYSKEYUP
+// WM_SYSTEMERROR
+// WM_TIMECHANGE
+// WM_UNDO
+// MM_JOY1BUTTONDOWN - MultiMedia messages
+// MM_JOY1BUTTONUP
+// MM_JOY1MOVE
+// MM_JOY1ZMOVE
+// MM_JOY2BUTTONDOWN
+// MM_JOY2BUTTONUP
+// MM_JOY2MOVE
+// MM_JOY2ZMOVE
+// MM_MCINOTIFY - MultiMedia messages
+
+
+BOOL FASTCALL WM32NoThunking(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+#if 0
+ //
+ // this routine is never called! It's used as a placeholder.
+ // if you want to make a change here, you have to make the change
+ // to the places where we compare the thunk routine to WM32NoThunking
+ // and only call the thunk routine if it's not this. also make sure
+ // that this 'default' thunking happens for NoThunking messages.
+ //
+
+ if (lpwm32mpex->fThunk) {
+ LOGDEBUG(6,(" No Thunking was required for the 32-bit message %s(%04x)\n", (LPSZ)GetWMMsgName(lpwm32mpex->uMsg), lpwm32mpex->uMsg));
+
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD)lpwm32mpex->uMsg;
+ lpwm32mpex->Parm16.WndProc.wParam = (WORD)lpwm32mpex->uParam;
+ lpwm32mpex->Parm16.WndProc.lParam = (LONG)lpwm32mpex->lParam;
+ }
+
+ //
+ // this routine is never called! It's used as a placeholder.
+ // if you want to make a change here, you have to make the change
+ // to the places where we compare the thunk routine to WM32NoThunking
+ // and only call the thunk routine if it's not this.
+ //
+#endif
+
+ //
+ // Return FALSE, so if for some reason this routine gets used
+ // the failure to thunk will be apparent.
+ //
+
+ return FALSE;
+}
+
+#ifdef DEBUG // see the macro WM32UNDOCUMENTED
+
+// These are undocumented messages for Win 3.0 so take a look at the app
+// who is using them.
+
+BOOL FASTCALL WM32Undocumented(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ LOGDEBUG(3,(" Window %08lX is receiving Undocumented Message %s\n", lpwm32mpex->hwnd, (LPSZ)GetWMMsgName(lpwm32mpex->uMsg), lpwm32mpex->uMsg));
+
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD)lpwm32mpex->uMsg;
+ lpwm32mpex->Parm16.WndProc.wParam = (WORD)lpwm32mpex->uParam;
+ lpwm32mpex->Parm16.WndProc.lParam = (LONG)lpwm32mpex->lParam;
+ }
+
+ return (TRUE);
+}
+
+#endif
+
+// This function thunks the messages,
+//
+// WM_CREATE
+// WM_NCCREATE
+//
+
+BOOL FASTCALL WM32Create(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+
+ INT cb;
+ VPVOID vpClass = 0;
+ VPVOID vpName = 0;
+ VPVOID vpCreateParams = 0;
+ register PCREATESTRUCT16 pcws16;
+ LPCREATESTRUCT lParam = (LPCREATESTRUCT) lpwm32mpex->lParam;
+
+ if (lpwm32mpex->fThunk) {
+
+ if (HIWORD(lParam)) {
+
+ // BUGBUG -- The assumption here is that GlobalAlloc will never
+ // return a memory object that isn't word-aligned, so that we can
+ // assign word-aligned words directly; we have no idea whether the
+ // memory is dword-aligned or not however, so dwords must always
+ // be paranoidly stored with the STOREDWORD/STORELONG macros -JTP
+
+
+ if (lParam->lpszClass) {
+ if ( HIWORD(lParam->lpszClass) == 0 ) {
+ vpClass = (VPVOID)lParam->lpszClass;
+ }
+ else {
+ cb = strlen(lParam->lpszClass)+1;
+ if (!(vpClass = malloc16(cb)))
+ goto Error;
+ putstr16(vpClass, lParam->lpszClass, cb);
+ }
+ }
+
+ if (lParam->lpszName) {
+ cb = strlen(lParam->lpszName)+1;
+ if (!(vpName = malloc16(cb)))
+ goto Error;
+ putstr16(vpName, lParam->lpszName, cb);
+ }
+
+ if (lpwm32mpex->pww == NULL) {
+ lpwm32mpex->pww = (PWW)GetWindowLong(lpwm32mpex->hwnd, GWL_WOWWORDS);
+ if (lpwm32mpex->pww == NULL)
+ return FALSE; // Window is dead
+ }
+
+ if (lParam->lpCreateParams && (lpwm32mpex->pww->dwExStyle & WS_EX_MDICHILD) ) {
+ // This works because wm32mdicreate thunk doesn't use any
+ // parameters except lParam
+
+ WM32MSGPARAMEX wm32mpexT;
+ wm32mpexT.fThunk = lpwm32mpex->fThunk;
+ wm32mpexT.hwnd = lpwm32mpex->hwnd;
+ wm32mpexT.uMsg = WM_MDICREATE;
+ wm32mpexT.uParam = lpwm32mpex->uParam;
+ wm32mpexT.lParam = (LONG)lParam->lpCreateParams;
+ wm32mpexT.pww = lpwm32mpex->pww;
+ wm32mpexT.fFree = lpwm32mpex->fFree;
+ wm32mpexT.Parm16.WndProc.lParam = 0;
+ WM32MDICreate(&wm32mpexT);
+ lpwm32mpex->dwParam = wm32mpexT.dwParam;
+ vpCreateParams = wm32mpexT.Parm16.WndProc.lParam;
+ }
+ else {
+ vpCreateParams = (VPVOID)lParam->lpCreateParams;
+ }
+
+ if (!(lpwm32mpex->Parm16.WndProc.lParam = stackalloc16(sizeof(CREATESTRUCT16))))
+ return FALSE;
+
+ GETVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(CREATESTRUCT16), pcws16);
+
+ STOREDWORD(pcws16->vpszClass, vpClass);
+ STOREDWORD(pcws16->vpszWindow, vpName);
+ STOREDWORD(pcws16->vpCreateParams, vpCreateParams);
+
+ lpwm32mpex->dwTmp[0] = vpClass; // store for later freeing
+ lpwm32mpex->dwTmp[1] = vpName;
+
+
+ // BUGBUG 08-Apr-91 JeffPar -- What if hModule is for a 32-bit task?
+ pcws16->hInstance = GETHINST16(lParam->hInstance);
+ pcws16->hMenu = GETHMENU16(lParam->hMenu);
+ pcws16->hwndParent = GETHWND16(lParam->hwndParent);
+ pcws16->cy = (SHORT)lParam->cy;
+ pcws16->cx = (SHORT)lParam->cx;
+ pcws16->y = (SHORT)lParam->y;
+ pcws16->x = (SHORT)lParam->x;
+ STOREDWORD(pcws16->dwStyle, lParam->style);
+ STOREDWORD(pcws16->dwExStyle, lParam->dwExStyle);
+
+ FLUSHVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(CREATESTRUCT16), pcws16);
+ FREEVDMPTR(pcws16);
+
+ return TRUE;
+
+ Error:
+ LOGDEBUG(LOG_ALWAYS,(" !!!! WM32Create, WM_CREATE thunking failed !!!! Window %08lX ", lpwm32mpex->hwnd));
+ if (HIW(vpClass)) free16(vpClass);
+ if (vpName) free16(vpName);
+ return (FALSE);
+
+ // do some clean up
+ // UnThunkWMCreate32(lParam, lpwm32mpex->Parm16.WndProc.lParam);
+
+ } else {
+ return TRUE;
+ }
+
+
+
+
+ }
+ else {
+
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+
+ if (lpwm32mpex->pww == NULL) {
+ lpwm32mpex->pww = (PWW)GetWindowLong(lpwm32mpex->hwnd, GWL_WOWWORDS);
+ if (lpwm32mpex->pww == NULL)
+ return FALSE; // Window is dead
+ }
+
+ if (lParam->lpCreateParams && (lpwm32mpex->pww->dwExStyle & WS_EX_MDICHILD) ) {
+ WM32MSGPARAMEX wm32mpexT;
+ GETVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(CREATESTRUCT16), pcws16);
+ wm32mpexT.fThunk = lpwm32mpex->fThunk;
+ wm32mpexT.hwnd = lpwm32mpex->hwnd;
+ wm32mpexT.uMsg = WM_MDICREATE;
+ wm32mpexT.uParam = lpwm32mpex->uParam;
+ wm32mpexT.lParam = (LONG)lParam->lpCreateParams;
+ wm32mpexT.pww = lpwm32mpex->pww;
+ wm32mpexT.fFree = lpwm32mpex->fFree;
+ wm32mpexT.Parm16.WndProc.lParam = (VPVOID)FETCHDWORD(pcws16->vpCreateParams);
+ wm32mpexT.lReturn = 0;
+ wm32mpexT.dwParam = lpwm32mpex->dwParam;
+ WM32MDICreate(&wm32mpexT);
+ FREEVDMPTR(pcws16);
+ }
+
+ vpClass = lpwm32mpex->dwTmp[0];
+ vpName = lpwm32mpex->dwTmp[1];
+
+ // if HIWORD(class) is zero, class is an atom, else a pointer.
+
+ if (HIW16(vpClass)) {
+ free16(vpClass);
+ }
+
+ if (vpName) {
+ free16(vpName);
+ }
+
+ stackfree16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return TRUE;
+ }
+
+}
+
+
+// This function thunks the messages,
+//
+// WM_NCACTIVATE
+// WM_ACTIVATE
+//
+
+BOOL FASTCALL WM32Activate(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = LOWORD(lpwm32mpex->uParam);
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = GETHWND16(lpwm32mpex->lParam);
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = HIWORD(lpwm32mpex->uParam);
+ }
+
+ return (TRUE);
+}
+
+
+
+// This function thunks the messages,
+//
+// WM_VKEYTOITEM
+// WM_CHARTOITEM
+// WM_BEGINDRAG
+//
+
+BOOL FASTCALL WM32VKeyToItem(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = GETHWND16(lpwm32mpex->lParam);
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = HIWORD(lpwm32mpex->uParam);
+ }
+ else {
+ lpwm32mpex->lReturn = (INT)(SHORT)(lpwm32mpex->lReturn); // sign extend.
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_SETFOCUS
+// WM_KILLFOCUS
+// WM_SETCURSOR
+// WM_MOUSEACTIVATE
+// WM_MDIDESTROY
+// WM_MDIRESTORE
+// WM_MDIMAXIMIZE
+// WM_VSCROLLCLIPBOARD
+// WM_HSCROLLCLIPBOARD
+// WM_PALETTECHANGED
+// WM_PALETTEISCHANGING
+// WM_INITDIALOG
+//
+
+BOOL FASTCALL WM32SetFocus(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+ }
+
+ return (TRUE);
+}
+
+// This function thunks the messages,
+//
+// WM_SETTEXT
+// WM_WININICHANGE
+// WM_DEVMODECHANGE
+//
+
+BOOL FASTCALL WM32SetText(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ INT cb;
+
+
+ if (lpwm32mpex->fThunk) {
+ if (lpwm32mpex->lParam) {
+
+ LONG lParam = (LONG)GetParam16(lpwm32mpex->lParam);
+ if (lParam) {
+ lpwm32mpex->Parm16.WndProc.lParam = lParam;
+ return (TRUE);
+ }
+
+ cb = strlen((LPSZ)lpwm32mpex->lParam)+1;
+
+ // winworks2.0a requires DS based string pointers for this message
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_DSBASEDSTRINGPOINTERS) {
+ if (!(lpwm32mpex->Parm16.WndProc.lParam = stackalloc16(cb)))
+ return FALSE;
+ } else {
+ if (!(lpwm32mpex->Parm16.WndProc.lParam = malloc16(cb)))
+ return FALSE;
+ }
+ putstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, cb);
+ }
+ }
+ else {
+// BUGBUG 09-Apr-91 -- Should I copy back?
+ if (DeleteParamMap(lpwm32mpex->Parm16.WndProc.lParam, PARAM_16, NULL)) {
+ return TRUE;
+ }
+
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_DSBASEDSTRINGPOINTERS) {
+ stackfree16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ } else {
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the message,
+//
+// WM_GETTEXT
+//
+
+BOOL FASTCALL WM32GetText(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ INT cb;
+ LPSTR psz;
+ INT cbWrote;
+
+
+
+ if (lpwm32mpex->fThunk) {
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_DSBASEDSTRINGPOINTERS) {
+ //
+ // msworks 2.0a has a wndproc called EdWnProc() which when it gets
+ // a WM_GETTEXT, assumes lParam is a based pointer whose segment
+ // value is equal to winwork's ds. That is true under win3.1, but
+ // if wow calls malloc16, it'll have a different segment value.
+ // so instead alloc the space on the caller's stack. Since most
+ // apps have SS == DS, this will fix apps that do this, including
+ // msworks 2.0a.
+ //
+
+ lpwm32mpex->Parm16.WndProc.lParam = stackalloc16(lpwm32mpex->Parm16.WndProc.wParam);
+ } else {
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(lpwm32mpex->Parm16.WndProc.wParam);
+ }
+
+ //
+ // non-zero fill to detect people who write more than they
+ // say that they do!
+ //
+ GETVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, lpwm32mpex->Parm16.WndProc.wParam, psz);
+ RtlFillMemory(psz, lpwm32mpex->Parm16.WndProc.wParam, 0xff);
+ FLUSHVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, lpwm32mpex->Parm16.WndProc.wParam, psz);
+ FREEVDMPTR(psz);
+ return (BOOL)lpwm32mpex->Parm16.WndProc.lParam;
+ }
+ else {
+ // some apps return garbage in the high word. safely assume
+ // that cbWindowText < 64K
+ HIW(lpwm32mpex->lReturn) = 0;
+
+ // it is necessary to check the length of the buffer, specified in
+ // lpwm32mpex->uParam. if number of bytes (lpwm32mpex->lReturn) that are to be copied is
+ // EQUAL to the length of the buffer, then copy ONLY the bytes EQUAL
+ // to the length of the buffer.
+ //
+
+ // Paradox is one of the apps where this condition is hit.
+ // bug # 4272.
+
+
+ //
+
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+
+ cb = lpwm32mpex->lReturn + 1;
+
+ if (lpwm32mpex->uParam == 0) {
+ // cb = 0 if lReturn == 0 && uParam == 0
+
+ if (cb == 1)
+ cb--;
+ }
+ else if (cb == 2 || cb == 1) {
+ // Here only if uParam != 0
+ //
+ // Determine how much of the buffer they touched!
+ //
+ // MyAdvancedLabelMaker returns 1 when they really return
+ // more than 1. Since the return 1, cb will be 2. Then
+ // We check to see how much of the buffer they really modified.
+ // Then we lie and say that they really filled in that much
+ // of the buffer.
+ //
+ // Sql administator also does this, except it returns 0
+ // bug 7731
+
+ GETVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, lpwm32mpex->Parm16.WndProc.wParam, psz);
+
+ cbWrote = lpwm32mpex->uParam;
+ while (cbWrote && (psz[cbWrote-1] == '\xff')) {
+ cbWrote--;
+ }
+ // copy out as many bytes as they wrote
+ // distinguish between 'zerobytes written vs. one byte written'
+
+ lpwm32mpex->lReturn = (cbWrote) ? (cbWrote - 1) : 0;
+ cb = cbWrote;
+
+ FREEVDMPTR(psz);
+ }
+
+
+ // cb = min(cb, wparam) only if wparam != 0
+ // MSPROFIT: does
+ // ret = sendmessage(hwnd, wm_gettest, wparam = 0, lparam);
+ // where ret != 0. so we have to copy the necessary bytes into
+ // lparam eventhough wparam is zero. It does this for reading
+ // those ominprseent "$0.00" strings in the app (ledgers etc).
+ //
+ // - nanduri
+
+ if (lpwm32mpex->uParam && (UINT)cb > lpwm32mpex->uParam) {
+ cb = lpwm32mpex->uParam;
+ }
+
+ getstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, cb);
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_DSBASEDSTRINGPOINTERS) {
+ stackfree16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ } else {
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_ERASEBKGND
+// WM_ICONERASEBKGND
+//
+
+BOOL FASTCALL WM32EraseBkGnd(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHDC16(lpwm32mpex->uParam);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_ACTIVATEAPP
+//
+
+BOOL FASTCALL WM32ActivateApp(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ extern void UpdateInt16State(void);
+
+ if (lpwm32mpex->fThunk) {
+
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) =
+ lpwm32mpex->lParam
+ ? ThreadID32toHtask16((DWORD)lpwm32mpex->lParam)
+ : 0;
+
+ // We need to update wow int 16 bios when I wow app gets the focus.
+ UpdateInt16State();
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_GETMINMAXINFO
+//
+
+BOOL FASTCALL WM32GetMinMaxInfo(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ LPPOINT lParam = (LPPOINT) lpwm32mpex->lParam;
+
+
+ if (lpwm32mpex->fThunk) {
+ if (lParam) {
+ lpwm32mpex->Parm16.WndProc.lParam = stackalloc16(sizeof(POINT16)*5);
+ UnThunkWMGetMinMaxInfo16(lpwm32mpex->Parm16.WndProc.lParam, lParam);
+ }
+ }
+ else {
+ ThunkWMGetMinMaxInfo16(lpwm32mpex->Parm16.WndProc.lParam, &lParam)
+ stackfree16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return(TRUE);
+}
+
+
+
+// This function thunks the messages,
+//
+// WM_NCPAINT
+//
+
+BOOL FASTCALL WM32NCPaint(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = (lpwm32mpex->uParam == 1) ? 1 :
+ GETHDC16(lpwm32mpex->uParam);
+ }
+ return (TRUE);
+}
+
+// This function thunks the messages,
+//
+// WM_GETDLGCODE
+//
+BOOL FASTCALL WM32GetDlgCode(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ if (lpwm32mpex->lParam) {
+
+ // BUGBUG -- The assumption here is that GlobalAlloc will never
+ // return a memory object that isn't word-aligned, so that we can
+ // assign word-aligned words directly; we have no idea whether the
+ // memory is dword-aligned or not however, so dwords must always
+ // be paranoidly stored with the STOREDWORD/STORELONG macros -JTP
+
+ if (!(lpwm32mpex->Parm16.WndProc.lParam = malloc16(sizeof(MSG16))))
+ return FALSE;
+
+ putmsg16(lpwm32mpex->Parm16.WndProc.lParam, (LPMSG)lpwm32mpex->lParam);
+
+ return TRUE;
+ }
+ }
+ else {
+ // Message structure doesn't need to be copied back does it? -Bob
+
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ }
+ return (TRUE);
+}
+
+// This function thunks the messages,
+//
+// WM_NEXTDLGCTL
+//
+
+BOOL FASTCALL WM32NextDlgCtl(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ if (lpwm32mpex->lParam) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+ }
+ }
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_DRAWITEM
+//
+
+BOOL FASTCALL WM32DrawItem(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ LPDRAWITEMSTRUCT lParam = (LPDRAWITEMSTRUCT) lpwm32mpex->lParam;
+
+
+ if (lpwm32mpex->fThunk) {
+ if (lParam) {
+ lpwm32mpex->Parm16.WndProc.lParam = stackalloc16(sizeof(DRAWITEMSTRUCT16));
+ putdrawitem16(lpwm32mpex->Parm16.WndProc.lParam, lParam);
+ }
+ }
+ else {
+ // BUGBUG 08-Apr-91 JeffPar -- Reflect changes back to 32-bit structure?
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ stackfree16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return(TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_MEASUREITEM
+//
+
+BOOL FASTCALL WM32MeasureItem(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ PMEASUREITEMSTRUCT16 pmis16;
+ LPMEASUREITEMSTRUCT lParam = (LPMEASUREITEMSTRUCT) lpwm32mpex->lParam;
+ BOOL fHasStrings;
+ DWORD cSize;
+
+
+ //
+ // Compatibility hack
+ //
+ // CrossTalk 2.0 has a bug where it fails to distinguish between
+ // WM_MEASUREITEM and WM_INITDIALOG when doing file.open
+ // on WM_MEASUREITEM it calls CallWindowProc() to send what it
+ // thinks is lpOpenFileName->lpCust but is really random stack.
+ // currently the high word of this random pointer is an hInstance
+ // and gets through the validation layer, whereas on Win31 it doesn't.
+ // if this WM_MEASUREITEM gets to the app's proc then the app will
+ // initialize incorrectly and take a GP. i have increased the stack
+ // allocation by XTALKHACK to ensure that the random data does is not
+ // a valid pointer.
+ //
+
+#define XTALKHACK (sizeof(OPENFILENAME16)-sizeof(MEASUREITEMSTRUCT16))
+
+
+ if (lpwm32mpex->fThunk) {
+ if (lParam) {
+
+ fHasStrings = FALSE;
+ if ( lParam->CtlType == ODT_COMBOBOX || lParam->CtlType == ODT_LISTBOX ) {
+ if (lParam->itemWidth == MIFLAG_FLAT) {
+ fHasStrings = TRUE;
+ }
+ }
+
+ cSize = sizeof(MEASUREITEMSTRUCT16);
+ if ( fHasStrings ) {
+ cSize += strlen((LPSTR)lParam->itemData) + 1;
+ }
+
+ if ( cSize < XTALKHACK+sizeof(MEASUREITEMSTRUCT16) ) {
+ cSize = XTALKHACK+sizeof(MEASUREITEMSTRUCT16);
+ }
+
+ if ( !(lpwm32mpex->Parm16.WndProc.lParam = stackalloc16(cSize)) )
+ return FALSE;
+
+ GETVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, cSize, pmis16);
+
+ pmis16->CtlType = (WORD)lParam->CtlType;
+ pmis16->CtlID = (WORD)lParam->CtlID;
+ pmis16->itemID = (WORD)lParam->itemID;
+ pmis16->itemWidth = (WORD)lParam->itemWidth;
+ pmis16->itemHeight = (WORD)lParam->itemHeight;
+
+#ifdef XTALKHACK
+ ((POPENFILENAME16)pmis16)->lCustData = 7; // invalid far pointer
+#endif
+ if ( fHasStrings ) {
+ pmis16->itemData = lpwm32mpex->Parm16.WndProc.lParam+sizeof(MEASUREITEMSTRUCT16);
+ strcpy( (LPSTR)(pmis16+1), (LPSTR)lParam->itemData );
+ } else {
+ STOREDWORD(pmis16->itemData, lParam->itemData);
+ }
+
+ WOW32ASSERT(HIWORD(cSize) == 0);
+ FLUSHVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, (USHORT) cSize, pmis16);
+ FREEVDMPTR(pmis16);
+ }
+ }
+ else {
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ GETVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(MEASUREITEMSTRUCT16), pmis16);
+
+ lParam->CtlType = WORD32(pmis16->CtlType);
+ lParam->CtlID = WORD32(pmis16->CtlID);
+ lParam->itemID = WORD32(pmis16->itemID);
+
+ // itemWidth must sign extend (PPT3 bug & Win3.1 treats it as signed!)
+ lParam->itemWidth = INT32(pmis16->itemWidth);
+
+ lParam->itemHeight = WORD32(pmis16->itemHeight);
+ lParam->itemData = pmis16->itemData;
+
+ FREEVDMPTR(pmis16);
+
+ stackfree16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+
+ return(TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_DELETEITEM
+//
+
+
+BOOL FASTCALL WM32DeleteItem(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ register PDELETEITEMSTRUCT16 pdes16;
+ LPDELETEITEMSTRUCT lParam = (LPDELETEITEMSTRUCT) lpwm32mpex->lParam;
+
+
+
+ if (lpwm32mpex->fThunk) {
+ if (lParam) {
+
+ // BUGBUG -- The assumption here is that GlobalAlloc will never
+ // return a memory object that isn't word-aligned, so that we can
+ // assign word-aligned words directly; we have no idea whether the
+ // memory is dword-aligned or not however, so dwords must always
+ // be paranoidly stored with the STOREDWORD/STORELONG macros -JTP
+
+ lpwm32mpex->Parm16.WndProc.lParam = stackalloc16(sizeof(DELETEITEMSTRUCT16));
+ GETVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(DELETEITEMSTRUCT16), pdes16);
+
+ pdes16->CtlType = (WORD)lParam->CtlType;
+ pdes16->CtlID = (WORD)lParam->CtlID;
+ pdes16->itemID = (WORD)lParam->itemID;
+ pdes16->hwndItem = GETHWND16(lParam->hwndItem);
+ STOREDWORD(pdes16->itemData, lParam->itemData);
+
+ FLUSHVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(DELETEITEMSTRUCT16), pdes16);
+ FREEVDMPTR(pdes16);
+ }
+ }
+ else {
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ stackfree16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return(TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_SETFONT
+//
+
+BOOL FASTCALL WM32SetFont(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHFONT16(lpwm32mpex->uParam);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_QUERYDRAGICON
+
+BOOL FASTCALL WM32QueryDragIcon(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (!lpwm32mpex->fThunk) {
+ lpwm32mpex->lReturn = (LONG)HICON32(lpwm32mpex->lReturn);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_COMPAREITEM
+//
+
+BOOL FASTCALL WM32CompareItem(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ LPCOMPAREITEMSTRUCT lParam = (LPCOMPAREITEMSTRUCT) lpwm32mpex->lParam;
+
+
+ if (lpwm32mpex->fThunk) {
+ if (lParam) {
+
+ // BUGBUG -- The assumption here is that GlobalAlloc will never
+ // return a memory object that isn't word-aligned, so that we can
+ // assign word-aligned words directly; we have no idea whether the
+ // memory is dword-aligned or not however, so dwords must always
+ // be paranoidly stored with the STOREDWORD/STORELONG macros -JTP
+
+ lpwm32mpex->Parm16.WndProc.lParam = stackalloc16(sizeof(COMPAREITEMSTRUCT16));
+ putcompareitem16(lpwm32mpex->Parm16.WndProc.lParam, lParam);
+ }
+ }
+ else {
+ // BUGBUG 08-Apr-91 JeffPar -- Reflect changes back to 32-bit structure?
+ if (lpwm32mpex->Parm16.WndProc.lParam)
+ stackfree16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_NCCALCSIZE
+//
+
+BOOL FASTCALL WM32NCCalcSize(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ PNCCALCSIZE_PARAMS16 pnc16;
+ PNCCALCSIZE_PARAMS16 lpnc16;
+ VPWINDOWPOS16 vpwp16;
+ LPNCCALCSIZE_PARAMS lParam = (LPNCCALCSIZE_PARAMS)lpwm32mpex->lParam;
+ UINT cb;
+ VPVOID vp;
+
+
+ // lpwm32mpex->uParam == TRUE ? (lParam is LPNCCALCSIZE_PARAMS) : (lParam is LPRECT);
+ //
+
+ if (lpwm32mpex->fThunk) {
+ if (lParam) {
+ if (lpwm32mpex->uParam)
+ cb = sizeof(NCCALCSIZE_PARAMS16) + sizeof(WINDOWPOS16);
+ else
+ cb = sizeof(RECT16);
+
+
+ vp = (VPVOID)stackalloc16(cb);
+ lpwm32mpex->Parm16.WndProc.lParam = (LONG)vp;
+
+ putrect16((VPRECT16)vp, (LPRECT)lParam);
+ if (lpwm32mpex->uParam) {
+ pnc16 = (PNCCALCSIZE_PARAMS16)vp;
+ putrect16((VPRECT16)(&pnc16->rgrc[1]), &lParam->rgrc[1]);
+ putrect16((VPRECT16)(&pnc16->rgrc[2]), &lParam->rgrc[2]);
+
+ GETVDMPTR( pnc16, sizeof(NCCALCSIZE_PARAMS16), lpnc16 );
+
+ vpwp16 = (VPWINDOWPOS16)(pnc16+1);
+ lpnc16->lppos = (PWINDOWPOS16)vpwp16;
+
+ FREEVDMPTR( lpnc16 );
+
+ putwindowpos16( vpwp16, lParam->lppos );
+
+ }
+ }
+ }
+ else {
+ vp = (VPVOID)lpwm32mpex->Parm16.WndProc.lParam;
+ getrect16((VPRECT16)vp, (LPRECT)lParam);
+ if (lpwm32mpex->uParam) {
+ pnc16 = (PNCCALCSIZE_PARAMS16)vp;
+
+ getrect16((VPRECT16)(&pnc16->rgrc[1]), &lParam->rgrc[1]);
+ getrect16((VPRECT16)(&pnc16->rgrc[2]), &lParam->rgrc[2]);
+
+ GETVDMPTR( pnc16, sizeof(NCCALCSIZE_PARAMS16), lpnc16 );
+
+ vpwp16 = (VPWINDOWPOS16)lpnc16->lppos;
+
+ FREEVDMPTR( lpnc16 );
+
+ getwindowpos16( vpwp16, lParam->lppos );
+
+
+ }
+ stackfree16(vp);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_COMMAND
+//
+
+BOOL FASTCALL WM32Command(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ // it's from a control
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = HIWORD(lpwm32mpex->uParam);
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = GETHWND16(lpwm32mpex->lParam);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_TIMER
+//
+
+BOOL FASTCALL WM32Timer(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+
+ /*
+ ** map the timer number and the timer proc address (cause its easy)
+ */
+ PTMR ptmr;
+
+ ptmr = FindTimer32((HAND16)GETHWND16(lpwm32mpex->hwnd), lpwm32mpex->uParam);
+
+ if ( !ptmr ) {
+ /*
+ ** Edit controls create their own timer, which can safely be
+ ** thunked to itself.
+ */
+ if ( lpwm32mpex->lParam || HIWORD(lpwm32mpex->uParam) ) {
+ LOGDEBUG(LOG_WARNING,(" WM32Timer ERROR: cannot find timer %08x\n", lpwm32mpex->uParam));
+ }
+ return TRUE;
+ }
+
+ lpwm32mpex->Parm16.WndProc.lParam = ptmr->vpfnTimerProc;
+ }
+
+ return (TRUE);
+}
+
+
+
+
+// This function thunks the messages,
+//
+// WM_HSCROLL
+// WM_VSCROLL
+//
+
+BOOL FASTCALL WM32HScroll(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = HIWORD(lpwm32mpex->uParam);
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = GETHWND16(lpwm32mpex->lParam);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_INITMENU
+// WM_INITMENUPOPUP
+//
+
+BOOL FASTCALL WM32InitMenu(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHMENU16(lpwm32mpex->uParam);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_MENUSELECT
+//
+
+BOOL FASTCALL WM32MenuSelect(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+
+ // Copy the menu flags
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = HIWORD(lpwm32mpex->uParam);
+
+ // Copy the "main" menu
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = GETHMENU16(lpwm32mpex->lParam);
+
+ if (HIWORD(lpwm32mpex->uParam) == 0xFFFF || !(HIWORD(lpwm32mpex->uParam) & MF_POPUP)) {
+ lpwm32mpex->Parm16.WndProc.wParam = LOWORD(lpwm32mpex->uParam); // Its an ID
+ }
+ else {
+ // convert menu index into menu handle
+ lpwm32mpex->Parm16.WndProc.wParam = GETHMENU16(GetSubMenu((HMENU)lpwm32mpex->lParam, LOWORD(lpwm32mpex->uParam)));
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_MENUCHAR
+//
+
+BOOL FASTCALL WM32MenuChar(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = HIWORD(lpwm32mpex->uParam);
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = GETHMENU16(lpwm32mpex->lParam);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_ENTERIDLE
+//
+
+BOOL FASTCALL WM32EnterIdle(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ if ((lpwm32mpex->uParam == MSGF_DIALOGBOX) || (lpwm32mpex->uParam == MSGF_MENU)) {
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = GETHWND16(lpwm32mpex->lParam);
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = 0;
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS,(" WOW::WM_ENTERIDLE: wParam has unknown value, wParam=%08x, Contact ChandanC\n", lpwm32mpex->uParam));
+ }
+ }
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_PARENTNOTIFY
+//
+
+BOOL FASTCALL WM32ParentNotify(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ if ((LOWORD(lpwm32mpex->uParam) == WM_CREATE) || (LOWORD(lpwm32mpex->uParam) == WM_DESTROY)) {
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = HIWORD(lpwm32mpex->uParam);
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = GETHWND16(lpwm32mpex->lParam);
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_MDICreate
+//
+
+BOOL FASTCALL WM32MDICreate(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ INT cb;
+ VPVOID vp;
+ register PMDICREATESTRUCT16 pmcs16;
+ LPMDICREATESTRUCT lParam = (LPMDICREATESTRUCT) lpwm32mpex->lParam;
+
+
+ if (lpwm32mpex->fThunk) {
+ if (lParam) {
+
+ lpwm32mpex->dwParam = (DWORD)0;
+ if (lParam->szClass) {
+ if ( HIWORD(lParam->szClass) == 0 ) {
+ vp = (VPVOID)lParam->szClass;
+ }
+ else {
+ cb = strlen(lParam->szClass)+1;
+ if (!(vp = malloc16(cb)))
+ goto Error;
+ putstr16(vp, lParam->szClass, cb);
+ }
+ }
+ else {
+ vp = (VPVOID)NULL;
+ }
+
+ //
+ // pfs:windowsworks overwrite pszclass, so we need to save the
+ // so that we can free the memory we just alloced
+ //
+ lpwm32mpex->dwParam = (DWORD)vp;
+
+ if (lParam->szTitle) {
+ cb = strlen(lParam->szTitle)+1;
+ if (!(vp = malloc16(cb)))
+ goto Error;
+ putstr16(vp, lParam->szTitle, cb);
+ }
+ else {
+ vp = (VPVOID)NULL;
+ }
+
+ // BUGBUG -- The assumption here is that GlobalAlloc will never
+ // return a memory object that isn't word-aligned, so that we can
+ // assign word-aligned words directly; we have no idea whether the
+ // memory is dword-aligned or not however, so dwords must always
+ // be paranoidly stored with the STOREDWORD/STORELONG macros -JTP
+
+ if (!(lpwm32mpex->Parm16.WndProc.lParam = malloc16(sizeof(MDICREATESTRUCT16))))
+ goto Error;
+
+ GETVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(MDICREATESTRUCT16), pmcs16);
+ STOREDWORD(pmcs16->vpszClass, lpwm32mpex->dwParam);
+ STOREDWORD(pmcs16->vpszTitle, vp);
+ pmcs16->hOwner = GETHINST16(lParam->hOwner);
+ pmcs16->x = (SHORT)lParam->x;
+ pmcs16->y = (SHORT)lParam->y;
+ pmcs16->cx = (SHORT)lParam->cx;
+ pmcs16->cy = (SHORT)lParam->cy;
+ STORELONG(pmcs16->style, lParam->style);
+ STORELONG(pmcs16->lParam, lParam->lParam);
+
+ FLUSHVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(MDICREATESTRUCT16), pmcs16);
+ FREEVDMPTR(pmcs16);
+
+ return (TRUE);
+
+ Error:
+ LOGDEBUG(LOG_ALWAYS,(" !!!! WM32MDICreate, WM_MDICREATE thunking failed !!!! Window %08lX ", lpwm32mpex->hwnd));
+ if (HIW16(lpwm32mpex->dwParam)) free16(lpwm32mpex->dwParam);
+ if (vp) free16(vp);
+ return FALSE;
+ }
+ }
+ else {
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ GETVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(MDICREATESTRUCT16), pmcs16);
+
+ if (FETCHDWORD(pmcs16->vpszTitle)) {
+ free16(FETCHDWORD(pmcs16->vpszTitle));
+ }
+
+ FREEVDMPTR(pmcs16);
+
+ // if HIWORD(class) is zero, class is an atom, else a pointer.
+
+ if (HIW16(lpwm32mpex->dwParam)) {
+ free16(lpwm32mpex->dwParam);
+ }
+
+
+ lpwm32mpex->lReturn = (LONG)HWND32(LOWORD(lpwm32mpex->lReturn));
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_MDIActivate
+//
+
+BOOL FASTCALL WM32MDIActivate(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ BOOL fHwndIsMdiChild;
+
+
+ if (lpwm32mpex->fThunk) {
+
+ // the format of the message is different based on the window that's
+ // receiving the message. If 'hwnd' is a MdiClient window it is of one
+ // form and if 'hwnd' is MdiChild it is of another form. We need to
+ // distinguish between the formats to correctly thunk the message.
+ //
+ // NOTE: we donot make calls like GetClassName because they are
+ // expensive and also I think we came across a case where a
+ // window of 'wow private class' processes these messages
+ //
+ // - Nanduri
+
+ if (lpwm32mpex->lParam) {
+
+ // lParam != NULL. The message is definitely going to a MdiChild.
+ //
+
+ fHwndIsMdiChild = TRUE;
+ }
+ else {
+
+ // lParam == NULL, doesnot necessarily mean that the message is
+ // going to a MdiClient window. So distinguish...
+
+ if (lpwm32mpex->uParam && (GETHWND16(lpwm32mpex->hwnd) ==
+ GETHWND16(lpwm32mpex->uParam))) {
+
+ // if hwnd is same as uParam then definitely hwnd is a MdiChild
+ // window. (because if hwnd is a MdiClient then uParam will be
+ // a MdiChild and thus they will not be equal)
+
+ fHwndIsMdiChild = TRUE;
+ }
+ else {
+ fHwndIsMdiChild = FALSE;
+ }
+
+ }
+
+ if (fHwndIsMdiChild) {
+ lpwm32mpex->Parm16.WndProc.wParam =
+ (WORD)(GETHWND16(lpwm32mpex->hwnd) == GETHWND16(lpwm32mpex->lParam));
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = GETHWND16(lpwm32mpex->lParam);
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = GETHWND16(lpwm32mpex->uParam);
+ } else {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+ lpwm32mpex->Parm16.WndProc.lParam = 0;
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_MDIGETACTIVE
+//
+
+BOOL FASTCALL WM32MDIGetActive(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.lParam = 0;
+ }
+ else {
+
+ if (lpwm32mpex->lParam != 0)
+ *((LPBOOL)lpwm32mpex->lParam) = (BOOL)HIWORD(lpwm32mpex->lReturn);
+
+ lpwm32mpex->lReturn = (LONG)HWND32(LOWORD(lpwm32mpex->lReturn));
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_MDISETMENU
+//
+
+BOOL FASTCALL WM32MDISetMenu(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ if (lpwm32mpex->uMsg == WM_MDIREFRESHMENU) {
+ lpwm32mpex->Parm16.WndProc.wParam = TRUE;
+ lpwm32mpex->Parm16.WndProc.wMsg = WM_MDISETMENU;
+ }
+ else {
+ lpwm32mpex->Parm16.WndProc.wParam = 0;
+ }
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = GETHMENU16(lpwm32mpex->uParam);
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = GETHMENU16(lpwm32mpex->lParam);
+ }
+ else {
+ lpwm32mpex->lReturn = (LONG)HMENU32(lpwm32mpex->lReturn);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_SIZECLIPBOARD
+// WM_PAINTCLIPBOARD
+//
+
+
+BOOL FASTCALL WM32SizeClipBoard(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ HAND16 hMem16 = 0;
+ VPVOID vp;
+ LPRECT lp;
+
+
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+
+ vp = GlobalAllocLock16(GMEM_MOVEABLE, (lpwm32mpex->uMsg == WM_SIZECLIPBOARD) ?
+ sizeof(RECT) : sizeof(PAINTSTRUCT), &hMem16);
+ if (vp) {
+ if (lp = (LPRECT) GlobalLock((HANDLE) lpwm32mpex->lParam)) {
+ if (lpwm32mpex->uMsg == WM_SIZECLIPBOARD) {
+ PUTRECT16(vp, lp);
+ }
+ else {
+ putpaintstruct16(vp, (LPPAINTSTRUCT) lp);
+ }
+ GlobalUnlock((HANDLE) lpwm32mpex->lParam);
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS, ("WOW::WM32SizeClipboard: Couldn't lock 32 bit memory handle!\n"));
+ // WOW32ASSERT (FALSE);
+ }
+
+ GlobalUnlock16(hMem16);
+ }
+ else {
+ hMem16 = 0;
+ LOGDEBUG(LOG_ALWAYS, ("WOW::WM32SizeClipboard: Couldn't allocate memory !\n"));
+ WOW32ASSERT (FALSE);
+ }
+
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) hMem16;
+ }
+ else {
+ if (LOW(lpwm32mpex->Parm16.WndProc.lParam)) {
+ GlobalUnlockFree16(GlobalLock16(LOW(lpwm32mpex->Parm16.WndProc.lParam), NULL));
+ }
+ }
+
+ return (TRUE);
+}
+
+
+
+// This function thunks the messages,
+//
+// WM_ASKCBFORMATNAME
+//
+
+
+BOOL FASTCALL WM32AskCBFormatName(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.lParam = malloc16(lpwm32mpex->Parm16.WndProc.wParam);
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ putstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, lpwm32mpex->uParam);
+ }
+
+ return (BOOL)lpwm32mpex->Parm16.WndProc.lParam;
+ }
+ else {
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ getstr16((VPSZ)lpwm32mpex->Parm16.WndProc.lParam, (LPSZ)lpwm32mpex->lParam, lpwm32mpex->uParam);
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_CHANGECBCHAIN
+//
+
+BOOL FASTCALL WM32ChangeCBChain(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+ lpwm32mpex->Parm16.WndProc.lParam = GETHWND16(lpwm32mpex->lParam);
+ }
+
+ return (TRUE);
+}
+
+
+
+// This function thunks the messages,
+//
+// WM_DDEINITIATE
+//
+
+BOOL FASTCALL WM32DDEInitiate(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+ lpwm32mpex->Parm16.WndProc.lParam = lpwm32mpex->lParam;
+ WI32DDEAddInitiator(lpwm32mpex->Parm16.WndProc.wParam);
+ }
+ else {
+ WI32DDEDeleteInitiator((HAND16)GETHWND16(lpwm32mpex->uParam));
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_DDEACK
+//
+
+BOOL FASTCALL WM32DDEAck(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+
+ if (WI32DDEInitiate((HAND16)GETHWND16(lpwm32mpex->hwnd))) {
+ //
+ // Initiate ACK
+ //
+ lpwm32mpex->Parm16.WndProc.lParam = lpwm32mpex->lParam;
+ }
+ else {
+ //
+ // NON-Initiate ACK
+ //
+
+ UINT lLo = 0;
+ UINT lHi = 0;
+ PHDDE pDdeNode;
+
+ UnpackDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam, &lLo, &lHi);
+
+ if (!HIWORD(lHi)) {
+ //
+ // NON-Execute ACK
+ //
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) lHi;
+ }
+ else {
+ //
+ // Execute ACK
+ //
+
+ //
+ // The order of To_hwnd and From_hwnd is reversed in the following
+ // DDEFirstPair16(), below. This is done to locate the h32.
+ //
+
+ pDdeNode = DDEFindAckNode ((HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ (HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HANDLE) lHi);
+
+ if (pDdeNode) {
+ if (pDdeNode->DdeMsg == WM_DDE_EXECUTE) {
+
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = pDdeNode->hMem16;
+
+ if (lpwm32mpex->fFree) {
+ if (lHi) {
+ if (pDdeNode->DdeFlags & DDE_EXECUTE_FREE_MEM) {
+ LOGDEBUG (12, ("WOW::W32DDEAck : Freeing EXECUTE pair h16 = %04x, h32 = %08x\n",
+ pDdeNode->hMem16, lHi));
+ W32UnMarkDDEHandle (pDdeNode->hMem16);
+ GlobalUnlockFree16(GlobalLock16(pDdeNode->hMem16, NULL));
+ if (DDEDeletehandle(pDdeNode->hMem16, (HANDLE) lHi)) {
+ GlobalFree((HANDLE)lHi);
+ }
+ else {
+ LOGDEBUG (0, ("WOW::DDE Ack : Ack can't find 16 - 32 aliasing : %04x, %04x, %04x, %08lx, %08lx\n", lpwm32mpex->hwnd, lpwm32mpex->uMsg, lpwm32mpex->Parm16.WndProc.wParam, lpwm32mpex->Parm16.WndProc.lParam, lHi)
+);
+ }
+ }
+ else {
+ if (pDdeNode->DdeFlags & DDE_EXECUTE_FREE_H16) {
+ W32UnMarkDDEHandle (pDdeNode->hMem16);
+ GlobalUnlockFree16(GlobalLock16(pDdeNode->hMem16, NULL));
+
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = pDdeNode->h16;
+ }
+
+ if (DDEDeletehandle(pDdeNode->hMem16, (HANDLE) lHi)) {
+ GlobalFree((HANDLE)lHi);
+ }
+ else {
+ LOGDEBUG (0, ("WOW::DDE Ack : Ack can't find 16 - 32 aliasing : %04x, %04x, %04x, %08lx, %08lx\n", lpwm32mpex->hwnd, lpwm32mpex->uMsg, lpwm32mpex->Parm16.WndProc.wParam, lpwm32mpex->Parm16.WndProc.lParam, lHi)
+);
+ }
+
+
+ }
+ }
+ else {
+ LOGDEBUG (2, ("WOW::W32DDEAck : h32 is NULL \n"));
+ WOW32ASSERT (FALSE);
+ }
+ }
+ }
+ else {
+ LOGDEBUG (2, ("WOW::DDE Ack : Ack received for bogus Execute : %04x, %04x, %04x, %08lx, %08lx\n", lpwm32mpex->hwnd, lpwm32mpex->uMsg, lpwm32mpex->Parm16.WndProc.wParam, lpwm32mpex->Parm16.WndProc.lParam, lHi));
+ }
+ } else {
+ LOGDEBUG (2, ("WOW::DDE Ack : Ack received for bogus Execute : %04x, %04x, %04x, %08lx, %08lx\n", lpwm32mpex->hwnd, lpwm32mpex->uMsg, lpwm32mpex->Parm16.WndProc.wParam, lpwm32mpex->Parm16.WndProc.lParam, lHi));
+ // We will get here when thunking a
+ // WM_DDE_ACK message when dispatching to a message
+ // filter hookproc and both parties of the DDE
+ // conversation are 32 bit and thus not in the WOW dde
+ // tables. Only fire this assert in the case where we
+ // are thunking this message for calling a windproc.
+ WOW32ASSERT(! lpwm32mpex->fFree);
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = 0;
+ }
+
+ }
+
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) lLo;
+
+ if (fThunkDDEmsg) {
+ FreeDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam);
+ }
+
+ LOGDEBUG (12, ("WOW::DDE Ack : %04x, %04x, %04x, %08lx, %08lx\n", lpwm32mpex->hwnd, lpwm32mpex->uMsg, lpwm32mpex->Parm16.WndProc.wParam, lpwm32mpex->Parm16.WndProc.lParam, lHi));
+ }
+ }
+ else {
+ //
+ // We will execute this scenario only if the app ate the message,
+ // because we need to free up the memory.
+ //
+
+ if (!fThunkDDEmsg) {
+ if (lpwm32mpex->lReturn) {
+ FreeDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_DDEREQUEST
+// WM_DDETERMINATE
+// WM_DDEUNADVISE
+//
+
+BOOL FASTCALL WM32DDERequest(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_DDEADVISE
+//
+
+BOOL FASTCALL WM32DDEAdvise(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ HAND16 h16;
+ VPVOID vp;
+ LPBYTE lpMem16;
+ LPBYTE lpMem32;
+ UINT lLo = 0;
+ UINT lHi = 0;
+ DDEINFO DdeInfo;
+
+
+ if (lpwm32mpex->fThunk) {
+ UnpackDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam, &lLo, &lHi);
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+
+ if (h16 = DDEFindPair16((HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ (HANDLE) lLo)) {
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = h16;
+ } else {
+ vp = GlobalAllocLock16(GMEM_DDESHARE, sizeof(DDEADVISE), &h16);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ lpMem32 = GlobalLock((HANDLE) lLo);
+ RtlCopyMemory(lpMem16, lpMem32, sizeof(DDEADVISE));
+ GlobalUnlock((HANDLE) lLo);
+ GlobalUnlock16(h16);
+ DdeInfo.Msg = lpwm32mpex->uMsg;
+ DdeInfo.Format = 0;
+ DdeInfo.Flags = DDE_PACKET;
+ DdeInfo.h16 = 0;
+ DDEAddhandle((HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ h16,
+ (HANDLE) lLo,
+ &DdeInfo);
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = h16;
+ }
+ }
+
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) lHi;
+
+ if (fThunkDDEmsg) {
+ FreeDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam);
+ }
+ }
+ else {
+ //
+ // We will execute this scenario only if the app ate the message,
+ // because we need to free up the memory.
+ //
+
+ if (!fThunkDDEmsg) {
+ if (lpwm32mpex->lReturn) {
+ FreeDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_DDEDATA
+//
+
+BOOL FASTCALL WM32DDEData(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ HAND16 h16;
+ UINT lLo = 0;
+ UINT lHi = 0;
+ DDEINFO DdeInfo;
+
+
+ if (lpwm32mpex->fThunk) {
+ UnpackDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam, &lLo, &lHi);
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+
+ if (!lLo) {
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = 0;
+ } else if (h16 = DDEFindPair16((HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ (HANDLE) lLo)) {
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = h16;
+ } else {
+ DdeInfo.Msg = lpwm32mpex->uMsg;
+ h16 = DDECopyhData16((HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ (HANDLE) lLo,
+ &DdeInfo);
+
+ //
+ // If we could not allocate 16 bit memory, then return NULL to the
+ // caller.
+ //
+
+ if (!h16) {
+ if (fThunkDDEmsg) {
+ FreeDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam);
+ }
+
+ lpwm32mpex->Parm16.WndProc.wParam = (WORD) lHi;
+ lpwm32mpex->Parm16.WndProc.lParam = lLo;
+ return (0);
+ }
+
+
+ DdeInfo.Flags = DDE_PACKET;
+ DdeInfo.h16 = 0;
+ DDEAddhandle((HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ h16,
+ (HANDLE) lLo,
+ &DdeInfo);
+
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = h16;
+ }
+
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) lHi;
+
+ if (fThunkDDEmsg) {
+ FreeDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam);
+ }
+
+
+ }
+ else {
+
+ //
+ // We will execute this scenario only if the app ate the message,
+ // because we need to free up the memory.
+ //
+
+ if (!fThunkDDEmsg) {
+ if (lpwm32mpex->lReturn) {
+ FreeDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_POKE
+//
+
+BOOL FASTCALL WM32DDEPoke(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ HAND16 h16;
+ UINT lLo = 0;
+ UINT lHi = 0;
+ DDEINFO DdeInfo;
+
+
+ if (lpwm32mpex->fThunk) {
+ UnpackDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam, &lLo, &lHi);
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+
+ // sudeepb 03-Apr-1996
+ // House Design Gold Edition sends a DDE_POKE message with lParam
+ // being 0. We are suppose to thunk this message with lParam being
+ // zero. Without this check, the below code will fail this call
+ // and the message will not be thunked to the app.
+
+ if (lLo == 0) {
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = 0;
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) lHi;
+ return (TRUE);
+ }
+
+ if (h16 = DDEFindPair16((HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ (HANDLE) lLo)) {
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = h16;
+ } else {
+ DdeInfo.Msg = lpwm32mpex->uMsg;
+ h16 = DDECopyhData16((HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ (HANDLE) lLo,
+ &DdeInfo);
+
+
+ //
+ // If we could not allocate 16 bit memory, then return NULL to the
+ // caller.
+ //
+
+ if (!h16) {
+ if (fThunkDDEmsg) {
+ FreeDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam);
+ }
+
+ lpwm32mpex->Parm16.WndProc.lParam = lLo;
+ return (0);
+ }
+
+ DdeInfo.Flags = DDE_PACKET;
+ DdeInfo.h16 = 0;
+ DDEAddhandle((HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ h16,
+ (HANDLE) lLo,
+ &DdeInfo);
+
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = h16;
+ }
+
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) lHi;
+
+ if (fThunkDDEmsg) {
+ FreeDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam);
+ }
+ }
+ else {
+ //
+ // We will execute this scenario only if the app ate the message,
+ // because we need to free up the memory.
+ //
+
+ if (!fThunkDDEmsg) {
+ if (lpwm32mpex->lReturn) {
+ FreeDDElParam(lpwm32mpex->uMsg, lpwm32mpex->lParam);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_EXECUTE
+//
+
+BOOL FASTCALL WM32DDEExecute(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ HAND16 h16;
+ VPVOID vp;
+ LPBYTE lpMem16;
+ LPBYTE lpMem32;
+ DDEINFO DdeInfo;
+
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+
+ if (h16 = DDEFindPair16((HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ (HANDLE) lpwm32mpex->lParam)) {
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = h16;
+ } else {
+ vp = GlobalAllocLock16(GMEM_DDESHARE, GlobalSize((HANDLE) lpwm32mpex->lParam), &h16);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ lpMem32 = GlobalLock((HANDLE) lpwm32mpex->lParam);
+ RtlCopyMemory(lpMem16, lpMem32, GlobalSize((HANDLE) lpwm32mpex->lParam));
+ GlobalUnlock((HANDLE) lpwm32mpex->lParam);
+ GlobalUnlock16(h16);
+
+ DdeInfo.Msg = lpwm32mpex->uMsg;
+ DdeInfo.Format = 0;
+ DdeInfo.Flags = DDE_PACKET;
+ DdeInfo.h16 = 0;
+ DDEAddhandle((HAND16)GETHWND16(lpwm32mpex->hwnd),
+ (HAND16)lpwm32mpex->Parm16.WndProc.wParam,
+ h16,
+ (HANDLE) lpwm32mpex->lParam,
+ &DdeInfo);
+
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = h16;
+ }
+ }
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = 0;
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_CTLCOLORMSGBOX
+// WM_CTLCOLOREDIT
+// WM_CTLCOLORLISTBOX
+// WM_CTLCOLORBTN
+// WM_CTLCOLORDLG
+// WM_CTLCOLORSCROLLBAR
+// WM_CTLCOLORSTATIC
+//
+// into WM_CTLCOLOR and the high word of lParam specifies the
+// control type.
+//
+
+BOOL FASTCALL WM32CtlColor(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = WM_CTLCOLOR;
+ if(lpwm32mpex->uMsg != WM_CTLCOLOR) { // see 16-bit thunk for this special case
+ lpwm32mpex->Parm16.WndProc.wParam = GETHDC16(lpwm32mpex->uParam);
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = GETHWND16(lpwm32mpex->lParam);
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = (WORD) (lpwm32mpex->uMsg - WM_CTLCOLORMSGBOX);
+ }
+ }
+ else {
+ if ((ULONG)lpwm32mpex->lReturn > COLOR_ENDCOLORS) {
+ lpwm32mpex->lReturn = (LONG) HBRUSH32(lpwm32mpex->lReturn);
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_GETFONT
+//
+
+BOOL FASTCALL WM32GetFont(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (!lpwm32mpex->fThunk) {
+ lpwm32mpex->lReturn = (LONG)HFONT32(lpwm32mpex->lReturn);
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_NEXTMENU
+//
+// Win16 NT
+// wParam VK_KEY VK_KEY
+// lParam.l hmenu PMDINEXTMENU
+// lParam.h 0
+// return.l menu BOOL
+// return.h window
+//
+
+
+BOOL FASTCALL WM32NextMenu(LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (lpwm32mpex->fThunk) {
+ if (lpwm32mpex->lParam) {
+ LOW(lpwm32mpex->Parm16.WndProc.lParam) = GETHMENU16(((PMDINEXTMENU)lpwm32mpex->lParam)->hmenuIn);
+ HIW(lpwm32mpex->Parm16.WndProc.lParam) = 0;
+ }
+ } else {
+ if (lpwm32mpex->lParam) {
+ ((PMDINEXTMENU)lpwm32mpex->lParam)->hmenuNext = HMENU32(LOWORD(lpwm32mpex->lReturn));
+ ((PMDINEXTMENU)lpwm32mpex->lParam)->hwndNext = HWND32(HIWORD(lpwm32mpex->lReturn));
+ lpwm32mpex->lReturn = TRUE;
+ } else {
+ lpwm32mpex->lReturn = FALSE;
+ }
+ }
+
+ return (TRUE);
+}
+
+
+BOOL FASTCALL WM32Destroy (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ if (!lpwm32mpex->fThunk) {
+ if (CACHENOTEMPTY()) {
+ // because of our method of window aliasing, 'hwnd' may or may
+ // not be a real 32bit handle. ie. it may be (hwnd16 | 0xffff0000).
+ // So always use hwnd16.
+
+ ReleaseCachedDCs((CURRENTPTD())->htask16, GETHWND16(lpwm32mpex->hwnd), 0,
+ (HWND)0, SRCHDC_TASK16_HWND16);
+ }
+ }
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+// WM_DROPFILES
+
+BOOL FASTCALL WM32DropFiles(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ if (lpwm32mpex->fThunk) {
+ return (BOOL)(lpwm32mpex->Parm16.WndProc.wParam = GETHDROP16(lpwm32mpex->uParam));
+ }
+
+ return (TRUE);
+}
+
+
+
+// This function thunks the messages,
+//
+// WM_DROPOBJECT
+// WM_QUERYDROPOBJECT
+// WM_DRAGLOOP
+// WM_DRAGSELECT
+// WM_DRAGMOVE
+//
+
+BOOL FASTCALL WM32DropObject(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ register PDROPSTRUCT16 pds16;
+ register LPDROPSTRUCT lParam = (LPDROPSTRUCT)lpwm32mpex->lParam;
+
+ if (lpwm32mpex->fThunk) {
+
+ lpwm32mpex->Parm16.WndProc.wParam = (WORD)lpwm32mpex->uParam;
+
+ // BUGBUG -- The assumption here is that GlobalAlloc will never
+ // return a memory object that isn't word-aligned, so that we can
+ // assign word-aligned words directly; we have no idea whether the
+ // memory is dword-aligned or not however, so dwords must always
+ // be paranoidly stored with the STOREDWORD/STORELONG macros -JTP
+
+ if (!(lpwm32mpex->Parm16.WndProc.lParam = malloc16(sizeof(DROPSTRUCT16))))
+ return FALSE;
+
+ GETVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(DROPSTRUCT16), pds16);
+
+ pds16->hwndSource = GETHWND16(lParam->hwndSource);
+ pds16->hwndSink = GETHWND16(lParam->hwndSink);
+ pds16->wFmt = (WORD) lParam->wFmt;
+ STOREDWORD(pds16->dwData, lParam->dwData);
+
+ pds16->ptDrop.x = (SHORT)lParam->ptDrop.x;
+ pds16->ptDrop.y = (SHORT)lParam->ptDrop.y;
+ STOREDWORD(pds16->dwControlData, lParam->dwControlData);
+
+ FLUSHVDMPTR(lpwm32mpex->Parm16.WndProc.lParam, sizeof(DROPSTRUCT16), pds16);
+ FREEVDMPTR(pds16);
+
+ } else {
+
+ free16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+
+ if (lpwm32mpex->uMsg == WM_QUERYDROPOBJECT) {
+
+ //
+ // Return value is either TRUE, FALSE,
+ // or a cursor!
+ //
+ if (lpwm32mpex->lReturn && lpwm32mpex->lReturn != (LONG)TRUE) {
+ lpwm32mpex->lReturn = (LONG)HCURSOR32(lpwm32mpex->lReturn);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+
+// This function thunks the messages,
+//
+// WM_WINDOWPOSCHANGING
+// WM_WINDOWPOSCHANGED
+//
+
+BOOL FASTCALL WM32WindowPosChanging (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ LPWINDOWPOS lParam = (LPWINDOWPOS) lpwm32mpex->lParam;
+
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.lParam = stackalloc16(sizeof(WINDOWPOS16));
+ putwindowpos16( (VPWINDOWPOS16)lpwm32mpex->Parm16.WndProc.lParam, lParam );
+
+ }
+ else {
+ getwindowpos16( (VPWINDOWPOS16)lpwm32mpex->Parm16.WndProc.lParam, lParam );
+ stackfree16((VPVOID) lpwm32mpex->Parm16.WndProc.lParam);
+ }
+
+ return (TRUE);
+}
+
+// This function thunks the message,
+//
+// WM_COPYDATA
+//
+
+BOOL FASTCALL WM32CopyData (LPWM32MSGPARAMEX lpwm32mpex)
+{
+
+ HAND16 h16;
+ HAND16 hMem16;
+ VPVOID vpCDS16;
+ VPVOID vpData16;
+ LPBYTE lpMem16;
+ PCOPYDATASTRUCT lpCDS32;
+ PCOPYDATASTRUCT lpCDS16;
+ PCPDATA pTemp;
+
+
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+
+ if (vpCDS16 = CopyDataFindData16 (GETHWND16(lpwm32mpex->hwnd), lpwm32mpex->Parm16.WndProc.wParam, lpwm32mpex->lParam)) {
+ lpwm32mpex->Parm16.WndProc.lParam = vpCDS16;
+ }
+ else {
+ vpCDS16 = GlobalAllocLock16(GMEM_DDESHARE, sizeof(COPYDATASTRUCT), &h16);
+ if (vpCDS16) {
+ GETMISCPTR(vpCDS16, lpCDS16);
+ lpCDS32 = (PCOPYDATASTRUCT) lpwm32mpex->lParam;
+ lpCDS16->dwData = lpCDS32->dwData;
+ if (lpCDS16->cbData = lpCDS32->cbData) {
+
+ FREEMISCPTR(lpCDS16);
+
+ vpData16 = GlobalAllocLock16(GMEM_DDESHARE, lpCDS32->cbData, &hMem16);
+ GETMISCPTR(vpData16, lpMem16);
+ if (lpMem16 && lpCDS32->lpData) {
+ RtlCopyMemory(lpMem16, lpCDS32->lpData, lpCDS32->cbData);
+ CopyDataAddNode (GETHWND16(lpwm32mpex->hwnd), lpwm32mpex->Parm16.WndProc.wParam, vpData16, (DWORD) lpCDS32->lpData, 0);
+ }
+ FREEMISCPTR(lpMem16);
+
+ GETMISCPTR(vpCDS16, lpCDS16);
+ lpCDS16->lpData = (PVOID) vpData16;
+ }
+ else {
+ lpCDS16->lpData = NULL;
+ }
+ FREEMISCPTR(lpCDS16);
+ }
+
+ lpwm32mpex->Parm16.WndProc.lParam = vpCDS16;
+ CopyDataAddNode (GETHWND16(lpwm32mpex->hwnd), lpwm32mpex->Parm16.WndProc.wParam, vpCDS16, lpwm32mpex->lParam, 0);
+ }
+ }
+ else {
+ if (lpwm32mpex->fFree) {
+ pTemp = CopyDataFindData32 (GETHWND16(lpwm32mpex->hwnd), GETHWND16(lpwm32mpex->uParam), lpwm32mpex->Parm16.WndProc.lParam);
+ if (pTemp && (!(pTemp->Flags))) {
+ GETMISCPTR(lpwm32mpex->Parm16.WndProc.lParam, lpCDS16);
+ GlobalUnlockFree16 ((VPVOID)lpCDS16->lpData);
+ CopyDataDeleteNode (GETHWND16(lpwm32mpex->hwnd), lpwm32mpex->Parm16.WndProc.wParam, (DWORD) ((PCOPYDATASTRUCT)lpwm32mpex->lParam)->lpData);
+ GlobalUnlockFree16 ((VPVOID)lpwm32mpex->Parm16.WndProc.lParam);
+ CopyDataDeleteNode (GETHWND16(lpwm32mpex->hwnd), lpwm32mpex->Parm16.WndProc.wParam, (DWORD) lpwm32mpex->lParam);
+ FREEMISCPTR(lpCDS16);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+// This function thunks the message,
+//
+// WM_WINHELP
+//
+
+BOOL FASTCALL WM32WinHelp (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ static WORD msgWinHelp = 0;
+ if (lpwm32mpex->fThunk) {
+ lpwm32mpex->Parm16.WndProc.wMsg = msgWinHelp ? msgWinHelp : (msgWinHelp = RegisterWindowMessage("WM_WINHELP"));
+ lpwm32mpex->Parm16.WndProc.wParam = GETHWND16(lpwm32mpex->uParam);
+ if (lpwm32mpex->lParam) {
+ // lpwm32mpex->lParam is LPHLP - however we need only the firstword,ie the size of data
+
+ HAND16 hMem16;
+ VPVOID vp;
+ LPBYTE lpT;
+ WORD cb;
+
+ cb = ((LPHLP)lpwm32mpex->lParam)->cbData;
+ if (vp = GlobalAllocLock16(GMEM_DDESHARE | GMEM_MOVEABLE, cb, &hMem16)) {
+ GETMISCPTR(vp, lpT);
+ RtlCopyMemory(lpT, (PVOID)lpwm32mpex->lParam, cb);
+ FREEMISCPTR(lpT);
+ }
+ lpwm32mpex->Parm16.WndProc.lParam = hMem16;
+ lpwm32mpex->dwParam = vp;
+ }
+ }
+ else {
+ // Make sure WinHelp is in the foreground
+ SetForegroundWindow(lpwm32mpex->hwnd);
+ if (lpwm32mpex->Parm16.WndProc.lParam) {
+ GlobalUnlockFree16((VPVOID)lpwm32mpex->dwParam);
+ }
+ }
+
+ return (TRUE);
+}
+
+//
+// Thunk the undocumented MM_CALCSCROLL MDI message. Message has no parameters,
+// but has different message values; 32-bit msg: 0x3F, 16-bit msg: 0x10AC.
+//
+BOOL FASTCALL WM32MMCalcScroll (LPWM32MSGPARAMEX lpwm32mpex)
+{
+ if ( lpwm32mpex->fThunk ) {
+ lpwm32mpex->Parm16.WndProc.wMsg = (WORD) WIN31_MM_CALCSCROLL;
+ }
+
+ return (TRUE);
+}
+
+// This function thunks the 32-bit message WM_NOTIFYWOW.
+// uParam dictates where the notification should be dispatched.
+//
+
+
+BOOL FASTCALL WM32NotifyWow(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ switch (lpwm32mpex->uParam) {
+ case WMNW_UPDATEFINDREPLACE:
+ if (lpwm32mpex->fThunk) {
+ // Update the 16-bit FINDREPLACE struct.
+ lpwm32mpex->Parm16.WndProc.lParam = WCD32UpdateFindReplaceTextAndFlags(lpwm32mpex->hwnd, lpwm32mpex->lParam);
+ lpwm32mpex->Parm16.WndProc.wMsg = msgFINDREPLACE;
+ return(TRUE);
+ }
+ break;
+
+ default:
+ LOGDEBUG(LOG_ALWAYS, ("WOW::WM32NotifyWow: Unknown dispatch parameter!\n"));
+ WOW32ASSERT (FALSE);
+
+ }
+
+ return (FALSE);
+}
+
+//
+// In ThunkMsg16 we use the data in 32->16 message thunk table to optimize
+// thunking process based on 'WM32NoThunking'.
+//
+// This is place holder for those messages which need nothunking on 32-16
+// trasitions but need some kind of thunking on 16->32 transistions.
+//
+// So this marks the message as 'this message needs 16-32 thunking but
+// not 32-16 thunking'
+//
+// - nanduri
+
+BOOL FASTCALL WM32Thunk16To32(LPWM32MSGPARAMEX lpwm32mpex)
+{
+ return (TRUE);
+}
diff --git a/private/mvdm/wow32/wmdisp32.h b/private/mvdm/wow32/wmdisp32.h
new file mode 100644
index 000000000..3527e452d
--- /dev/null
+++ b/private/mvdm/wow32/wmdisp32.h
@@ -0,0 +1,130 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMDISP32.H
+ * WOW32 32-bit message thunks
+ *
+ * History:
+ * Created 19-Feb-1992 by Chandan S. Chauhan (ChandanC)
+ * Changed 12-May-1992 by Mike Tricker (MikeTri) Added MultiMedia prototypes
+--*/
+#ifndef _DEF_WMDISP32_ // if this hasn't already been included
+#define _DEF_WMDISP32_
+
+
+/* Types
+ */
+
+//
+// W32MSGPARAMEX structure defined below is passed to all the 32->16
+// message thunks. pww provides quick access to WOW words, and
+// dwParam provides a DWORD to squirrel away a value during thunking
+// for use in unthunking. The scope of dwParam is strictly the
+// thunking and subsequent unthunking of one message.
+//
+
+typedef struct _WM32MSGPARAMEX *LPWM32MSGPARAMEX;
+typedef BOOL (FASTCALL LPFNM32PROTO)(LPWM32MSGPARAMEX lpwm32mpex);
+typedef LPFNM32PROTO *LPFNM32;
+
+typedef struct _WM32MSGPARAMEX {
+ HWND hwnd;
+ UINT uMsg;
+ UINT uParam;
+ LONG lParam;
+ PARM16 Parm16;
+ LPFNM32 lpfnM32; // function address
+ BOOL fThunk;
+ LONG lReturn;
+ PWW pww;
+ DWORD dwParam;
+ BOOL fFree;
+ DWORD dwTmp[2];
+} WM32MSGPARAMEX;
+
+/* Dispatch table entry
+ */
+typedef struct _M32 { /* w32 */
+ LPFNM32 lpfnM32; // function address
+#ifdef DEBUG_OR_WOWPROFILE
+ LPSZ lpszW32; // message name (DEBUG version only)
+ DWORD cCalls; // # times the message has been passed
+ DWORD cTics; // sum total of thunk tics
+#endif
+} M32, *PM32;
+
+extern BOOL fThunkDDEmsg;
+
+#define WIN31_MM_CALCSCROLL 0x10AC // WM_USER+0xCAC
+
+/* Function prototypes
+ */
+LONG W32Win16WndProcEx(HWND hwnd, UINT uMsg, UINT uParam, LONG lParam, DWORD dwCPD, PWW pww);
+
+LPFNM32PROTO WM32NoThunking;
+LPFNM32PROTO WM32Undocumented;
+LPFNM32PROTO WM32Create;
+LPFNM32PROTO WM32Activate;
+LPFNM32PROTO WM32VKeyToItem;
+LPFNM32PROTO WM32SetFocus;
+LPFNM32PROTO WM32SetText;
+LPFNM32PROTO WM32GetText;
+LPFNM32PROTO WM32EraseBkGnd;
+LPFNM32PROTO WM32ActivateApp;
+LPFNM32PROTO WM32RenderFormat;
+LPFNM32PROTO WM32GetMinMaxInfo;
+LPFNM32PROTO WM32NCPaint;
+LPFNM32PROTO WM32GetDlgCode;
+LPFNM32PROTO WM32NextDlgCtl;
+LPFNM32PROTO WM32DrawItem;
+LPFNM32PROTO WM32MeasureItem;
+LPFNM32PROTO WM32DeleteItem;
+LPFNM32PROTO WM32SetFont;
+LPFNM32PROTO WM32QueryDragIcon;
+LPFNM32PROTO WM32CompareItem;
+LPFNM32PROTO WM32NCCalcSize;
+LPFNM32PROTO WM32Command;
+LPFNM32PROTO WM32Timer;
+LPFNM32PROTO WM32HScroll;
+LPFNM32PROTO WM32InitMenu;
+LPFNM32PROTO WM32MenuSelect;
+LPFNM32PROTO WM32MenuChar;
+LPFNM32PROTO WM32EnterIdle;
+LPFNM32PROTO WM32ParentNotify;
+LPFNM32PROTO WM32MDICreate;
+LPFNM32PROTO WM32MDIActivate;
+LPFNM32PROTO WM32MDIGetActive;
+LPFNM32PROTO WM32MDISetMenu;
+LPFNM32PROTO WM32PaintClipBoard;
+LPFNM32PROTO WM32SizeClipBoard;
+LPFNM32PROTO WM32AskCBFormatName;
+LPFNM32PROTO WM32ChangeCBChain;
+LPFNM32PROTO WM32DDEInitiate;
+LPFNM32PROTO WM32DDEAck;
+LPFNM32PROTO WM32DDERequest;
+LPFNM32PROTO WM32DDEAdvise;
+LPFNM32PROTO WM32DDEData;
+LPFNM32PROTO WM32DDEPoke;
+LPFNM32PROTO WM32DDEExecute;
+LPFNM32PROTO WM32CtlColor;
+LPFNM32PROTO WM32GetFont;
+LPFNM32PROTO WM32MNFindMenuWindow;
+LPFNM32PROTO WM32NextMenu;
+LPFNM32PROTO WM32Destroy;
+LPFNM32PROTO WM32WindowPosChanging ;
+LPFNM32PROTO WM32DropFiles ;
+LPFNM32PROTO WM32DropObject ;
+LPFNM32PROTO WM32DestroyClipboard;
+LPFNM32PROTO WM32NextMenu;
+LPFNM32PROTO WM32CopyData;
+LPFNM32PROTO WM32MMCalcScroll;
+LPFNM32PROTO WM32Thunk16To32;
+LPFNM32PROTO WM32WinHelp;
+LPFNM32PROTO WM32NotifyWow;
+
+#endif // #ifndef _DEF_WMDISP32_ THIS SHOULD BE THE LAST LINE IN THIS FILE
+
+
diff --git a/private/mvdm/wow32/wmmalias.c b/private/mvdm/wow32/wmmalias.c
new file mode 100644
index 000000000..70bb0916c
--- /dev/null
+++ b/private/mvdm/wow32/wmmalias.c
@@ -0,0 +1,373 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMMALIAS.C
+ * WOW32 16-bit handle alias support
+ *
+ * History:
+ * Created Sept-1-1992 by Chandan Chauhan (ChandanC)
+ * Modified 12-May-1992 by Mike Tricker (miketri) to add MultiMedia support
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wmmalias.h"
+
+MODNAME(wmmalias.c);
+
+HINFO hiMMedia; // MultiMedia handle alias info - MikeTri 12-May-1992
+HINFO hiWinsock; // Winsock handle alias info - DavidTr 4-Oct-1992
+
+#ifdef DEBUG
+INT nAliases;
+#endif
+INT iLargestListSlot;
+
+extern CRITICAL_SECTION mmHandleCriticalSection;
+
+#ifdef DEBUG
+extern BOOL fSkipLog; // TRUE to temporarily skip certain logging
+#endif
+
+
+/*
+ * Added MultiMedia functions - MikeTri 12-May-1992
+ */
+
+HAND16 GetMMedia16(HAND32 h32, INT iClass)
+{
+ PHMAP phm;
+
+ EnterCriticalSection( &mmHandleCriticalSection );
+ if (phm = FindHMap32(h32, &hiMMedia, iClass)) {
+ LeaveCriticalSection( &mmHandleCriticalSection );
+ return phm->h16;
+ }
+ LeaveCriticalSection( &mmHandleCriticalSection );
+
+ return (HAND16)h32;
+}
+
+
+VOID FreeMMedia16(HAND16 h16)
+{
+ EnterCriticalSection( &mmHandleCriticalSection );
+ FreeHMap16(h16, &hiMMedia);
+ LeaveCriticalSection( &mmHandleCriticalSection );
+}
+
+
+HAND32 GetMMedia32(HAND16 h16)
+{
+ PHMAP phm;
+
+ EnterCriticalSection( &mmHandleCriticalSection );
+ if (phm = FindHMap16(h16, &hiMMedia)) {
+ LeaveCriticalSection( &mmHandleCriticalSection );
+ return phm->h32;
+ }
+ LeaveCriticalSection( &mmHandleCriticalSection );
+
+ return NULL;
+
+// return (HAND32)INT32(h16);
+}
+
+
+PHMAP FindHMap32(HAND32 h32, PHINFO phi, INT iClass)
+{
+ INT iHash;
+#ifndef NEWALIAS
+ INT iList, iListEmpty;
+#endif
+ register PHMAP phm, phmPrev, phmEmpty;
+
+ if (!h32 || (INT)h32 == 0xFFFF || (INT)h32 == -1)
+ return NULL;
+
+ // If we don't have a hash table yet, allocate one
+
+ if (!phi->pphmHash) {
+ if (!(phi->pphmHash = malloc_w(HASH_SLOTS*sizeof(PHMAP)))) {
+ LOGDEBUG(0,(" FindHMap32 ERROR: cannot allocate hash table\n"));
+ return NULL;
+ }
+ RtlZeroMemory(phi->pphmHash, HASH_SLOTS*sizeof(PHMAP));
+ }
+
+ // Compute the index into the hash table, and retrieve from it
+ // the initial HMAP pointer
+
+ iHash = HASH32(h32);
+ phmPrev = (PHMAP)(phi->pphmHash + iHash);
+
+ // Start walking the HMAP list, looking for a match (and keeping
+ // track of any free entries we may find in case we decide to reuse it)
+
+#ifndef NEWALIAS
+ iList = 1;
+#endif
+ phmEmpty = NULL;
+ while (phm = phmPrev->phmNext) {
+ if (MASK32(phm->h32) == MASK32(h32)) {
+ break;
+ }
+ if (phm->h32 == NULL && !phmEmpty) {
+ phmEmpty = phm;
+#ifndef NEWALIAS
+ iListEmpty = iList;
+#endif
+ }
+ phmPrev = phm;
+#ifndef NEWALIAS
+ iList++;
+#endif
+ }
+
+ // If we couldn't find a match but we did find an empty HMAP structure
+ // on the list, reuse it
+
+ if (!phm && phmEmpty) {
+ phm = phmEmpty;
+#ifndef NEWALIAS
+ iList = iListEmpty;
+#endif
+ }
+
+ // If we have to allocate a new HMAP, here's where we do it
+
+ if (!phm) {
+#ifndef NEWALIAS
+ if (iList > LIST_SLOTS) {
+ LOGDEBUG(0,(" FindHMap32 ERROR: out of list slots for hash slot %d\n", iHash));
+ return NULL;
+ }
+#else
+ // If we don't have an alias table yet, allocate one
+
+ if (!phi->pphmAlias) {
+ if (!(phi->pphmAlias = malloc_w(ALIAS_SLOTS*sizeof(PHMAP)))) {
+ LOGDEBUG(0,(" FindHMap32 ERROR: cannot allocate alias table\n"));
+ return NULL;
+ }
+ RtlZeroMemory(phi->pphmAlias, ALIAS_SLOTS*sizeof(PHMAP));
+ phi->nAliasEntries = ALIAS_SLOTS;
+ }
+
+ // If the current hint is in use, then look for the next free one
+
+ if (phi->pphmAlias[phi->iAliasHint] &&
+ !((INT)phi->pphmAlias[phi->iAliasHint]&1)) {
+
+ INT i;
+ LOGDEBUG(13,(" FindHMap32: alias hint failed, scanning...\n"));
+ for (i=phi->iAliasHint+1; i<phi->nAliasEntries; i++) {
+ if (!phi->pphmAlias[i] || ((INT)phi->pphmAlias[i]&1))
+ goto Break;
+ }
+ for (i=0; i<phi->iAliasHint; i++) {
+ if (!phi->pphmAlias[i] || ((INT)phi->pphmAlias[i]&1))
+ goto Break;
+ }
+ Break:
+ phi->iAliasHint = i;
+
+ // If we've exhausted all the slots in the existing table, grow it
+
+ if (phi->pphmAlias[i] && !((INT)phi->pphmAlias[i]&1)) {
+ PPHMAP p;
+
+ if (phi->nAliasEntries >= (1<<(16-RES_BITS))) {
+ LOGDEBUG(0,(" FindHMap32 ERROR: at 16-bit handle limit\n"));
+ return NULL;
+ }
+ LOGDEBUG(1,(" FindHMap32: growing handle alias array\n"));
+ if (!(p = realloc(phi->pphmAlias, (phi->nAliasEntries+ALIAS_SLOTS)*sizeof(PHMAP)))) {
+ LOGDEBUG(0,(" FindHMap32 ERROR: cannot grow alias table\n"));
+ return NULL;
+ }
+ phi->pphmAlias = p;
+ RtlZeroMemory(phi->pphmAlias+phi->nAliasEntries, ALIAS_SLOTS*sizeof(PHMAP));
+ phi->iAliasHint = phi->nAliasEntries;
+ phi->nAliasEntries += ALIAS_SLOTS;
+ }
+ }
+#endif
+ phm = malloc_w(sizeof(HMAP));
+ if (!phm) {
+ LOGDEBUG(0,(" FindHMap32 ERROR: cannot allocate new list entry\n"));
+ return NULL;
+ }
+ phm->h32 = NULL;
+
+#ifdef NEWALIAS
+ // Record the new list entry in the alias table
+
+ phm->h16 = (HAND16)(++phi->iAliasHint << RES_BITS);
+ if (phi->iAliasHint >= phi->nAliasEntries)
+ phi->iAliasHint = 0;
+
+ // New entries can simply be inserted at the head of the list,
+ // because their position in the list has no relationship to the aliases
+
+ phm->phmNext = phi->pphmHash[iHash];
+ phi->pphmHash[iHash] = phm;
+#else
+#ifdef DEBUG
+ nAliases++;
+ if (iList > iLargestListSlot) {
+ iLargestListSlot = iList;
+ LOGDEBUG(1,(" FindHMap32: largest list slot is now %d\n", iLargestListSlot));
+ }
+#endif
+ phm->h16 = (HAND16)((iHash | (iList << HASH_BITS)) << RES_BITS);
+
+ // New entries must be appended rather than inserted, because
+ // our phoney 16-bit handles are dependent on position in the list
+
+ phm->phmNext = NULL;
+ phmPrev->phmNext = phm;
+#endif
+ }
+
+ // If this a new entry, initialize it
+
+ if (!phm->h32) {
+#ifdef DEBUG
+ if (!fSkipLog) {
+ LOGDEBUG(7,(" Adding %s alias %04x for %08lx\n",
+ GetHMapNameM(phi, iClass), phm->h16, h32));
+ }
+#endif
+
+ // Insure that the alias pointer is valid
+#ifdef NEWALIAS
+ phi->pphmAlias[(phm->h16>>RES_BITS)-1] = phm;
+#endif
+ phm->h32 = h32;
+ phm->htask16 = FETCHWORD(CURRENTPTD()->htask16);
+ phm->iClass = iClass;
+ phm->dwStyle = 0;
+ phm->vpfnWndProc = 0;
+ phm->pwcd = 0;
+ }
+
+ return phm;
+}
+
+
+PHMAP FindHMap16(HAND16 h16, PHINFO phi)
+{
+#ifndef NEWALIAS
+ INT i, iHash, iList;
+#endif
+ register PHMAP phm;
+#ifdef HACK32
+ static HMAP hmDummy = {NULL, NULL, 0, 0, 0, 0, NULL, 0};
+#endif
+
+ if (!h16 || h16 == 0xFFFF)
+ return NULL;
+
+#ifdef HACK32
+ if (h16 == TRUE)
+ return &hmDummy;
+#endif
+
+ // Verify all the RES_BITS are clear
+ if (h16 & ((1 << RES_BITS)-1)) {
+ WOW32ASSERT(FALSE);
+ return NULL;
+ }
+
+ h16 >>= RES_BITS;
+
+#ifdef NEWALIAS
+ // Verify the handle is within range
+ WOW32ASSERT((INT)h16 <= phi->nAliasEntries);
+
+ // This can happen if we haven't allocated any aliases yet
+ if (!phi->pphmAlias)
+ return NULL;
+
+ phm = phi->pphmAlias[h16-1];
+ if ((INT)phm & 1) {
+ (INT)phm &= ~1;
+ LOGDEBUG(0,(" FindHMap16 WARNING: defunct alias %04x reused\n", h16<<RES_BITS));
+ }
+#else
+ iHash = h16 & HASH_MASK;
+ iList = (h16 & LIST_MASK) >> HASH_BITS;
+
+ phm = (PHMAP)(phi->pphmHash + iHash);
+
+ i = iList;
+ while (i-- && phm) {
+ phm = phm->phmNext;
+ }
+#endif
+ if (!phm) {
+ LOGDEBUG(0,(" FindHMap16 ERROR: could not find %04x\n", h16<<RES_BITS));
+ return NULL;
+ }
+ // Verify requested handle is same as stored in alias
+ if (h16 != (HAND16)(phm->h16>>RES_BITS)) {
+ LOGDEBUG(0, ("FindHMap16: Got bad H16\n"));
+ WOW32ASSERT(FALSE);
+ return NULL;
+ }
+
+#ifdef DEBUG
+ if (!fSkipLog) {
+ LOGDEBUG(9,(" Found %s %08lx for alias %04x\n",
+ GetHMapNameM(phi, phm->iClass), phm->h32, h16<<RES_BITS));
+ }
+#endif
+
+ return phm;
+}
+
+
+VOID FreeHMap16(HAND16 h16, PHINFO phi)
+{
+ register PHMAP phm;
+
+ if (phm = FindHMap16(h16, phi)) {
+ LOGDEBUG(7,(" Freeing %s alias %04x for %08lx\n",
+ GetHMapNameM(phi, phm->iClass), phm->h16, phm->h32));
+
+// if (phm->iClass == WOWCLASS_WIN16)
+// phm->pwcd->nWindows--;
+
+ // BUGBUG -- We'll eventually want some garbage collection... -JTP
+
+
+ phm->h32 = NULL;
+
+#ifdef NEWALIAS
+ // We don't want to totally zap the alias' hmap pointer yet, because
+ // if we're dealing with an app that is using cached handles after
+ // it has technically freed them, we want to try to reassociate their
+ // handle with a new 32-bit handle. So we'll just set the low bit
+ // of the alias hmap pointer and leave the hint index alone; we will
+ // still try to reuse entries with the low bit set however.
+ //
+ // phi->iAliasHint = (h16>>RES_BITS)-1;
+ // phi->pphmAlias[phi->iAliasHint] = NULL;
+
+ (INT)phi->pphmAlias[(h16>>RES_BITS)-1] |= 1;
+#endif
+ return;
+ }
+ LOGDEBUG(1,(" FreeHMap16: handle alias %04x not found\n"));
+}
+
+
+PSZ GetHMapNameM(PHINFO phi, INT iClass)
+{
+ return "MMEDIA";
+}
diff --git a/private/mvdm/wow32/wmmalias.h b/private/mvdm/wow32/wmmalias.h
new file mode 100644
index 000000000..174c0ebe7
--- /dev/null
+++ b/private/mvdm/wow32/wmmalias.h
@@ -0,0 +1,95 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMMALIAS.H
+ * WOW32 16-bit handle alias support
+ *
+ * History:
+ * Created Sept-1-1992 by Chandan Chauhan (ChandanC)
+ * Modified 12-May-1992 by Mike Tricker (miketri) to add MultiMedia support
+--*/
+
+
+
+/* 16-bit handle format
+ *
+ * Bits 0 and 1 are always zero (potential compatibility requirement).
+ * Note however that the macros below treat HASH_BITS as starting at bit
+ * 0, for simplicity. We just shift the alias left two bits when we're
+ * done. The actual number of low bits that are reserved is determined
+ * by RES_BITS.
+ *
+ * Of the remaining 14 bits, the next HASH_BITS bits are the hash slot #
+ * (relative to 0), followed by LIST_BITS bits containing the list slot #
+ * (relative to 1). List slot is relative to 1 because some portion of
+ * a valid handle must be non-zero; this is also why LIST_SLOTS contains
+ * that extra "-1".
+ */
+#define RES_BITS 2
+
+#define HASH_BITS 6
+#define HASH_SLOTS (1 << HASH_BITS)
+#define HASH_MASK (HASH_SLOTS-1)
+#define MASK32(h32) ((INT)(h32))
+#define HASH32(h32) (MASK32(h32) & (HASH_SLOTS-1))
+
+#define LIST_BITS (16-RES_BITS-HASH_BITS)
+#define LIST_SLOTS ((1 << LIST_BITS) - 1)
+#define LIST_MASK (LIST_SLOTS << HASH_BITS)
+
+#define ALIAS_SLOTS 128 // must be a power of 2
+
+
+/* Class map entry
+ */
+#pragma pack(2)
+typedef struct _WCDM { /* wcd */
+ struct _WCD *pwcdNext; // pointer to next wcd entry
+ PSZ pszClass; // pointer to local copy of class name
+ VPSZ vpszMenu; // pointer to original copy of menu name, if any
+ HAND16 hModule16; // handle of owning module
+ HAND16 hInst16; // 16-bit hInstance (wndclass16.hInstance)
+ WORD nWindows; // # of windows in existence based on class
+ VPWNDPROC vpfnWndProc; // 16-bit window proc address
+ WORD wStyle; // Class Style bits
+} WCD, *PWCD, **PPWCD;
+#pragma pack()
+
+
+
+/* Handle map entry
+ */
+#pragma pack(2)
+typedef struct _HMAP { /* hm */
+ struct _HMAP *phmNext; // pointer to next hmap entry
+ HANDLE h32; // 32-bit handle
+ HAND16 h16; // 16-bit handle
+ HTASK16 htask16; // 16-bit handle of owning task
+ INT iClass; // WOW class index
+ DWORD dwStyle; // style flags (if handle to window)
+ PWCD pwcd; // WOW class data pointer
+ VPWNDPROC vpfnWndProc; // associated 16-bit function address
+ VPWNDPROC vpfnDlgProc; // 16-bit dialog function
+} HMAP, *PHMAP, **PPHMAP;
+#pragma pack()
+
+
+/* Handle alias info
+ */
+typedef struct _HINFO { /* hi */
+ PPHMAP pphmHash; // address of hash table
+#ifdef NEWALIAS
+ PPHMAP pphmAlias; // address of alias table
+ INT nAliasEntries; // size of alias table, in entries
+ INT iAliasHint; // next (possibly) free slot in alias table
+#endif
+} HINFO, *PHINFO, **PPHINFO;
+
+
+PHMAP FindHMap32(HAND32 h32, PHINFO phi, INT iClass);
+PHMAP FindHMap16(HAND16 h16, PHINFO phi);
+VOID FreeHMap16(HAND16 h16, PHINFO phi);
+PSZ GetHMapNameM(PHINFO phi, INT iClass);
diff --git a/private/mvdm/wow32/wmmedia.c b/private/mvdm/wow32/wmmedia.c
new file mode 100644
index 000000000..82c8fb20b
--- /dev/null
+++ b/private/mvdm/wow32/wmmedia.c
@@ -0,0 +1,357 @@
+/*---------------------------------------------------------------------*\
+*
+* WOW v1.0
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* WMMEDIA.C
+* WOW32 16-bit MultiMedia API support
+*
+* Contains:
+* General support apis
+* Timer support apis
+* MCI apis
+*
+* History:
+* Created 21-Jan-1992 by Mike Tricker (MikeTri), after jeffpar
+* Changed 15-Jul-1992 by Mike Tricker (MikeTri), fixing GetDevCaps calls
+* 26-Jul-1992 by Stephen Estrop (StephenE) thunks for mciSendCommand
+* 30-Jul-1992 by Mike Tricker (MikeTri), fixing Wave/Midi/MMIO
+* 03-Aug-1992 by Mike Tricker (MikeTri), added proper error handling
+* 08-Oct-1992 by StephenE used correct thunk macro for UINT's
+* also split file into 3 because it was getting to big.
+*
+\*---------------------------------------------------------------------*/
+
+//
+// We define NO_STRICT so that the compiler doesn't moan and groan when
+// I use the FARPROC type for the Multi-Media api loading.
+//
+#define NO_STRICT
+#define OEMRESOURCE
+
+#include "precomp.h"
+#pragma hdrstop
+#include <stdlib.h>
+
+
+
+
+
+
+
+MODNAME(wmmedia.c);
+
+PCALLBACK_DATA pCallBackData; // A 32 bit ptr to the 16 bit callback data
+CRITICAL_SECTION mmCriticalSection;
+CRITICAL_SECTION mmHandleCriticalSection;
+
+//
+// All this stuff is required for the dynamic linking of Multi-Media to WOW32
+//
+HANDLE hWinmm = NULL;
+FARPROC mmAPIEatCmdEntry = NULL;
+FARPROC mmAPIGetParamSize = NULL;
+FARPROC mmAPIUnlockCmdTable = NULL;
+FARPROC mmAPISendCmdW = NULL;
+FARPROC mmAPIFindCmdItem = NULL;
+FARPROC mmAPIGetYieldProc = NULL;
+
+VOID FASTCALL Set_MultiMedia_16bit_Directory( PVDMFRAME pFrame );
+
+
+/*++
+
+ GENERIC FUNCTION PROTOTYPE:
+ ==========================
+
+ULONG FASTCALL WMM32<function name>(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register P<function name>16 parg16;
+
+ GETARGPTR(pFrame, sizeof(<function name>16), parg16);
+
+ <get any other required pointers into 16 bit space>
+
+ ALLOCVDMPTR
+ GETVDMPTR
+ GETMISCPTR
+ et cetera
+
+ <copy any complex structures from 16 bit -> 32 bit space>
+ <ALWAYS use the FETCHxxx macros>
+
+ ul = GET<return type>16(<function name>(parg16->f1,
+ :
+ :
+ parg16->f<n>);
+
+ <copy any complex structures from 32 -> 16 bit space>
+ <ALWAYS use the STORExxx macros>
+
+ <free any pointers to 16 bit space you previously got>
+
+ <flush any areas of 16 bit memory if they were written to>
+
+ FLUSHVDMPTR
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+NOTE:
+
+ The VDM frame is automatically set up, with all the function parameters
+ available via parg16->f<number>.
+
+ Handles must ALWAYS be mapped for 16 -> 32 -> 16 space via the mapping tables
+ laid out in WALIAS.C.
+
+ Any storage you allocate must be freed (eventually...).
+
+ Further to that - if a thunk which allocates memory fails in the 32 bit call
+ then it must free that memory.
+
+ Also, never update structures in 16 bit land if the 32 bit call fails.
+
+--*/
+
+
+/* ---------------------------------------------------------------------
+** General Support API's
+** ---------------------------------------------------------------------
+*/
+
+/*****************************Private*Routine******************************\
+* WMM32CallProc32
+*
+*
+*
+* History:
+* dd-mm-94 - StephenE - Created
+*
+\**************************************************************************/
+ULONG FASTCALL
+WMM32CallProc32(
+ PVDMFRAME pFrame
+ )
+{
+ register DWORD dwReturn;
+ PMMCALLPROC3216 parg16;
+
+
+ GETARGPTR(pFrame, sizeof(PMMCALLPROC32), parg16);
+
+
+ // Don't call to Zero
+
+ if (parg16->lpProcAddress == 0) {
+ LOGDEBUG(LOG_ALWAYS,("MMCallProc32 - Error calling to 0 not allowed"));
+ return(0);
+ }
+
+ //
+ // Make sure we have the correct 16 bit directory set.
+ //
+ if (parg16->fSetCurrentDirectory != 0) {
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+ }
+
+
+ dwReturn = ((FARPROC)parg16->lpProcAddress)( parg16->p5, parg16->p4,
+ parg16->p3, parg16->p2,
+ parg16->p1);
+
+
+ FREEARGPTR(parg16);
+ return dwReturn;
+}
+
+
+/******************************Public*Routine******************************\
+* WOW32ResolveMemory
+*
+* Enable multi-media (and others) to reliably map memory from 16 bit land
+* to 32 bit land.
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+LPVOID APIENTRY
+WOW32ResolveMemory(
+ VPVOID vp
+ )
+{
+ LPVOID lpReturn;
+
+ GETMISCPTR( vp, lpReturn );
+ return lpReturn;
+}
+
+
+/**********************************************************************\
+* WOW32ResolveHandle
+*
+* This is a general purpose handle mapping function. It allows WOW thunk
+* extensions to get access to 32 bit handles given a 16 bit handle.
+*
+\**********************************************************************/
+BOOL APIENTRY WOW32ResolveHandle( UINT uHandleType, UINT uMappingDirection,
+ WORD wHandle16_In, LPWORD lpwHandle16_Out,
+ DWORD dwHandle32_In, LPDWORD lpdwHandle32_Out )
+{
+ BOOL fReturn = FALSE;
+ DWORD dwHandle32;
+ WORD wHandle16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "WOW32ResolveMultiMediaHandle", mmAPI,
+ MMSYSERR_NODRIVER );
+
+ if ( uMappingDirection == WOW32_DIR_16IN_32OUT ) {
+
+ switch ( uHandleType ) {
+
+ case WOW32_USER_HANDLE:
+ dwHandle32 = (DWORD)USER32( wHandle16_In );
+ break;
+
+
+ case WOW32_GDI_HANDLE:
+ dwHandle32 = (DWORD)GDI32( wHandle16_In );
+ break;
+
+
+ case WOW32_WAVEIN_HANDLE:
+ case WOW32_WAVEOUT_HANDLE:
+ case WOW32_MIDIOUT_HANDLE:
+ case WOW32_MIDIIN_HANDLE:
+ (*mmAPI)( uHandleType, uMappingDirection, wHandle16_In,
+ lpwHandle16_Out, dwHandle32_In, lpdwHandle32_Out );
+ break;
+ }
+
+ /*
+ ** Protect ourself from being given a duff pointer.
+ */
+ try {
+
+ if ( *lpdwHandle32_Out = dwHandle32 ) {
+ fReturn = TRUE;
+ }
+ else {
+ fReturn = FALSE;
+ }
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ fReturn = FALSE;
+ }
+ }
+ else if ( uMappingDirection == WOW32_DIR_32IN_16OUT ) {
+
+ switch ( uHandleType ) {
+
+ case WOW32_USER_HANDLE:
+ wHandle16 = (WORD)USER16( dwHandle32_In );
+ break;
+
+
+ case WOW32_GDI_HANDLE:
+ wHandle16 = (WORD)GDI16( dwHandle32_In );
+ break;
+
+
+ case WOW32_WAVEIN_HANDLE:
+ case WOW32_WAVEOUT_HANDLE:
+ case WOW32_MIDIOUT_HANDLE:
+ case WOW32_MIDIIN_HANDLE:
+ (*mmAPI)( uHandleType, uMappingDirection, wHandle16_In,
+ lpwHandle16_Out, dwHandle32_In, lpdwHandle32_Out );
+ break;
+ }
+
+ /*
+ ** Protect ourself from being given a duff pointer.
+ */
+ try {
+ if ( *lpwHandle16_Out = wHandle16 ) {
+ fReturn = TRUE;
+ }
+ else {
+ fReturn = FALSE;
+ }
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ fReturn = FALSE;
+ }
+ }
+ return fReturn;
+}
+
+
+/**********************************************************************\
+*
+* WOW32DriverCallback
+*
+* Callback stub, which invokes the "real" 16 bit callback.
+* The parameters to this function must be in the format that the 16 bit
+* code expects, i.e. all handles must be 16 bit handles, all addresses must
+* be 16:16 ones.
+*
+*
+* It is possible that this function will have been called with the
+* DCB_WINDOW set in which case the 16 bit interrupt handler will call
+* PostMessage. Howver, it is much more efficient if PostMessage is called
+* from the 32 bit side.
+*
+\**********************************************************************/
+BOOL APIENTRY WOW32DriverCallback( DWORD dwCallback, DWORD dwFlags,
+ WORD wID, WORD wMsg,
+ DWORD dwUser, DWORD dw1, DWORD dw2 )
+{
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "WOW32DriverCallback", mmAPI, MMSYSERR_NODRIVER );
+
+ /*
+ ** Just pass the call onto winmm
+ */
+ return (*mmAPI)( dwCallback, dwFlags, wID, wMsg, dwUser, dw1, dw2 );
+}
+
+
+/**********************************************************************\
+*
+* Get_MultiMedia_ProcAddress
+*
+* This function gets the address of the given Multi-Media api. It loads
+* Winmm.dll if this it has not already been loaded.
+*
+\**********************************************************************/
+FARPROC Get_MultiMedia_ProcAddress( LPSTR lpstrProcName )
+{
+ /*
+ ** Either this is the first time this function has been called
+ ** or the Multi-Media sub-system is in a bad way.
+ */
+ if ( hWinmm == NULL ) {
+
+ // dprintf2(( "Attempting to load WINMM.DLL" ));
+ hWinmm = SafeLoadLibrary( "WINMM.DLL" );
+
+ if ( hWinmm == NULL ) {
+
+ /* Looks like the Multi-Media sub-system is in a bad way */
+ // dprintf2(( "FAILED TO LOAD WINMM.DLL!!" ));
+ return NULL;
+ }
+
+ }
+
+ return GetProcAddress( hWinmm, lpstrProcName );
+
+}
diff --git a/private/mvdm/wow32/wmmedia.h b/private/mvdm/wow32/wmmedia.h
new file mode 100644
index 000000000..2eae61f37
--- /dev/null
+++ b/private/mvdm/wow32/wmmedia.h
@@ -0,0 +1,311 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMMEDIA.H
+ * WOW32 16-bit MultiMedia API support
+ *
+ * History:
+ * Created 21-Jan-1992 by Mike Tricker (MikeTri), after jeffpar
+ * Changed 30-Apr-1992 by Mike Tricker (MikeTri) Added callback prototypes and structs
+ * 30-Jul-1992 by Stephen Estrop (StephenE) Added MCCICommand Thunk stuff
+--*/
+
+
+#define MMGETOPTPTR(vp,cb,p) {p=NULL; if (HIWORD(FETCHDWORD(vp))) GETVDMPTR(vp,cb,p);}
+
+
+/*++
+ Enumeration handler data for the six callback types:
+--*/
+
+typedef struct _TIMEDATA { /* timedata */
+ VPPROC vpfnTimeFunc; // 16 bit enumeration function
+ DWORD dwUserParam; // user param, if required
+ DWORD dwFlags; // flags, ieTIME_ONESHOT or TIME_PERIODIC
+} TIMEDATA, *PTIMEDATA;
+
+/*
+ * A couple of handy structures that probably ought to be elsewhere.
+ */
+
+typedef struct _INSTANCEDATA {
+ DWORD dwCallback; //Callback function or window handle
+ DWORD dwCallbackInstance; //Instance data for callback function (only)
+ DWORD dwFlags; //Flags
+} INSTANCEDATA, *PINSTANCEDATA;
+
+typedef struct _WAVEHDR32 {
+ PWAVEHDR16 pWavehdr32; //32 bit address to 16 bit WAVEHDR
+ PWAVEHDR16 pWavehdr16; //16 bit address to 16 bit WAVEHDR
+ WAVEHDR Wavehdr; //32 bit address to 32 bit WAVEHDR
+} WAVEHDR32, *PWAVEHDR32;
+
+typedef struct _MIDIHDR32 {
+ PMIDIHDR16 pMidihdr32; //32 bit address to 16 bit MIDIHDR
+ PMIDIHDR16 pMidihdr16; //16 bit address to 16 bit MIDIHDR
+ MIDIHDR Midihdr; //32 bit address to 32 bit MIDIHDR
+} MIDIHDR32, *PMIDIHDR32;
+
+/*++
+ Function Prototypes:
+--*/
+
+ULONG FASTCALL WMM32CallProc32( PVDMFRAME pFrame );
+ULONG FASTCALL WMM32sndPlaySound(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32mmsystemGetVersion(PVDMFRAME pFrame);
+
+ULONG FASTCALL WMM32OutputDebugStr(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32DriverCallback(PVDMFRAME pFrame);
+
+ULONG FASTCALL WMM32joyGetNumDevs(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32joyGetDevCaps(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32joyGetPos(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32joyGetThreshold(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32joyReleaseCapture(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32joySetCapture(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32joySetThreshold(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32joySetCalibration(PVDMFRAME pFrame);
+
+ULONG FASTCALL WMM32midiOutGetNumDevs(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutGetDevCaps(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutGetErrorText(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutOpen(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutClose(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutPrepareHeader(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutUnprepareHeader(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutShortMsg(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutLongMsg(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutReset(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutGetVolume(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutSetVolume(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutCachePatches(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutCacheDrumPatches(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutGetID(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiOutMessage(PVDMFRAME pFrame);
+
+ULONG FASTCALL WMM32midiInGetNumDevs(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInGetDevCaps(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInGetErrorText(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInOpen(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInClose(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInPrepareHeader(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInUnprepareHeader(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInAddBuffer(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInStart(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInStop(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInReset(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInGetID(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32midiInMessage(PVDMFRAME pFrame);
+
+ULONG FASTCALL WMM32auxGetNumDevs(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32auxGetDevCaps(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32auxGetVolume(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32auxSetVolume(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32auxOutMessage(PVDMFRAME pFrame);
+
+ULONG FASTCALL WMM32waveOutGetNumDevs(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutGetDevCaps(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutGetErrorText(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutOpen(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutClose(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutPrepareHeader(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutUnprepareHeader(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutWrite(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutPause(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutRestart(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutReset(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutGetPosition(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutGetPitch(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutSetPitch(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutGetVolume(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutSetVolume(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutGetPlaybackRate(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutSetPlaybackRate(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutBreakLoop(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutGetID(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveOutMessage(PVDMFRAME pFrame);
+
+ULONG FASTCALL WMM32waveInGetNumDevs(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInGetDevCaps(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInGetErrorText(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInOpen(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInClose(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInPrepareHeader(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInUnprepareHeader(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInAddBuffer(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInStart(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInStop(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInReset(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInGetPosition(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInGetID(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32waveInMessage(PVDMFRAME pFrame);
+
+ULONG FASTCALL WMM32timeGetSystemTime(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32timeGetTime(PVDMFRAME pFrame);
+
+VOID W32TimeFunc(UINT wID, UINT wMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
+
+ULONG FASTCALL WMM32timeSetEvent(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32timeKillEvent(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32timeGetDevCaps(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32timeBeginPeriod(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32timeEndPeriod(PVDMFRAME pFrame);
+
+ULONG FASTCALL WMM32mciSendCommand(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32mciSendString(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32mciGetDeviceID(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32mciGetErrorString(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32mciExecute(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32mciGetDeviceIDFromElementID(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32mciGetCreatorTask(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32mciSetYieldProc(PVDMFRAME pFrame);
+ULONG FASTCALL WMM32mciGetYieldProc(PVDMFRAME pFrame);
+
+BOOL APIENTRY WOW32DriverCallback(
+ DWORD dwCallback, DWORD dwFlags, WORD wID, WORD wMsg,
+ DWORD dwUser, DWORD dw1, DWORD dw2 );
+
+UINT WMM32mciYieldProc( MCIDEVICEID wDeviceID, DWORD dwYieldData );
+
+VOID W32CommonDeviceOpen( HANDLE handle, UINT uMsg, DWORD dwInstance,
+ DWORD dwParam1, DWORD dwParam2);
+
+ULONG FASTCALL WMM32NotifyCallbackData(PVDMFRAME pFrame);
+
+FARPROC Get_MultiMedia_ProcAddress( LPSTR lpstrProcName );
+
+#define GET_MULTIMEDIA_API( name, proc, error ) \
+ if ( (proc) == NULL ) { \
+ (proc) = Get_MultiMedia_ProcAddress( (name) ); \
+ if ( (proc) == NULL ) { \
+ RETURN( (error) ); \
+ } \
+ }
+
+#define MIN_WOW_TIME_PERIOD 0x10
+
+
+
+/* -----------------------------------------------------------------------
+ *
+ * MCI Command Thunks
+ *
+ * ----------------------------------------------------------------------- */
+
+/**************************************************************************\
+*
+* MCI Command Thunks function prototypes.
+*
+\**************************************************************************/
+INT ThunkMciCommand16( MCIDEVICEID OrigDevice, UINT OrigCommand, DWORD OrigFlags,
+ DWORD OrigParms, PDWORD pNewParms, LPWSTR *lplpCommand,
+ PUINT puTable );
+INT UnThunkMciCommand16( MCIDEVICEID devID, UINT OrigCommand, DWORD OrigFlags,
+ DWORD OrigParms, DWORD NewParms, LPWSTR lpCommand,
+ UINT uTable );
+DWORD AllocMciParmBlock( PDWORD pOrigFlags, DWORD OrigParms );
+UINT GetSizeOfParameter( LPWSTR lpCommand );
+
+/*************************************************************************\
+* Thunk Command Parms IN
+\*************************************************************************/
+INT ThunkCommandViaTable( LPWSTR lpCommand, DWORD OrigFlags, DWORD OrigParms,
+ DWORD pNewParms );
+DWORD ThunkBreakCmd ( PDWORD pOrigFlags, DWORD OrigParms, DWORD pNewParms );
+DWORD ThunkSysInfoCmd( PDWORD pOrigFlags, DWORD OrigParms, DWORD pNewParms );
+DWORD ThunkOpenCmd ( PDWORD pOrigFlags, DWORD OrigParms, DWORD pNewParms );
+DWORD ThunkSetCmd ( MCIDEVICEID DeviceID, PDWORD pOrigFlags,
+ DWORD OrigParms, DWORD pNewParms );
+DWORD ThunkWindowCmd ( MCIDEVICEID DeviceID, PDWORD pOrigFlags,
+ DWORD OrigParms, DWORD pNewParms );
+DWORD ThunkSetVideoCmd( MCIDEVICEID DeviceID, PDWORD pOrigFlags,
+ DWORD OrigParms, DWORD pNewParms );
+
+/*************************************************************************\
+* Thunk Command Parms OUT
+\*************************************************************************/
+INT UnThunkCommandViaTable( LPWSTR lpCommand, DWORD OrigFlags, DWORD OrigParms,
+ DWORD pNewParms, BOOL fReturnValNotThunked );
+VOID UnThunkSysInfoCmd( DWORD OrigFlags, DWORD OrigParms, DWORD NewParms );
+VOID UnThunkOpenCmd( DWORD OrigFlags, DWORD OrigParms, DWORD NewParms );
+VOID UnThunkStatusCmd( MCIDEVICEID devID, DWORD OrigFlags,
+ DWORD OrigParms, DWORD NewParms );
+
+
+#if DBG
+/* -----------------------------------------------------------------------
+ *
+ * MCI Command Thunks Debugging Functions and Macros
+ *
+ * ----------------------------------------------------------------------- */
+typedef struct {
+ UINT uMsg;
+ LPSTR lpstMsgName;
+} MCI_MESSAGE_NAMES;
+
+extern int mmDebugLevel;
+extern int mmTraceWave;
+extern int mmTraceMidi;
+extern MCI_MESSAGE_NAMES mciMessageNames[32];
+
+extern VOID wow32MciSetDebugLevel( VOID );
+extern VOID wow32MciDebugOutput( LPSTR lpstrFormatStr, ... );
+
+#define dprintf( _x_ ) wow32MciDebugOutput _x_
+#define dprintf1( _x_ ) if (mmDebugLevel >= 1) {wow32MciDebugOutput _x_ ;} else
+#define dprintf2( _x_ ) if (mmDebugLevel >= 2) {wow32MciDebugOutput _x_ ;} else
+#define dprintf3( _x_ ) if (mmDebugLevel >= 3) {wow32MciDebugOutput _x_ ;} else
+#define dprintf4( _x_ ) if (mmDebugLevel >= 4) {wow32MciDebugOutput _x_ ;} else
+#define dprintf5( _x_ ) if (mmDebugLevel >= 5) {wow32MciDebugOutput _x_ ;} else
+
+#define trace_wave( _x_ ) if (mmTraceWave) {wow32MciDebugOutput _x_ ;} else
+#define trace_midi( _x_ ) if (mmTraceMidi) {wow32MciDebugOutput _x_ ;} else
+#define trace_aux( _x_ ) if (mmTraceAux) {wow32MciDebugOutput _x_ ;} else
+#define trace_joy( _x_ ) if (mmTraceJoy) {wow32MciDebugOutput _x_ ;} else
+
+
+#else
+
+#define dprintf( _x_ )
+#define dprintf1( _x_ )
+#define dprintf2( _x_ )
+#define dprintf3( _x_ )
+#define dprintf4( _x_ )
+#define dprintf5( _x_ )
+
+#define trace_wave( _x_ )
+#define trace_midi( _x_ )
+#define trace_aux( _x_ )
+#define trace_joy( _x_ )
+
+
+#endif
+
+/* Stuff needed for MCI thunking. Defined in MEDIA\WINMM\MCI.H but here
+ * until a common place can be found
+ */
+
+extern BOOL WINAPI mciExecute (LPCSTR lpstrCommand);
+
+extern LPWSTR FindCommandItem (MCIDEVICEID wDeviceID, LPCWSTR lpstrType,
+ LPCWSTR lpstrCommand, PUINT lpwMessage,
+ PUINT lpwTable);
+
+extern UINT mciEatCommandEntry(LPCWSTR lpEntry, LPDWORD lpValue, PUINT lpID);
+
+extern UINT mciGetParamSize (DWORD dwValue, UINT wID);
+
+extern BOOL mciUnlockCommandTable (UINT wCommandTable);
+
+#define MCI_MAX_PARAM_SLOTS 20
+
+//
+// This typedef is used to remove a compiler warning caused by implementing
+// the dynamic linking of Multi-Media from WOW.
+//
+typedef LPWSTR (*FINDCMDITEM)(MCIDEVICEID wDeviceID, LPCWSTR lpstrType,
+ LPCWSTR lpstrCommand, PUINT lpwMessage,
+ PUINT lpwTable);
diff --git a/private/mvdm/wow32/wmmedia1.c b/private/mvdm/wow32/wmmedia1.c
new file mode 100644
index 000000000..8fd35c7aa
--- /dev/null
+++ b/private/mvdm/wow32/wmmedia1.c
@@ -0,0 +1,555 @@
+/*---------------------------------------------------------------------*\
+*
+* WOW v1.0
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* WMMEDIA3.C
+* WOW32 16-bit MultiMedia API support
+*
+* Contains:
+* Aux sound support apis
+* Joystick support apis
+*
+*
+* History:
+* Created 21-Jan-1992 by Mike Tricker (MikeTri), after jeffpar
+* Changed 15-Jul-1992 by Mike Tricker (MikeTri), fixing GetDevCaps calls
+* 26-Jul-1992 by Stephen Estrop (StephenE) thunks for mciSendCommand
+* 30-Jul-1992 by Mike Tricker (MikeTri), fixing Wave/Midi/MMIO
+* 03-Aug-1992 by Mike Tricker (MikeTri), added proper error handling
+* 08-Oct-1992 by StephenE spawn from the original wmmedia.c
+*
+\*---------------------------------------------------------------------*/
+
+
+
+//
+// We define NO_STRICT so that the compiler doesn't moan and groan when
+// I use the FARPROC type for the Multi-Media api loading.
+//
+#define NO_STRICT
+#define OEMRESOURCE
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if 0
+
+MODNAME(wmmedia1.c);
+
+#if DBG
+int mmTraceAux = 0;
+int mmTraceJoy = 0;
+#endif
+
+/* ---------------------------------------------------------------------
+** Auxiliary Sound APIs
+** ---------------------------------------------------------------------
+*/
+
+/**********************************************************************\
+*
+* WMM32auxGetNumDevs
+*
+* This function retrieves the number of auxiliary output devices present in the
+* system.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32auxGetNumDevs(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "auxGetNumDevs", mmAPI, MMSYSERR_NODRIVER );
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ trace_aux(( "auxGetNumDevs()" ));
+ ul = GETWORD16( (*mmAPI)() );
+ trace_aux(( "-> %ld\n", ul ));
+
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32auxGetDevCaps
+*
+* This function queries a specified auxiliary output device to determine its
+* capabilities.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32auxGetDevCaps(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ AUXCAPS auxcaps;
+ register PAUXGETDEVCAPS16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "auxGetDevCapsA", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(AUXGETDEVCAPS16), parg16);
+
+ trace_aux(( "auxGetDevCaps( %x, %x, %x )", INT32(parg16->f1),
+ DWORD32(parg16->f2), UINT32(parg16->f3) ));
+
+ /*
+ ** If the size parameter was zero return straight away. Note that this
+ ** is not an error.
+ */
+ if ( UINT32( parg16->f3 ) == 0 ) {
+ ul = MMSYSERR_NOERROR;
+ }
+ else {
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), &auxcaps,
+ sizeof(AUXCAPS) ));
+ /*
+ ** Don't update the 16 bit structure if the call falied
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+ ul = PUTAUXCAPS16( parg16->f2, &auxcaps, UINT32(parg16->f3) );
+ }
+ }
+ trace_aux(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32auxGetVolume
+*
+* This function returns the current volume setting of an auxiliary output
+* device.
+*
+* Does this actually return the value in f2 ? It should...
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32auxGetVolume(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPDWORD lpdwVolume;
+ register PAUXGETVOLUME16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "auxGetVolume", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(AUXGETVOLUME16), parg16);
+ GETMISCPTR(parg16->f2, lpdwVolume);
+
+ trace_aux(( "auxGetVolume( %x, %x )", INT32(parg16->f1),
+ DWORD32(parg16->f2) ));
+
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), lpdwVolume ));
+ trace_aux(( "-> %ld\n", ul ));
+
+ FREEMISCPTR(lpdwVolume);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32auxSetVolume
+*
+* This function sets the volume of an auxiliary output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32auxSetVolume(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PAUXSETVOLUME16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "auxSetVolume", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(AUXSETVOLUME16), parg16);
+
+ trace_aux(( "auxSetVolume( %x, %x )", INT32(parg16->f1),
+ DWORD32(parg16->f2) ));
+
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), DWORD32(parg16->f2) ));
+ trace_aux(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32auxOutMessage
+*
+* This function sends a message to an auxiliary output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32auxOutMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PAUXOUTMESSAGE3216 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "auxOutMessage", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(AUXOUTMESSAGE16), parg16);
+
+ trace_aux(( "auxOutMessage( %x, %x, %x, %x )", WORD32(parg16->f1),
+ UINT32(parg16->f2), DWORD32(parg16->f3), DWORD32(parg16->f4) ));
+
+ if ( (UINT32(parg16->f2) >= DRV_BUFFER_LOW)
+ && (UINT32(parg16->f2) <= DRV_BUFFER_HIGH) ) {
+
+ LPDWORD lpdwParam1;
+ GETMISCPTR(parg16->f3, lpdwParam1);
+
+ ul = GETDWORD16((*mmAPI)( INT32(parg16->f1), UINT32(parg16->f2),
+ (DWORD)lpdwParam1, DWORD32(parg16->f4) ));
+ FREEMISCPTR(lpdwParam1);
+
+ } else {
+
+ ul = GETDWORD16((*mmAPI)( INT32(parg16->f1),
+ MAKELONG( WORD32(parg16->f2), 0xFFFF ),
+ DWORD32(parg16->f3),
+ DWORD32(parg16->f4) ));
+ }
+
+ trace_aux(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/* ---------------------------------------------------------------------
+** Joystick APIs
+** ---------------------------------------------------------------------
+*/
+
+/**********************************************************************\
+*
+* WMM32joyGetNumDevs
+*
+* This function returns the number of joystick devices supported by the system.
+*
+*
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32joyGetNumDevs(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "joyGetNumDevs", mmAPI, MMSYSERR_NODRIVER );
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ trace_joy(( "joyGetNumDevs()" ));
+ ul = GETWORD16((*mmAPI)());
+ trace_joy(( "-> %ld\n", ul ));
+
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32joyGetDevCaps
+*
+* This function queries a joystick device to determine its capabilities.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32joyGetDevCaps(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ JOYCAPS joycaps;
+ register PJOYGETDEVCAPS16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "joyGetDevCapsA", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(JOYGETDEVCAPS16), parg16);
+
+ trace_joy(( "joyGetDevCaps( %x, %x, %x )", INT32(parg16->f1),
+ DWORD32(parg16->f2), UINT32(parg16->f3) ));
+
+ ul = GETWORD16((*mmAPI)(INT32(parg16->f1), &joycaps, sizeof(JOYCAPS)));
+
+ if ( ul == JOYERR_NOERROR ) {
+ ul = PUTJOYCAPS16( parg16->f2, &joycaps, UINT32(parg16->f3) );
+ }
+ trace_joy(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32joyGetPos
+*
+* This function queries the position and button activity of a joystick device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32joyGetPos(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ JOYINFO joyinfo;
+ register PJOYGETPOS16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "joyGetPos", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(JOYGETPOS16), parg16);
+ trace_joy(( "joyGetPosition( %x, %x )", WORD32(parg16->f1),
+ DWORD32(parg16->f2) ));
+
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), &joyinfo ));
+
+ if ( ul == JOYERR_NOERROR ) {
+ ul = PUTJOYINFO16( parg16->f2, &joyinfo );
+ }
+ trace_joy(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32joySetThreshold
+*
+* This function sets the movement threshold of a joystick device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32joySetThreshold(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PJOYSETTHRESHOLD16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "joySetThreshold", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(JOYSETTHRESHOLD), parg16);
+
+ trace_joy(( "joySetThreshold( %x, %x )", INT32(parg16->f1),
+ UINT32(parg16->f2) ));
+
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), UINT32(parg16->f2) ));
+ trace_joy(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32joyGetThreshold
+*
+* This function queries the current movement threshold of a joystick device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32joyGetThreshold(PVDMFRAME pFrame)
+{
+ register PJOYGETTHRESHOLD16 parg16;
+ ULONG ul;
+ UINT uThreshold;
+ LPWORD lpwThreshold16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "joyGetThreshold", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(JOYGETTHRESHOLD16), parg16);
+ trace_joy(( "joyGetThreshold( %x, %x )", WORD32(parg16->f1),
+ DWORD32(parg16->f2) ));
+
+
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), &uThreshold ));
+
+ /*
+ ** Only copy the threshold back to 16 bit space if the call was sucessful
+ **
+ */
+ if ( ul == JOYERR_NOERROR ) {
+
+ MMGETOPTPTR( parg16->f2, sizeof(WORD), lpwThreshold16 );
+
+ if ( lpwThreshold16 ) {
+ STOREWORD ( *lpwThreshold16, uThreshold );
+ FLUSHVDMPTR( DWORD32(parg16->f2), sizeof(WORD), lpwThreshold16 );
+ FREEVDMPTR ( lpwThreshold16 );
+ }
+ else {
+ ul = JOYERR_PARMS;
+ }
+ }
+
+ trace_joy(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/**********************************************************************\
+*
+* WMM32joyReleaseCapture
+*
+* This function releases the capture set by joySetCapture on the specified
+* joystick device
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32joyReleaseCapture(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PJOYRELEASECAPTURE16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "joyReleaseCapture", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(JOYRELEASECAPTURE16), parg16);
+
+ trace_joy(( "joyReleaseCapture( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1) ));
+ trace_joy(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32joySetCapture
+*
+* This function causes joystick messages to be sent to the specified window.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32joySetCapture(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PJOYSETCAPTURE16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "joySetCapture", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(JOYSETCAPTURE), parg16);
+
+ trace_joy(( "joySetCapture( %x, %x, %x, %x )", WORD32(parg16->f1),
+ INT32(parg16->f2), UINT32(parg16->f3), BOOL32(parg16->f4) ));
+
+ ul = GETWORD16((*mmAPI)( HWND32(parg16->f1), INT32(parg16->f2),
+ UINT32(parg16->f3), BOOL32(parg16->f4) ));
+ trace_joy(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/**********************************************************************\
+*
+* WMM32joySetCalibration
+*
+* This function allows the calibration of a joystick device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32joySetCalibration(PVDMFRAME pFrame)
+{
+ register PJOYSETCALIBRATION16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ LPWORD lpwXbase;
+ LPWORD lpwXdelta;
+ LPWORD lpwYbase;
+ LPWORD lpwYdelta;
+ LPWORD lpwZbase;
+ LPWORD lpwZdelta;
+ UINT uXbase;
+ UINT uXdelta;
+ UINT uYbase;
+ UINT uYdelta;
+ UINT uZbase;
+ UINT uZdelta;
+
+ GET_MULTIMEDIA_API( "joySetCapture", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(JOYSETCALIBRATION16), parg16);
+
+ trace_joy(( "joySetCalibration( %x, %x, %x, %x, %x, %x, %x )",
+ DWORD32(parg16->f1), UINT32(parg16->f2), UINT32(parg16->f3),
+ UINT32(parg16->f4), UINT32(parg16->f5), UINT32(parg16->f6),
+ UINT32(parg16->f7) ));
+
+ MMGETOPTPTR( parg16->f2, sizeof(WORD), lpwXbase );
+ if ( lpwXbase == NULL ) {
+ goto exit_1;
+ }
+
+ MMGETOPTPTR( parg16->f3, sizeof(WORD), lpwXdelta );
+ if ( lpwXdelta == NULL ) {
+ goto exit_2;
+ }
+
+ MMGETOPTPTR( parg16->f4, sizeof(WORD), lpwYbase );
+ if ( lpwYbase == NULL ) {
+ goto exit_3;
+ }
+
+ MMGETOPTPTR( parg16->f5, sizeof(WORD), lpwYdelta );
+ if ( lpwYdelta == NULL ) {
+ goto exit_4;
+ }
+
+ MMGETOPTPTR( parg16->f6, sizeof(WORD), lpwZbase );
+ if ( lpwZbase == NULL ) {
+ goto exit_5;
+ }
+
+ MMGETOPTPTR( parg16->f7, sizeof(WORD), lpwZdelta );
+ if ( lpwZdelta == NULL ) {
+ goto exit_6;
+ }
+
+ uXbase = FETCHWORD( *lpwXbase );
+ uXdelta = FETCHWORD( *lpwXdelta );
+ uYbase = FETCHWORD( *lpwYbase );
+ uYdelta = FETCHWORD( *lpwYdelta );
+ uZbase = FETCHWORD( *lpwZbase );
+ uZdelta = FETCHWORD( *lpwZdelta );
+
+ ul = GETWORD16((*mmAPI)( DWORD32(parg16->f1), &uXbase, &uXdelta,
+ &uYbase, &uYdelta, &uZbase, &uZdelta ));
+
+ STOREWORD( *lpwXbase, uXbase );
+ STOREWORD( *lpwXdelta, uXdelta );
+ STOREWORD( *lpwYbase, uYbase );
+ STOREWORD( *lpwYdelta, uYdelta );
+ STOREWORD( *lpwZbase, uZbase );
+ STOREWORD( *lpwZdelta, uZdelta );
+
+ FREEMISCPTR( lpwZdelta );
+
+exit_6:
+ FREEMISCPTR( lpwZbase );
+
+exit_5:
+ FREEMISCPTR( lpwYdelta );
+
+exit_4:
+ FREEMISCPTR( lpwYbase );
+
+exit_3:
+ FREEMISCPTR( lpwXdelta );
+
+exit_2:
+ FREEMISCPTR( lpwXbase );
+
+exit_1:
+ trace_joy(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+#endif
+
+
diff --git a/private/mvdm/wow32/wmmedia2.c b/private/mvdm/wow32/wmmedia2.c
new file mode 100644
index 000000000..df5e10043
--- /dev/null
+++ b/private/mvdm/wow32/wmmedia2.c
@@ -0,0 +1,3382 @@
+/***********************************************************************\
+
+*
+* WOW v1.0
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* WMMEDIA2.C
+* WOW32 16-bit MultiMedia API support
+*
+* Contains:
+* Midi IN apis
+* Midi OUT apis
+* Wave IN apis
+* Wave OUT apis
+*
+*
+* History:
+* Created 21-Jan-1992 by Mike Tricker (MikeTri), after jeffpar
+* Changed 15-Jul-1992 by Mike Tricker (MikeTri), fixing GetDevCaps calls
+* 26-Jul-1992 by Stephen Estrop (StephenE) thunks for mciSendCommand
+* 30-Jul-1992 by Mike Tricker (MikeTri), fixing Wave/Midi/MMIO
+* 03-Aug-1992 by Mike Tricker (MikeTri), added proper error handling
+* 08-Oct-1992 by StephenE spawned from the original wmmedia.c
+*
+\***********************************************************************/
+
+
+//
+// We define NO_STRICT so that the compiler doesn't moan and groan when
+// I use the FARPROC type for the Multi-Media api loading.
+//
+#define NO_STRICT
+#define OEMRESOURCE
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if 0
+
+
+MODNAME(wmmedia2.c);
+
+// A 32 bit ptr to the 16 bit callback data
+extern PCALLBACK_DATA pCallBackData;
+extern CRITICAL_SECTION mmCriticalSection;
+
+#if DBG
+/*
+** AllocCount maintains a count of the number XXM_DONE messages that
+** we expect to receive before the device is closed. When the device is
+** closed this count should be zero.
+**
+*/
+int AllocWaveCount = 0;
+int AllocMidiCount = 0;
+int mmTraceWave = 0;
+int mmTraceMidi = 0;
+#endif
+
+
+/* ---------------------------------------------------------------------
+** MIDI Output API's
+** ---------------------------------------------------------------------
+*/
+
+/**********************************************************************\
+*
+* WMM32midiOutGetNumDevs
+*
+* This function retrieves the number of MIDI output devices present
+* in the system.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutGetNumDevs(PVDMFRAME pFrame)
+{
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ GET_MULTIMEDIA_API( "midiOutGetNumDevs", mmAPI, MMSYSERR_NODRIVER );
+
+ trace_midi(( "midiOutGetNumDevs()" ));
+ ul = GETWORD16((*mmAPI)() );
+ trace_midi(( "-> %ld\n", ul ));
+
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutGetDevCaps
+*
+* This function queries a specified MIDI output device to determine its
+* capabilities.
+*
+*
+*
+* We will now change things...
+*
+* Step 1: get the ENTIRE Caps structure, irrespective of the number of bytes
+* requested
+* (previously I was getting the requested number of bytes via
+* parg16->f3 (plus 2 'cos of the WORD -> UINT change for version -
+* which was wrong anyway...) )
+*
+* Step 2: thunk the ENTIRE structure in to a 16 bit local variable
+*
+* Step 3: RtlCopyMemory the REQUESTED number of bytes from the local copy
+* to the "real" structure within the app
+*
+* Thanks to RCBS for sorting me out once again !
+*
+*
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutGetDevCaps(PVDMFRAME pFrame)
+
+{
+ register PMIDIOUTGETDEVCAPS16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ MIDIOUTCAPS midioutcaps;
+
+ GET_MULTIMEDIA_API( "midiOutGetDevCapsA", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTGETDEVCAPS16), parg16);
+
+ trace_midi(( "midiOutGetDevCaps( %x, %x, %x )", INT32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+
+ /*
+ ** If the size parameter was zero return straight away. Note that this
+ ** is not an error.
+ */
+ if ( UINT32( parg16->f3 ) == 0 ) {
+ ul = MMSYSERR_NOERROR;
+ }
+ else {
+
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), &midioutcaps,
+ sizeof(MIDIOUTCAPS) ));
+ /*
+ ** This must now thunk the ENTIRE structure, then copy parg16->f3
+ ** bytes onto the "real" structure in the app, but only if the call
+ ** returned success.
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+ ul = PUTMIDIOUTCAPS16(parg16->f2, &midioutcaps, UINT32(parg16->f3));
+ }
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutGetErrorText
+*
+* This function retrieves a textual description of the error
+* identified by the specified error number.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutGetErrorText(PVDMFRAME pFrame)
+{
+ register PMIDIOUTGETERRORTEXT16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul = MMSYSERR_NOERROR;
+ PSZ pszText;
+
+ GET_MULTIMEDIA_API( "midiOutGetErrorTextA", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTGETERRORTEXT16), parg16);
+
+ trace_midi(( "midiOutGetErrorText( %x, %x, %x )", UINT32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** Test against a zero length string and a NULL pointer. If 0 is passed
+ ** as the buffer length then the manual says we should return
+ ** MMSYSERR_NOERR. MMGETOPTPTR only returns a pointer if parg16->f2 is
+ ** not NULL.
+ */
+ MMGETOPTPTR( parg16->f2, UINT32(parg16->f3), pszText );
+ if ( pszText != NULL ) {
+
+ ul = GETWORD16((*mmAPI)( UINT32(parg16->f1), pszText,
+ UINT32(parg16->f3) ));
+
+ FLUSHVDMPTR(DWORD32(parg16->f2), UINT32(parg16->f3), pszText);
+ FREEVDMPTR(pszText);
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/***********************************************************************\
+*
+* WMM32midiOutOpen
+*
+* This function opens a specified MIDI output device for playback.
+*
+\***********************************************************************/
+ULONG FASTCALL WMM32midiOutOpen(PVDMFRAME pFrame)
+{
+ register PMIDIOUTOPEN16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ ULONG ul = MMSYSERR_NOERROR;
+ UINT uDevID;
+ PINSTANCEDATA pInstanceData;
+ LPHMIDIOUT lpHMidiOut; // pointer to handle in 16 bit app space
+ HMIDIOUT Hand32; // 32bit handle
+
+ GET_MULTIMEDIA_API( "midiOutOpen", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTOPEN16), parg16);
+
+ trace_midi(( "midiOutOpen( %x, %x, %x, %x, %x )",
+ DWORD32( parg16->f1 ), INT32 ( parg16->f2 ),
+ DWORD32( parg16->f3 ), DWORD32( parg16->f4 ),
+ DWORD32( parg16->f5 ) ));
+
+ /*
+ ** Get the device ID. We use INT32 here not UINT32 to make sure that
+ ** negative values (such as MIDI_MAPPER (-1)) get thunked correctly.
+ */
+ uDevID = (UINT)INT32(parg16->f2);
+
+ /*
+ ** Map the 16 bit pointer is one was specified.
+ */
+ MMGETOPTPTR( parg16->f1, sizeof(HMIDIOUT16), lpHMidiOut );
+ if ( lpHMidiOut ) {
+
+ /*
+ ** Create InstanceData block to be used by our callback routine.
+ **
+ ** NOTE: Although we malloc it here we don't free it.
+ ** This is not a mistake - it must not be freed before the
+ ** callback routine has used it - so it does the freeing.
+ **
+ ** If the malloc fails we bomb down to the bottom,
+ ** set ul to MMSYSERR_NOMEM and exit gracefully.
+ **
+ ** We always have a callback functions. This is to ensure that
+ ** the MIDIHDR structure keeps getting copied back from
+ ** 32 bit space to 16 bit, as it contains flags which
+ ** applications are liable to keep checking.
+ */
+ if ( pInstanceData = malloc_w(sizeof(INSTANCEDATA)) ) {
+
+ dprintf2(( "WM32midiOutOpen: Allocated instance buffer at %8X",
+ pInstanceData ));
+ pInstanceData->dwCallback = DWORD32(parg16->f3);
+ pInstanceData->dwCallbackInstance = DWORD32(parg16->f4);
+ pInstanceData->dwFlags = DWORD32(parg16->f5);
+
+ ul = GETWORD16((*mmAPI)( &Hand32, uDevID,
+ (DWORD)W32CommonDeviceOpen,
+ (DWORD)pInstanceData,
+ CALLBACK_FUNCTION ));
+
+ }
+ else {
+ ul = MMSYSERR_NOMEM;
+ }
+
+ /*
+ ** If the call returns success update the 16 bit handle,
+ ** otherwise don't, and free the memory we malloc'd earlier, as
+ ** the callback that would have freed it will never get callled.
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ HMIDIOUT16 Hand16 = GETHMIDIOUT16(Hand32);
+
+ trace_midi(( "Handle -> %x", Hand16 ));
+
+ STOREWORD ( *lpHMidiOut, Hand16 );
+ FLUSHVDMPTR( DWORD32(parg16->f1), sizeof(HMIDIOUT16),
+ lpHMidiOut );
+ }
+
+ /*
+ ** We only free the memory if we actually allocated any
+ */
+ else if ( pInstanceData ) {
+
+ free_w(pInstanceData);
+ }
+
+ /*
+ ** Regardless of sucess or failure we need to free the pointer
+ ** to the 16 bit MidiIn handle.
+ */
+ FREEVDMPTR ( lpHMidiOut );
+
+ }
+ else {
+
+ ul = MMSYSERR_INVALPARAM;
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/**********************************************************************\
+*
+* WMM32midiOutClose
+*
+* This function closes the specified MIDI output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutClose(PVDMFRAME pFrame)
+{
+ register PMIDIOUTCLOSE16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+
+ GET_MULTIMEDIA_API( "midiOutClose", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTCLOSE16), parg16);
+
+ trace_midi(( "midiOutClose( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16( (*mmAPI)(HMIDIOUT32(parg16->f1) ));
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/**********************************************************************\
+*
+* WMM32midiOutPrepareHeader
+*
+* This function prepares the specified midiform header.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutPrepareHeader(PVDMFRAME pFrame)
+{
+ register PMIDIOUTPREPAREHEADER3216 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ MIDIHDR midihdr;
+
+
+ GET_MULTIMEDIA_API( "midiOutPrepareHeader", mmAPI, MMSYSERR_NODRIVER );
+ GETARGPTR(pFrame, sizeof(MIDIOUTPREPAREHEADER3216), parg16);
+ trace_midi(( "midiOutPrepareHeader( %x %x %x)", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), WORD32( parg16->f3 ) ));
+
+ GETMIDIHDR16(parg16->f2, &midihdr);
+
+ ul = GETWORD16((*mmAPI)( HMIDIOUT32(parg16->f1),
+ &midihdr, WORD32(parg16->f3) ) );
+ /*
+ ** Only update the 16 bit structure if the call returns success
+ **
+ */
+ if ( !ul ) {
+ PUTMIDIHDR16(parg16->f2, &midihdr);
+ }
+
+ trace_midi(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutUnprepareHeader
+*
+* This function prepares the specified midiform header.
+* This function cleans up the preparation performed by midiOutPrepareHeader.
+* The function must be called after the device driver has finished with a
+* data block. You must call this function before freeing the data buffer.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutUnprepareHeader(PVDMFRAME pFrame)
+{
+ register PMIDIOUTUNPREPAREHEADER3216 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ MIDIHDR midihdr;
+
+ GET_MULTIMEDIA_API( "midiOutUnprepareHeader", mmAPI, MMSYSERR_NODRIVER );
+ GETARGPTR(pFrame, sizeof(MIDIOUTUNPREPAREHEADER3216), parg16);
+ trace_midi(( "midiOutUnprepareHeader( %x %x %x)", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), WORD32( parg16->f3 ) ));
+
+ GETMIDIHDR16(parg16->f2, &midihdr);
+
+ ul = GETWORD16((*mmAPI)( HMIDIOUT32(parg16->f1),
+ &midihdr, WORD32(parg16->f3) ) );
+ /*
+ ** Only update the 16 bit structure if the call returns success
+ */
+ if (!ul) {
+ PUTMIDIHDR16(parg16->f2, &midihdr);
+ }
+
+ trace_midi(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/**********************************************************************\
+*
+* WMM32midiOutShortMsg
+*
+* This function sends a short MIDI message to the specified MIDI output device.
+* Use this function to send any MIDI message except for system exclusive
+* messages.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutShortMsg(PVDMFRAME pFrame)
+{
+ register PMIDIOUTSHORTMSG16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+
+ GET_MULTIMEDIA_API( "midiOutShortMsg", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTSHORTMSG16), parg16);
+
+ trace_midi(( "midiOutShortMsg( %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+
+ ul = GETWORD16((*mmAPI)( HMIDIOUT32(parg16->f1), DWORD32(parg16->f2) ));
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutLongMsg
+*
+* This function sends a long MIDI message to the specified MIDI output
+* device. Use this function to send system exclusive messages or to
+* send a buffer filled with short messages.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutLongMsg(PVDMFRAME pFrame)
+{
+ register PMIDIOUTLONGMSG16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ PMIDIHDR32 pMidihdr32;
+
+ GET_MULTIMEDIA_API( "midiOutLongMsg", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTLONGMSG16), parg16);
+
+ trace_midi(( "midiOutLongMsg( %x, %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** If the given size of the MIDIHDR structure is too small
+ ** or the lphdr is invalid return an error
+ **
+ */
+ if ( UINT32(parg16->f3) < sizeof(MIDIHDR16)
+ || HIWORD( DWORD32(parg16->f2) ) == 0 ) {
+
+ ul = MMSYSERR_INVALPARAM;
+ }
+ else {
+ if ( pMidihdr32 = malloc_w(sizeof(MIDIHDR32)) ) {
+
+ PMIDIHDR lpwhdr;
+#if DBG
+ AllocMidiCount++;
+ dprintf2(( "M>> %8X (%d)", pMidihdr32, AllocMidiCount ));
+#endif
+ /* Copy across the midi header stuff. Note that lpwhdr (a
+ ** 32 bit ptr to a 32 bit midi header) is used to make the
+ ** pointer stuff a bit less hairy.
+ **
+ ** pMidihdr32->pMidihdr32 is a 32 bit ptr to a 16 bit midi header
+ ** pMidihdr32->pMidihdr16 is a 16 bit ptr to a 16 bit midi header
+ ** pMidihdr32->Midihdr is a 32 bit midi header
+ */
+ lpwhdr = &(pMidihdr32->Midihdr);
+ pMidihdr32->pMidihdr16 = (PMIDIHDR16)DWORD32(parg16->f2);
+ pMidihdr32->pMidihdr32 = GETMIDIHDR16(DWORD32(parg16->f2), lpwhdr);
+
+ /*
+ ** GETMIDIHDR16 can return NULL, in which case we should set
+ ** lpwhdr to NULL too and call midiOutLongMessage only to get the
+ ** correct error code.
+ */
+ if ( pMidihdr32->pMidihdr32 == NULL ) {
+ lpwhdr = NULL;
+ }
+
+ ul = GETWORD16( (*mmAPI)( HMIDIOUT32(parg16->f1), lpwhdr,
+ UINT32(parg16->f3) ) );
+ /*
+ ** If the call fails we need to free the memory we malloc'd
+ ** above, as the callback that would have freed it will never
+ ** get called.
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ /*
+ ** Make sure we reflect any changes that midiOutLongMessage did
+ ** to the MIDIHDR back to 16 bit land.
+ **
+ ** This is important because some apps poll the
+ ** MHDR_DONE bit !!
+ */
+ COPY_MIDIOUTHDR16_FLAGS( pMidihdr32->pMidihdr32,
+ pMidihdr32->Midihdr );
+ }
+ else {
+#if DBG
+ AllocMidiCount--;
+ dprintf2(( "M<< \t%8X (%d)", pMidihdr32,
+ AllocMidiCount ));
+#endif
+ free_w( pMidihdr32 );
+ }
+ }
+ else {
+ ul = MMSYSERR_NOMEM;
+ }
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutReset
+*
+* This function turns off all notes on al MIDI channels for the specified
+* MIDI output deice.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutReset(PVDMFRAME pFrame)
+{
+ register PMIDIOUTRESET16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+
+ GET_MULTIMEDIA_API( "midiOutReset", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTRESET16), parg16);
+
+ trace_midi(( "midiOutReset( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)( HMIDIOUT32(parg16->f1) ));
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutGetVolume
+*
+* This function returns the current volume setting of a MIDI output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutGetVolume(PVDMFRAME pFrame)
+{
+ register PMIDIOUTGETVOLUME16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ LPDWORD lpdwVolume;
+ DWORD dwVolume;
+
+ GET_MULTIMEDIA_API( "midiOutGetVolume", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTGETVOLUME16), parg16);
+
+ trace_midi(( "midiOutGetVolume( %x, %x )", INT32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), &dwVolume ));
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ MMGETOPTPTR( parg16->f2, sizeof(DWORD), lpdwVolume);
+
+ if ( lpdwVolume ) {
+ STOREDWORD ( *lpdwVolume, dwVolume );
+ FLUSHVDMPTR( DWORD32(parg16->f2), sizeof(DWORD), lpdwVolume );
+ FREEVDMPTR ( lpdwVolume );
+ }
+ else {
+ ul = MMSYSERR_INVALPARAM;
+ }
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutSetVolume
+*
+* This function sets the volume of a MIDI output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutSetVolume(PVDMFRAME pFrame)
+{
+ register PMIDIOUTSETVOLUME16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+
+ GET_MULTIMEDIA_API( "midiOutSetVolume", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTSETVOLUME16), parg16);
+
+ trace_midi(( "midiOutSetVolume( %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), DWORD32(parg16->f2) ));
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutCachePatches
+*
+* This function requests that an internal MIDI synthesizer device preload a
+* specified set of patches. Some synthesizers are not capable of keeping all
+* patches loaded simultaneously and must load data from disk when they receive
+* MIDI program change messages. Caching patches ensures specified patches are
+* immediately available.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutCachePatches(PVDMFRAME pFrame)
+{
+ register PMIDIOUTCACHEPATCHES16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul = MMSYSERR_INVALPARAM;
+ LPPATCHARRAY lppa1;
+
+ GET_MULTIMEDIA_API( "midiOutCachePatches", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTCACHEPATCHES16), parg16);
+
+ trace_midi(( "midiOutCachePatches( %x, %x, %x, %x )", WORD32( parg16->f1 ),
+ UINT32( parg16->f2 ), DWORD32( parg16->f3 ),
+ UINT32( parg16->f4 ) ));
+
+ /*
+ ** GETMISCPTR checks that parg16->f3 is not zero so we need not bother.
+ */
+ GETMISCPTR( DWORD32( parg16->f3 ), lppa1 );
+
+ if ( lppa1 ) {
+
+ ul = GETWORD16((*mmAPI)( HMIDIOUT32(parg16->f1), UINT32(parg16->f2),
+ lppa1, UINT32(parg16->f4) ));
+ FREEMISCPTR( lppa1 );
+
+ }
+ else {
+ dprintf1(( "WMM32midiOutCachePatches passed a NULL pointer" ));
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutCacheDrumPatches
+*
+* This function requests that an internal MIDI synthesizer device preload a
+* specified set of key-based percussion patches. Some synthesizers are not
+* capable of keeping all percussion patches loaded simultaneously. Caching
+* patches ensures specified patches are immediately available.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutCacheDrumPatches(PVDMFRAME pFrame)
+{
+ register PMIDIOUTCACHEDRUMPATCHES16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul = MMSYSERR_INVALPARAM;
+ LPKEYARRAY lpka1;
+
+ GET_MULTIMEDIA_API( "midiOutCacheDrumPatches", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTCACHEDRUMPATCHES16), parg16);
+ trace_midi(( "midiOutCacheDrumPatches( %x, %x, %x, %x )",
+ WORD32( parg16->f1 ), UINT32( parg16->f2 ),
+ DWORD32( parg16->f3 ), UINT32( parg16->f4 ) ));
+
+ GETMISCPTR( DWORD32( parg16->f3 ), lpka1 );
+ if ( lpka1 ) {
+
+ ul = GETWORD16((*mmAPI)( HMIDIOUT32(parg16->f1), UINT32(parg16->f2),
+ lpka1, UINT32(parg16->f4) ) );
+ FREEMISCPTR(lpka1);
+ }
+ else {
+ dprintf1(( "WMM32midiOutCacheDrumPatches passed a NULL pointer" ));
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutGetID
+*
+* This function gets the device ID for a MIDI output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutGetID(PVDMFRAME pFrame)
+{
+ register PMIDIOUTGETID16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ UINT dwDeviceID32;
+ LPWORD lpwDeviceID16;
+
+ GET_MULTIMEDIA_API( "midiOutGetID", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTGETID16), parg16);
+
+ trace_midi(( "midiOutGetID( %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+
+ ul = GETWORD16((*mmAPI)( (HMIDIOUT)HMIDIOUT32(parg16->f1), &dwDeviceID32 ));
+
+ /*
+ ** Only copy the ID back to 16 bit space if the call was sucessful
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ MMGETOPTPTR( parg16->f2, sizeof(WORD), lpwDeviceID16 );
+
+ if ( lpwDeviceID16 ) {
+ STOREWORD ( *lpwDeviceID16, dwDeviceID32 );
+ FLUSHVDMPTR( DWORD32(parg16->f2), sizeof(WORD), lpwDeviceID16 );
+ FREEVDMPTR ( lpwDeviceID16 );
+ }
+ else {
+ ul = MMSYSERR_INVALPARAM;
+ }
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiOutMessage
+*
+* This function sends a message to the specified MIDI output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiOutMessage(PVDMFRAME pFrame)
+{
+ register PMIDIOUTMESSAGE3216 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+
+ GET_MULTIMEDIA_API( "midiOutMessage", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIOUTMESSAGE16), parg16);
+
+ trace_midi(( "midiOutMessage( %x, %x, %x, %x )",
+ WORD32( parg16->f1 ), UINT32( parg16->f2 ),
+ DWORD32( parg16->f3 ), DWORD32( parg16->f4 ) ));
+
+ if ( (UINT32(parg16->f2) >= DRV_BUFFER_LOW)
+ && (UINT32(parg16->f2) <= DRV_BUFFER_HIGH) ) {
+
+ LPDWORD lpdwParam1;
+ GETMISCPTR(parg16->f3, lpdwParam1);
+
+ ul = GETDWORD16((*mmAPI)( HMIDIOUT32(parg16->f1), UINT32(parg16->f2),
+ (DWORD)lpdwParam1, DWORD32(parg16->f4)));
+ FREEMISCPTR(lpdwParam1);
+
+ } else {
+ ul = GETDWORD16((*mmAPI)( HMIDIOUT32(parg16->f1),
+ MAKELONG( WORD32(parg16->f2), 0xFFFF ),
+ DWORD32(parg16->f3), DWORD32(parg16->f4) ));
+ }
+
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/* ---------------------------------------------------------------------
+** MIDI Input API's
+** ---------------------------------------------------------------------
+*/
+
+
+/**********************************************************************\
+*
+* WMM32midiInGetNumDevs
+*
+* This function retrieves the number of MIDI input devices in the system.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInGetNumDevs(PVDMFRAME pFrame)
+{
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+
+ GET_MULTIMEDIA_API( "midiInGetNumDevs", mmAPI, MMSYSERR_NODRIVER );
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ trace_midi(( "midiInGetNumDevs()" ));
+ ul = GETWORD16((*mmAPI)() );
+ trace_midi(( "-> %ld\n", ul ));
+
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiInGetDevCaps
+*
+* This function queries a specified MIDI input device to determine its
+* capabilities.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInGetDevCaps(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ MIDIINCAPS midiincaps1;
+ register PMIDIINGETDEVCAPS16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "midiInGetDevCapsA", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIINGETDEVCAPS16), parg16);
+
+ trace_midi(( "midiInGetDevCaps( %x, %x, %x )", INT32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+ if ( UINT32( parg16->f3 ) == 0 ) {
+ ul = MMSYSERR_NOERROR;
+ }
+ else {
+
+ ul = GETWORD16((*mmAPI)(INT32(parg16->f1), &midiincaps1,
+ sizeof(MIDIINCAPS) ) );
+ /*
+ ** This must now thunk the ENTIRE structure, then copy parg16->f3
+ ** bytes onto the "real" structure in the app, but only if the
+ ** call returned success.
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+ ul = PUTMIDIINCAPS16( parg16->f2, &midiincaps1, UINT32(parg16->f3) );
+ }
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiInGetErrorText
+*
+* This function retrieves a textual description of the error identified by the
+* specified error number.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInGetErrorText(PVDMFRAME pFrame)
+{
+ register PMIDIINGETERRORTEXT16 parg16;
+ ULONG ul = MMSYSERR_NOERROR;
+ PSZ pszText;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "midiInGetErrorTextA", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR( pFrame, sizeof(MIDIINGETERRORTEXT16), parg16 );
+
+ trace_midi(( "midiInGetErrorText( %x, %x, %x )", UINT32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+ /*
+ ** Test against a zero length string and a NULL pointer. If 0 is passed
+ ** as the buffer length then the manual says we should return
+ ** MMSYSERR_NOERR.
+ */
+ MMGETOPTPTR( parg16->f2, UINT32(parg16->f3), pszText );
+ if ( pszText != NULL ) {
+
+ ul = GETWORD16( (*mmAPI)( UINT32(parg16->f1), pszText,
+ UINT32(parg16->f3) ) );
+
+ FLUSHVDMPTR( DWORD32(parg16->f2), UINT32(parg16->f3), pszText);
+ FREEVDMPTR( pszText );
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/**********************************************************************\
+*
+* WMM32midiInOpen
+*
+* This function opens a specified MIDI input device.
+*
+\***********************************************************************/
+ULONG FASTCALL WMM32midiInOpen(PVDMFRAME pFrame)
+{
+ ULONG ul=0;
+ UINT uDevID;
+ PINSTANCEDATA pInstanceData;
+ LPHMIDIIN lpHMidiIn; // pointer to handle in 16 bit app space
+ HMIDIIN Hand32; // 32bit handle
+ register PMIDIINOPEN16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "midiInOpen", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIINOPEN16), parg16);
+
+ trace_midi(( "midiInOpen( %x, %x, %x, %x, %x )",
+ DWORD32( parg16->f1 ), INT32 ( parg16->f2 ),
+ DWORD32( parg16->f3 ), DWORD32( parg16->f4 ),
+ DWORD32( parg16->f5 ) ));
+
+ /*
+ ** Get the device ID. We use INT32 here not UINT32 to make sure that
+ ** negative values (such as MIDI_MAPPER (-1)) get thunked correctly.
+ */
+ uDevID = (UINT)INT32(parg16->f2);
+
+ /*
+ ** Map the 16 bit pointer is one was specified.
+ */
+ MMGETOPTPTR( parg16->f1, sizeof(HMIDIIN), lpHMidiIn );
+ if ( lpHMidiIn ) {
+
+ /*
+ ** Create InstanceData block to be used by our callback routine.
+ **
+ ** NOTE: Although we malloc it here we don't free it.
+ ** This is not a mistake - it must not be freed before the
+ ** callback routine has used it - so it does the freeing.
+ **
+ ** If the malloc fails we bomb down to the bottom,
+ ** set ul to MMSYSERR_NOMEM and exit gracefully.
+ **
+ ** We always have a callback functions. This is to ensure that
+ ** the MIDIHDR structure keeps getting copied back from
+ ** 32 bit space to 16 bit, as it contains flags which
+ ** applications are liable to keep checking.
+ */
+ if ( pInstanceData = malloc_w(sizeof(INSTANCEDATA) ) ) {
+
+ dprintf2(( "WM32midiInOpen: Allocated instance buffer at %8X",
+ pInstanceData ));
+ pInstanceData->dwCallback = DWORD32(parg16->f3);
+ pInstanceData->dwCallbackInstance = DWORD32(parg16->f4);
+ pInstanceData->dwFlags = DWORD32(parg16->f5);
+
+ ul = GETWORD16((*mmAPI)( &Hand32, uDevID,
+ (DWORD)W32CommonDeviceOpen,
+ (DWORD)pInstanceData,
+ CALLBACK_FUNCTION ));
+
+ }
+ else {
+
+ ul = (ULONG)MMSYSERR_NOMEM;
+ }
+
+ /*
+ ** If the call returns success update the 16 bit handle,
+ ** otherwise don't, and free the memory we malloc'd earlier, as
+ ** the callback that would have freed it will never get callled.
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ HMIDIIN16 Hand16 = GETHMIDIIN16(Hand32);
+
+ trace_midi(( "Handle -> %x", Hand16 ));
+ STOREWORD ( *lpHMidiIn, Hand16 );
+ FLUSHVDMPTR( DWORD32(parg16->f1), sizeof(HMIDIIN), lpHMidiIn );
+ }
+
+ /*
+ ** We only free the memory if we actually allocated any and the
+ ** 32 bit call failed.
+ */
+ else if ( pInstanceData ) {
+
+ free_w(pInstanceData);
+ }
+
+ /*
+ ** Regardless of sucess or failure we need to free the pointer
+ ** to the 16 bit MidiIn handle.
+ */
+ FREEVDMPTR ( lpHMidiIn );
+
+ }
+ else {
+ ul = MMSYSERR_INVALPARAM;
+ }
+
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiInClose
+*
+* This function closes the specified MIDI input device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInClose(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PMIDIINCLOSE16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "midiInClose", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIINCLOSE16), parg16);
+
+ trace_midi(( "midiInClose( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)(HMIDIIN32(parg16->f1) ) );
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/**********************************************************************\
+*
+* WMM32midiInPrepareHeader
+*
+* This function prepares the specified midiform header.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInPrepareHeader(PVDMFRAME pFrame)
+{
+ register PMIDIOUTPREPAREHEADER3216 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ MIDIHDR midihdr;
+
+
+ GET_MULTIMEDIA_API( "midiInPrepareHeader", mmAPI, MMSYSERR_NODRIVER );
+ GETARGPTR(pFrame, sizeof(MIDIOUTPREPAREHEADER3216), parg16);
+ trace_midi(( "midiInPrepareHeader( %x %x %x)", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), WORD32( parg16->f3 ) ));
+
+ GETMIDIHDR16(parg16->f2, &midihdr);
+
+ ul = GETWORD16((*mmAPI)( HMIDIOUT32(parg16->f1),
+ &midihdr, WORD32(parg16->f3) ) );
+ /*
+ ** Only update the 16 bit structure if the call returns success
+ **
+ */
+ if ( !ul ) {
+ PUTMIDIHDR16(parg16->f2, &midihdr);
+ }
+
+ trace_midi(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiInUnprepareHeader
+*
+* This function prepares the specified midiform header.
+* This function cleans up the preparation performed by midiInPrepareHeader.
+* The function must be called after the device driver has finished with a
+* data block. You must call this function before freeing the data buffer.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInUnprepareHeader(PVDMFRAME pFrame)
+{
+ register PMIDIOUTUNPREPAREHEADER3216 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ MIDIHDR midihdr;
+
+ GET_MULTIMEDIA_API( "midiInUnprepareHeader", mmAPI, MMSYSERR_NODRIVER );
+ GETARGPTR(pFrame, sizeof(MIDIOUTUNPREPAREHEADER3216), parg16);
+ trace_midi(( "midiInUnprepareHeader( %x %x %x)", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), WORD32( parg16->f3 ) ));
+
+ GETMIDIHDR16(parg16->f2, &midihdr);
+
+ ul = GETWORD16((*mmAPI)( HMIDIOUT32(parg16->f1),
+ &midihdr, WORD32(parg16->f3) ) );
+ /*
+ ** Only update the 16 bit structure if the call returns success
+ */
+ if (!ul) {
+ PUTMIDIHDR16(parg16->f2, &midihdr);
+ }
+
+ trace_midi(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiInAddBuffer
+*
+* This function sends an input buffer to a specified opened MIDI input device.
+* When the buffer is filled, it is sent back to the application. Input buffers
+* are used only for system exclusive messages.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInAddBuffer(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PMIDIHDR32 pMidihdr32;
+ register PMIDIINADDBUFFER16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "midiInAddBuffer", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIINADDBUFFER16), parg16);
+
+ trace_midi(( "midiInAddBuffer( %x, %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** If the given size of the MIDIHDR structure is too small
+ ** or the lphdr is invalid return an error
+ **
+ */
+ if ( UINT32(parg16->f3) < sizeof(MIDIHDR16)
+ || HIWORD( DWORD32(parg16->f2) ) == 0 ) {
+
+ ul = (ULONG)MMSYSERR_INVALPARAM;
+ }
+ else {
+ if (pMidihdr32 = malloc_w(sizeof(MIDIHDR32) ) ) {
+
+ PMIDIHDR lpwhdr;
+#if DBG
+ AllocMidiCount++;
+ dprintf2(( "M>> %8X (%d)", pMidihdr32, AllocMidiCount ));
+#endif
+ /* Copy across the midi header stuff. Note that lpwhdr (a
+ ** 32 bit ptr to a 32 bit midi header) is used to make the
+ ** pointer stuff a bit less hairy.
+ **
+ ** pMidihdr32->Midihdr is a 32 bit midi header
+ ** pMidihdr32->pMidihdr16 is a 16 bit ptr to a 16 bit midi header
+ ** pMidihdr32->pMidihdr32 is a 32 bit ptr to a 16 bit midi header
+ */
+ lpwhdr = &(pMidihdr32->Midihdr);
+ pMidihdr32->pMidihdr16 = (PMIDIHDR16)DWORD32(parg16->f2);
+ pMidihdr32->pMidihdr32 = GETMIDIHDR16(DWORD32(parg16->f2), lpwhdr);
+
+ /*
+ ** GETMIDIHDR16 can return NULL, in which case we should set
+ ** lpwhdr to NULL too and call midiInAddBuffer only to get the
+ ** correct error code.
+ */
+ if ( pMidihdr32->pMidihdr32 == NULL ) {
+ lpwhdr = NULL;
+ }
+
+ ul = GETWORD16((*mmAPI)( HMIDIIN32(parg16->f1), lpwhdr,
+ UINT32(parg16->f3) ));
+ /*
+ ** If the call fails we need to free the memory we malloc'd
+ ** above, as the callback that would have freed it will never
+ ** get called.
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ /*
+ ** Make sure we reflect any changes that midiInAddBuffer did
+ ** to the MIDIHDR back to 16 bit land.
+ **
+ ** This is important because some apps poll the
+ ** MHDR_DONE bit !!
+ */
+ COPY_MIDIINHDR16_FLAGS( pMidihdr32->pMidihdr32,
+ pMidihdr32->Midihdr );
+ }
+ else {
+#if DBG
+ AllocMidiCount--;
+ dprintf2(( "M<< \t%8X (%d)", pMidihdr32,
+ AllocMidiCount ));
+#endif
+ free_w( pMidihdr32 );
+ }
+ }
+ else {
+ ul = (ULONG)MMSYSERR_NOMEM;
+ }
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiInStart
+*
+* This function starts MIDI input on the specified MIDI input device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInStart(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PMIDIINSTART16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "midiInStart", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIINSTART16), parg16);
+
+ trace_midi(( "midiInStart( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)(HMIDIIN32(parg16->f1) ) );
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiInStop
+*
+* This function terminates MIDI input on the specified MIDI input device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInStop(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PMIDIINSTOP16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "midiInStop", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIINSTOP16), parg16);
+
+ trace_midi(( "midiInStop( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)(HMIDIIN32(parg16->f1) ) );
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiInReset
+*
+* This function stops input on a given MIDI input device and marks all pending
+* input buffers as done.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInReset(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PMIDIINRESET16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "midiInReset", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIINRESET16), parg16);
+
+ trace_midi(( "midiInReset( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)(HMIDIIN32(parg16->f1) ) );
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiInGetID
+*
+* This function gets the device ID for a MIDI input device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInGetID(PVDMFRAME pFrame)
+{
+ register PMIDIINGETID16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ UINT dwDeviceID32;
+ LPWORD lpwDeviceID16;
+
+ GET_MULTIMEDIA_API( "midiInGetID", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIINGETID16), parg16);
+
+ trace_midi(( "midiInGetID( %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+
+ ul = GETWORD16((*mmAPI)( HMIDIIN32(parg16->f1), &dwDeviceID32 ));
+
+ /*
+ ** Only copy the ID back to 16 bit space if the call was sucessful
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ MMGETOPTPTR( parg16->f2, sizeof(WORD), lpwDeviceID16 );
+
+ if ( lpwDeviceID16 ) {
+ STOREWORD ( *lpwDeviceID16, dwDeviceID32 );
+ FLUSHVDMPTR( DWORD32(parg16->f2), sizeof(WORD), lpwDeviceID16 );
+ FREEVDMPTR ( lpwDeviceID16 );
+ }
+ else {
+ ul = MMSYSERR_INVALPARAM;
+ }
+ }
+ trace_midi(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32midiInMessage
+*
+* This function sends a message to the specified MIDI input device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32midiInMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PMIDIINMESSAGE3216 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "midiInMessage", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(MIDIINMESSAGE16), parg16);
+
+ trace_midi(( "midiInMessage( %x, %x, %x, %x )",
+ WORD32( parg16->f1 ), UINT32( parg16->f2 ),
+ DWORD32( parg16->f3 ), DWORD32( parg16->f4 ) ));
+
+ if ( (UINT32(parg16->f2) >= DRV_BUFFER_LOW)
+ && (UINT32(parg16->f2) <= DRV_BUFFER_HIGH) ) {
+
+ LPDWORD lpdwParam1;
+ GETMISCPTR(parg16->f3, lpdwParam1);
+
+ ul = GETDWORD16((*mmAPI)( HMIDIIN32(parg16->f1), UINT32(parg16->f2),
+ (DWORD)lpdwParam1, DWORD32(parg16->f4)));
+ FREEMISCPTR(lpdwParam1);
+
+ } else {
+ ul = GETDWORD16((*mmAPI)( HMIDIIN32(parg16->f1),
+ MAKELONG( WORD32(parg16->f2), 0xFFFF ),
+ DWORD32(parg16->f3), DWORD32(parg16->f4) ));
+ }
+
+ trace_midi(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/* ---------------------------------------------------------------------
+** WAVE Output API's
+** ---------------------------------------------------------------------
+*/
+
+/**********************************************************************\
+*
+* WMM32waveOutGetNumDevs
+*
+* This function retrieves the number of waveform output devices present in the
+* system.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutGetNumDevs(PVDMFRAME pFrame)
+{
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+
+ GET_MULTIMEDIA_API( "waveOutGetNumDevs", mmAPI, MMSYSERR_NODRIVER );
+
+ trace_wave(( "waveOutGetNumDevs()" ));
+ ul = GETWORD16((*mmAPI)() );
+ trace_wave(( "-> %ld\n", ul ));
+
+ RETURN(ul);
+
+ UNREFERENCED_PARAMETER(pFrame);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutGetDevCaps
+*
+* This function queries a specified waveform device to determine its
+* capabilities.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutGetDevCaps(PVDMFRAME pFrame)
+{
+ register PWAVEOUTGETDEVCAPS16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ WAVEOUTCAPS waveoutcaps;
+
+ GET_MULTIMEDIA_API( "waveOutGetDevCapsA", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTGETDEVCAPS16), parg16);
+
+ trace_wave(( "waveOutGetDevCaps( %x, %x, %x )", INT32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** If the size parameter was zero return straight away. Note that this
+ ** is not an error.
+ */
+ if ( UINT32( parg16->f3 ) == 0 ) {
+ ul = MMSYSERR_NOERROR;
+ }
+ else {
+
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), &waveoutcaps,
+ sizeof(WAVEOUTCAPS) ));
+ /*
+ ** Don't update the 16 bit structure if the call failed
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+ ul = PUTWAVEOUTCAPS16(parg16->f2, &waveoutcaps, UINT32(parg16->f3));
+ }
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutGetErrorText
+*
+* This function retrieves a textual description of the error identified by the
+* specified error number.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutGetErrorText(PVDMFRAME pFrame)
+{
+ register PWAVEOUTGETERRORTEXT16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul = MMSYSERR_NOERROR;
+ PSZ pszText;
+
+ GET_MULTIMEDIA_API( "waveOutGetErrorTextA", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTGETERRORTEXT16), parg16);
+
+ trace_wave(( "waveOutGetErrorText( %x, %x, %x )", UINT32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** Test against a zero length string and a NULL pointer. If 0 is passed
+ ** as the buffer length then the manual says we should return
+ ** MMSYSERR_NOERR. MMGETOPTPTR only returns a pointer if parg16->f2 is
+ ** not NULL.
+ */
+ MMGETOPTPTR( parg16->f2, UINT32(parg16->f3), pszText );
+ if ( pszText != NULL ) {
+
+ ul = GETWORD16( (*mmAPI)( UINT32(parg16->f1), pszText,
+ UINT32(parg16->f3) ) );
+
+ FLUSHVDMPTR( DWORD32(parg16->f2), UINT32(parg16->f3), pszText);
+ FREEVDMPTR(pszText);
+ }
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutOpen
+*
+* This function opens a specified waveform output device for playback.
+*
+* As of November 1992 we map the 16 bit Wave Format data directly to the
+* the 32 bit side, no thunking of the parameters is performed.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutOpen(PVDMFRAME pFrame)
+{
+ ULONG ul = MMSYSERR_NOERROR;
+ UINT uDevID;
+ PINSTANCEDATA pInstanceData = NULL;
+ DWORD dwFlags;
+ PWAVEFORMAT16 lpWaveformData;
+ LPHWAVEOUT lphWaveOut = NULL; // pointer to handle in 16 bit app space
+ HWAVEOUT Hand32; // 32bit handle
+ register PWAVEOUTOPEN16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveOutOpen", mmAPI, MMSYSERR_NODRIVER );
+
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTOPEN16), parg16);
+
+ trace_wave(( "waveOutOpen( %x, %x, %x, %x, %x, %x )",
+ DWORD32( parg16->f1 ), INT32 ( parg16->f2 ),
+ DWORD32( parg16->f3 ), DWORD32( parg16->f4 ),
+ DWORD32( parg16->f5 ), DWORD32( parg16->f6 ) ));
+
+ /*
+ ** Get the device ID. We use INT32 here not UINT32 to make sure that
+ ** negative values (such as WAVE_MAPPER (-1)) get thunked correctly.
+ ** Also, get the flags to be used.
+ */
+ uDevID = (UINT)INT32(parg16->f2);
+ dwFlags = DWORD32(parg16->f6);
+
+
+ /*
+ ** Get a pointer to the WAVEFORMAT structure. Because the format of this
+ ** structure is exactly the same in 32 and 16 bit land I will use
+ ** GETMISCPTR to get a generic pointer to the data. The stuff being
+ ** pointed to could be full of unaligned WORDs, but the 32 bit code
+ ** would have to cope with this anyway.
+ */
+ GETMISCPTR( parg16->f3, lpWaveformData );
+ if ( lpWaveformData == (PWAVEFORMAT16)NULL ) {
+ ul = (ULONG)MMSYSERR_INVALPARAM;
+ goto exit_function;
+ }
+
+
+ /*
+ ** We don't need a callback routine when the WAVE_FORMAT_QUERY flag
+ ** is specified.
+ */
+ if ( !(dwFlags & WAVE_FORMAT_QUERY) ) {
+
+ /*
+ ** Map the 16 bit pointer is one was specified.
+ */
+ MMGETOPTPTR( parg16->f1, sizeof(HWAVEOUT), lphWaveOut );
+ if ( lphWaveOut == NULL ) {
+
+ ul = MMSYSERR_INVALPARAM;
+ }
+
+ /*
+ ** Create InstanceData block to be used by our callback routine.
+ **
+ ** NOTE: Although we malloc it here we don't free it.
+ ** This is not a mistake - it must not be freed before the
+ ** callback routine has used it - so it does the freeing.
+ **
+ ** If the malloc fails we bomb down to the bottom,
+ ** set ul to MMSYSERR_NOMEM and exit gracefully.
+ **
+ ** We always have a callback functions. This is to ensure that
+ ** the WAVEHDR structure keeps getting copied back from
+ ** 32 bit space to 16 bit, as it contains flags which
+ ** applications are liable to keep checking.
+ */
+ else if ( pInstanceData = malloc_w(sizeof(INSTANCEDATA) ) ) {
+
+ DWORD dwNewFlags = CALLBACK_FUNCTION;
+
+ dprintf2(( "WM32waveOutOpen: Allocated instance buffer at %8X",
+ pInstanceData ));
+ pInstanceData->dwCallback = DWORD32(parg16->f4);;
+ pInstanceData->dwCallbackInstance = DWORD32(parg16->f5);
+ pInstanceData->dwFlags = dwFlags;
+
+ dwNewFlags |= (dwFlags & WAVE_ALLOWSYNC);
+
+ ul = GETWORD16((*mmAPI)( &Hand32, uDevID,
+ (LPWAVEFORMAT)lpWaveformData,
+ (DWORD)W32CommonDeviceOpen,
+ (DWORD)pInstanceData, dwNewFlags ));
+ /*
+ ** If the call returns success update the 16 bit handle,
+ ** otherwise don't, and free the memory we malloc'd earlier, as
+ ** the callback that would have freed it will never get callled.
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ HWAVEOUT16 Hand16 = GETHWAVEOUT16(Hand32);
+
+ trace_wave(( "Handle -> %x", Hand16 ));
+
+ STOREWORD ( *lphWaveOut, Hand16);
+ FLUSHVDMPTR( DWORD32(parg16->f1), sizeof(HWAVEOUT),
+ lphWaveOut );
+ }
+ else {
+
+ dprintf2(( "WM32waveOutOpen: Freeing instance buffer at %8X",
+ pInstanceData ));
+ free_w(pInstanceData);
+ }
+
+ /*
+ ** Regardless of sucess or failure we need to free the pointer
+ ** to the 16 bit WaveOut handle.
+ */
+ FREEVDMPTR ( lphWaveOut );
+ }
+ else {
+ ul = (ULONG)MMSYSERR_NOMEM;
+ }
+ }
+ else {
+ ul = GETWORD16((*mmAPI)( NULL, uDevID, (LPWAVEFORMAT)lpWaveformData,
+ DWORD32(parg16->f4), DWORD32(parg16->f5),
+ dwFlags ));
+ }
+
+ /*
+ ** Regardless of sucess or failure we need to free the pointer to the
+ ** 16 bit WaveFormatData.
+ */
+ FREEMISCPTR( lpWaveformData );
+
+
+exit_function:
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutClose
+*
+* This function closes the specified waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutClose(PVDMFRAME pFrame)
+{
+ register PWAVEOUTCLOSE16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+
+ GET_MULTIMEDIA_API( "waveOutClose", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTCLOSE16), parg16);
+
+ trace_wave(( "waveOutClose( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutPrepareHeader
+*
+* This function prepares the specified waveform header.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutPrepareHeader(PVDMFRAME pFrame)
+{
+ register PWAVEOUTPREPAREHEADER3216 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ WAVEHDR wavehdr;
+
+
+ GET_MULTIMEDIA_API( "waveOutPrepareHeader", mmAPI, MMSYSERR_NODRIVER );
+ GETARGPTR(pFrame, sizeof(WAVEOUTPREPAREHEADER3216), parg16);
+ trace_wave(( "waveOutPrepareHeader( %x %x %x)", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), WORD32( parg16->f3 ) ));
+
+ GETWAVEHDR16(parg16->f2, &wavehdr);
+
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1),
+ &wavehdr, WORD32(parg16->f3) ) );
+ /*
+ ** Only update the 16 bit structure if the call returns success
+ **
+ */
+ if ( !ul ) {
+ PUTWAVEHDR16(parg16->f2, &wavehdr);
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutUnprepareHeader
+*
+* This function prepares the specified waveform header.
+* This function cleans up the preparation performed by waveOutPrepareHeader.
+* The function must be called after the device driver has finished with a
+* data block. You must call this function before freeing the data buffer.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutUnprepareHeader(PVDMFRAME pFrame)
+{
+ register PWAVEOUTUNPREPAREHEADER3216 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ WAVEHDR wavehdr;
+
+ GET_MULTIMEDIA_API( "waveOutUnprepareHeader", mmAPI, MMSYSERR_NODRIVER );
+ GETARGPTR(pFrame, sizeof(WAVEOUTUNPREPAREHEADER3216), parg16);
+ trace_wave(( "waveOutUnprepareHeader( %x %x %x)", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), WORD32( parg16->f3 ) ));
+
+ GETWAVEHDR16(parg16->f2, &wavehdr);
+
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1),
+ &wavehdr, WORD32(parg16->f3) ) );
+ /*
+ ** Only update the 16 bit structure if the call returns success
+ */
+ if (!ul) {
+ PUTWAVEHDR16(parg16->f2, &wavehdr);
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutWrite
+*
+* This function sends a data block to the specified waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutWrite(PVDMFRAME pFrame)
+{
+ register PWAVEOUTWRITE16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ PWAVEHDR32 pWavehdr32;
+
+ GET_MULTIMEDIA_API( "waveOutWrite", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTWRITE16), parg16);
+
+ trace_wave(( "waveOutWrite( %x, %x, %x)", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** If the given size of the WAVEHDR structure is too small
+ ** or the lphdr is invalid return an error
+ **
+ */
+ if ( UINT32(parg16->f3) < sizeof(WAVEHDR16)
+ || HIWORD( DWORD32(parg16->f2) ) == 0 ) {
+
+ ul = (ULONG)MMSYSERR_INVALPARAM;
+ }
+ else {
+
+ if ( pWavehdr32 = malloc_w( sizeof(WAVEHDR32) ) ) {
+
+ PWAVEHDR lpwhdr; /* used to simplify ptr stuff later on */
+#if DBG
+ AllocWaveCount++;
+ dprintf2(( "W>> %8X (%d)", pWavehdr32, AllocWaveCount ));
+#endif
+
+ /* Copy across the wave header stuff. Note that lpwhdr (a
+ ** 32 bit ptr to a 32 bit wave header) is used to make the
+ ** pointer stuff a bit less hairy.
+ **
+ ** pWavehdr32->Wavehdr is a 32 bit wave header
+ ** pWavehdr32->pWavehdr16 is a 16 bit ptr to a 16 bit wave header
+ ** pWavehdr32->pWavehdr32 is a 32 bit ptr to a 16 bit wave header
+ */
+ lpwhdr = &(pWavehdr32->Wavehdr);
+ pWavehdr32->pWavehdr16 = (PWAVEHDR16)DWORD32(parg16->f2);
+ pWavehdr32->pWavehdr32 = GETWAVEHDR16(DWORD32(parg16->f2), lpwhdr);
+
+ /*
+ ** GETWAVEHDR16 can return NULL, in which case we should set
+ ** lpwhdr to NULL too and call waveOutWrite only to get the
+ ** correct error code.
+ */
+ if ( pWavehdr32->pWavehdr32 == NULL ) {
+ lpwhdr = NULL;
+ }
+
+ ul = GETWORD16( (*mmAPI)( HWAVEOUT32(parg16->f1),
+ lpwhdr, UINT32(parg16->f3) ) );
+
+ /* If the call fails we need to free the memory we malloc'd
+ ** above, as the callback that would have freed it will never
+ ** get called.
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ /* Make sure we reflect any changes that waveOutWrite did
+ ** to the WAVEHDR back to 16 bit land.
+ **
+ ** This is important because some apps (waveedit) poll the
+ ** WHDR_DONE bit !!
+ */
+ COPY_WAVEOUTHDR16_FLAGS( pWavehdr32->pWavehdr32,
+ pWavehdr32->Wavehdr );
+ }
+ else {
+#if DBG
+ AllocWaveCount--;
+ dprintf2(( "W<< \t%8X (%d)", pWavehdr32,
+ AllocWaveCount ));
+#endif
+ free_w( pWavehdr32 );
+ }
+ }
+ else {
+ ul = (ULONG)MMSYSERR_NOMEM;
+ }
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutPause
+*
+* This function pauses playback on a specified waveform output device. The
+* current playback position is saved. Use wavOutRestart to resume playback from
+* the current playback position.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutPause(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEOUTPAUSE16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveOutPause", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTPAUSE16), parg16);
+
+ trace_wave(( "waveOutGetPause( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutRestart
+*
+* This function restarts a paused waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutRestart(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEOUTRESTART16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveOutRestart", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTRESTART16), parg16);
+
+ trace_wave(( "waveOutRestart( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutReset
+*
+* This function stops playback on a given waveform output device and resets the
+* current position to 0. All pending playback buffers are marked as done and
+* returned to the application.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutReset(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEOUTRESET16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveOutReset", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTRESET16), parg16);
+
+ trace_wave(( "waveOutReset( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16( (*mmAPI)( HWAVEOUT32(parg16->f1) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutGetPosition
+*
+* This function retrieves the current palyback position of the specified
+* waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutGetPosition(PVDMFRAME pFrame)
+{
+ register PWAVEOUTGETPOSITION16 parg16;
+ static FARPROC mmAPI = NULL;
+ MMTIME mmtime;
+ ULONG ul = MMSYSERR_INVALPARAM;
+
+ GET_MULTIMEDIA_API( "waveOutGetPosition", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTGETPOSITION16), parg16);
+
+ trace_wave(( "waveOutGetPosition( %x, %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** If the given size of the MMTIME structure is too small return an error
+ **
+ ** There is a problem here on MIPS. For some reason the MIPS
+ ** compiler thinks a MMTIME16 structure is 10 bytes big. We
+ ** have a pragma in wowmmed.h to align this structure on byte
+ ** boundaries therefore I guess this is a compiler bug!
+ **
+ ** If the input structure is not large enough we return immediately
+ */
+
+#ifdef MIPS_COMPILER_PACKING_BUG
+ if ( UINT32(parg16->f3) >= 8 ) {
+#else
+ if ( UINT32(parg16->f3) >= sizeof(MMTIME16) ) {
+#endif
+
+ ul = GETMMTIME16( parg16->f2, &mmtime);
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1),
+ &mmtime, sizeof(MMTIME) ));
+ /*
+ ** Only update the 16 bit structure if the call returns success
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+ ul = PUTMMTIME16( parg16->f2, &mmtime);
+ }
+ }
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/**********************************************************************\
+*
+* WMM32waveOutGetPitch
+*
+* This function queries the current pitch setting of a waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutGetPitch(PVDMFRAME pFrame)
+{
+ register PWAVEOUTGETPITCH16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul = MMSYSERR_INVALPARAM;
+ LPDWORD lpdwPitch;
+ DWORD dwPitch;
+
+ GET_MULTIMEDIA_API( "waveOutGetPitch", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTGETPITCH16), parg16);
+ trace_wave(( "waveOutGetPitch( %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1), &dwPitch ));
+
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ MMGETOPTPTR( parg16->f2, sizeof(DWORD), lpdwPitch);
+
+ if ( lpdwPitch ) {
+ STOREDWORD ( *lpdwPitch, dwPitch );
+ FLUSHVDMPTR( DWORD32(parg16->f2), sizeof(DWORD), lpdwPitch );
+ FREEVDMPTR ( lpdwPitch );
+ }
+ else {
+ ul = MMSYSERR_INVALPARAM;
+ }
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutSetPitch
+*
+* This function sets the pitch of a waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutSetPitch(PVDMFRAME pFrame)
+{
+ register PWAVEOUTSETPITCH16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+
+ GET_MULTIMEDIA_API( "waveOutSetPitch", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTSETPITCH16), parg16);
+ trace_wave(( "waveOutSetPitch( %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1), DWORD32(parg16->f2) ));
+
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutGetVolume
+*
+* This function queries the current volume setting of a waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutGetVolume(PVDMFRAME pFrame)
+{
+ register PWAVEOUTGETVOLUME16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ LPDWORD lpdwVolume;
+ DWORD dwVolume;
+
+ GET_MULTIMEDIA_API( "waveOutGetVolume", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTGETVOLUME16), parg16);
+
+ trace_wave(( "waveOutGetVolume( %x, %x )", INT32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), &dwVolume ));
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ MMGETOPTPTR( parg16->f2, sizeof(DWORD), lpdwVolume);
+
+ if ( lpdwVolume ) {
+ STOREDWORD ( *lpdwVolume, dwVolume );
+ FLUSHVDMPTR( DWORD32(parg16->f2), sizeof(DWORD), lpdwVolume );
+ FREEVDMPTR ( lpdwVolume );
+ }
+ else {
+ ul = MMSYSERR_INVALPARAM;
+ }
+ }
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutSetVolume
+*
+* This function sets the volume of a waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutSetVolume(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEOUTSETVOLUME16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveOutSetVolume", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTSETVOLUME16), parg16);
+
+ trace_wave(( "waveOutSetVolume( %x, %x )", INT32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+ ul = GETWORD16((*mmAPI)( INT32(parg16->f1), DWORD32(parg16->f2) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutGetPlaybackRate
+*
+* This function queries the current playback rate setting of a waveform output
+* device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutGetPlaybackRate(PVDMFRAME pFrame)
+{
+ register PWAVEOUTGETPLAYBACKRATE16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ LPDWORD lpdwRate;
+ DWORD dwRate;
+
+ GET_MULTIMEDIA_API( "waveOutGetPlaybackRate", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTGETPLAYBACKRATE16), parg16);
+ trace_wave(( "waveOutGetPlaybackRate( %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1), &dwRate ));
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ MMGETOPTPTR( parg16->f2, sizeof(DWORD), lpdwRate );
+
+ if ( lpdwRate ) {
+
+ STOREDWORD ( *lpdwRate, dwRate );
+ FLUSHVDMPTR( DWORD32(parg16->f2), sizeof(DWORD), lpdwRate );
+ FREEVDMPTR ( lpdwRate );
+ }
+ }
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutSetPlaybackRate
+*
+* This function sets the playback rate of a waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutSetPlaybackRate(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEOUTSETPLAYBACKRATE16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveOutSetPlaybackRate", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTSETPLAYBACKRATE16), parg16);
+
+ trace_wave(( "waveOutSetPlaybackRate( %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1), DWORD32(parg16->f2) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/**********************************************************************\
+*
+* WMM32waveOutBreakLoop
+*
+* This function breaks a loop on a given waveform output device and allows
+* playback to continue with the next block in the driver list.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutBreakLoop(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEOUTBREAKLOOP16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveOutBreakLoop", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTBREAKLOOP16), parg16);
+
+ trace_wave(( "waveOutBreakLoop( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutGetID
+*
+* This function gets the device ID for a waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutGetID(PVDMFRAME pFrame)
+{
+ register PWAVEOUTGETID16 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ UINT dwDeviceID32;
+ LPWORD lpwDeviceID16;
+
+ GET_MULTIMEDIA_API( "waveOutGetID", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTGETID16), parg16);
+
+ trace_wave(( "waveOutGetID( %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+
+ ul = GETWORD16((*mmAPI)( HWAVEOUT32(parg16->f1), &dwDeviceID32 ));
+
+ /*
+ ** Only copy the ID back to 16 bit space if the call was sucessful
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ MMGETOPTPTR( parg16->f2, sizeof(WORD), lpwDeviceID16 );
+
+ if ( lpwDeviceID16 ) {
+ STOREWORD ( *lpwDeviceID16, dwDeviceID32 );
+ FLUSHVDMPTR( DWORD32(parg16->f2), sizeof(WORD), lpwDeviceID16 );
+ FREEVDMPTR ( lpwDeviceID16 );
+ }
+ else {
+ ul = MMSYSERR_INVALPARAM;
+ }
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveOutMessage
+*
+* This function send a message to a waveform output device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveOutMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEOUTMESSAGE3216 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveOutMessage", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEOUTMESSAGE16), parg16);
+
+ trace_wave(( "waveOutMessage( %x, %x, %x, %x )",
+ WORD32( parg16->f1 ), UINT32( parg16->f2 ),
+ DWORD32( parg16->f3 ), DWORD32( parg16->f4 ) ));
+
+ if ( (UINT32(parg16->f2) >= DRV_BUFFER_LOW)
+ && (UINT32(parg16->f2) <= DRV_BUFFER_HIGH) ) {
+
+ LPDWORD lpdwParam1;
+ GETMISCPTR(parg16->f3, lpdwParam1);
+
+ ul = GETDWORD16((*mmAPI)( HWAVEOUT32(parg16->f1), UINT32(parg16->f2),
+ (DWORD)lpdwParam1, DWORD32(parg16->f4) ));
+ FREEMISCPTR(lpdwParam1);
+
+ } else {
+ ul = GETDWORD16((*mmAPI)( HWAVEOUT32(parg16->f1),
+ MAKELONG( WORD32(parg16->f2), 0xFFFF ),
+ DWORD32(parg16->f3), DWORD32(parg16->f4) ));
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/* ---------------------------------------------------------------------
+** WAVE Input API's
+** ---------------------------------------------------------------------
+*/
+
+/**********************************************************************\
+*
+* WMM32waveInGetNumDevs
+*
+* This function returns the number of waveform input devices.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInGetNumDevs(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInGetNumDevs", mmAPI, MMSYSERR_NODRIVER );
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ trace_wave(( "waveInGetNumDevs()" ));
+ ul = GETWORD16((*mmAPI)() );
+ trace_wave(( "-> %ld\n", ul ));
+
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInGetDevCaps
+*
+* This function queries a specified waveform input device to determine its
+* capabilities.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInGetDevCaps(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ WAVEINCAPS waveincaps1;
+ register PWAVEINGETDEVCAPS16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInGetDevCapsA", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINGETDEVCAPS16), parg16);
+
+ trace_wave(( "waveInGetDevCaps( %x, %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** If the size parameter was zero return straight away. Note that this
+ ** is not an error.
+ */
+ if ( UINT32( parg16->f3 ) == 0 ) {
+ ul = MMSYSERR_NOERROR;
+ }
+ else {
+
+ ul = GETWORD16((*mmAPI)(INT32(parg16->f1), &waveincaps1,
+ sizeof(WAVEINCAPS) ) );
+ /*
+ ** Don't update the 16 bit structure if the call failed
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+ ul = PUTWAVEINCAPS16(parg16->f2, &waveincaps1, UINT32(parg16->f3));
+ }
+ }
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInGetErrorText
+*
+* This function retrieves a textual description of the error identified by the
+* specified error number.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInGetErrorText(PVDMFRAME pFrame)
+{
+ ULONG ul = MMSYSERR_NOERROR;
+ PSZ pszText;
+ register PWAVEINGETERRORTEXT16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInGetErrorTextA", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINGETERRORTEXT16), parg16);
+
+ trace_wave(( "waveInGetErrorText( %x, %x, %x )", UINT32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** Test against a zero length string and a NULL pointer. If 0 is passed
+ ** as the buffer length then the manual says we should return
+ ** MMSYSERR_NOERR. MMGETOPTPTR only returns a pointer if parg16->f2 is
+ ** not NULL.
+ */
+ MMGETOPTPTR( parg16->f2, UINT32(parg16->f3), pszText );
+ if ( pszText != NULL ) {
+
+ ul = GETWORD16((*mmAPI)( UINT32(parg16->f1), pszText,
+ UINT32(parg16->f3) ));
+
+ FLUSHVDMPTR( DWORD32(parg16->f2), UINT32(parg16->f3), pszText);
+ FREEVDMPTR(pszText);
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInOpen
+*
+* This function opens a specified waveform input device for recording.
+*
+* As of November 1992 we map the 16 bit Wave Format data directly to the
+* the 32 bit side, no thunking of the parameters is performed.
+*
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInOpen(PVDMFRAME pFrame)
+{
+ ULONG ul=0;
+ UINT uDevID;
+ PINSTANCEDATA pInstanceData = NULL;
+ DWORD dwFlags;
+ PWAVEFORMAT16 lpWaveformData;
+ LPHWAVEIN lphWaveIn; // pointer to handle in 16 bit app space
+ HWAVEIN Hand32; // 32bit handle
+ register PWAVEINOPEN16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInOpen", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINOPEN16), parg16);
+
+ trace_wave(( "waveInOpen( %x, %x, %x, %x, %x, %x )",
+ DWORD32( parg16->f1 ), INT32 ( parg16->f2 ),
+ DWORD32( parg16->f3 ), DWORD32( parg16->f4 ),
+ DWORD32( parg16->f5 ), DWORD32( parg16->f6 ) ));
+
+ /*
+ ** Get the device ID. We use INT32 here not UINT32 to make sure that
+ ** negative values (such as WAVE_MAPPER (-1)) get thunked correctly.
+ */
+ uDevID = (UINT)INT32(parg16->f2);
+
+ /*
+ ** Get the flags to be used.
+ */
+ dwFlags = DWORD32(parg16->f6);
+
+ /*
+ ** Get a pointer to the WAVEFORMAT structure. Because the format of this
+ ** structure is exactly the same in 32 and 16 bit land I will use
+ ** GETMISCPTR to get a generic pointer to the data. The stuff being
+ ** pointed to could be full of unaligned WORDs, but the 32 bit code
+ ** would have to cope with this anyway.
+ */
+ GETMISCPTR( DWORD32(parg16->f3), lpWaveformData );
+ if ( lpWaveformData == (PWAVEFORMAT16)NULL ) {
+ ul = (ULONG)MMSYSERR_INVALPARAM;
+ goto exit_function;
+ }
+
+ /*
+ ** We don't need a callback routine when the WAVE_FORMAT_QUERY flag
+ ** is specified.
+ */
+ if ( !( dwFlags & WAVE_FORMAT_QUERY ) ) {
+
+ /*
+ ** Map the 16 bit pointer is one was specified.
+ */
+ MMGETOPTPTR( parg16->f1, sizeof(HWAVEIN), lphWaveIn );
+ if ( lphWaveIn == NULL ) {
+
+ ul = MMSYSERR_INVALPARAM;
+ }
+
+ /*
+ ** Create InstanceData block to be used by our callback routine.
+ **
+ ** NOTE: Although we malloc it here we don't free it.
+ ** This is not a mistake - it must not be freed before the
+ ** callback routine has used it - so it does the freeing.
+ **
+ ** If the malloc fails we bomb down to the bottom,
+ ** set ul to MMSYSERR_NOMEM and exit gracefully.
+ **
+ ** We always have a callback functions. This is to ensure that
+ ** the WAVEHDR structure keeps getting copied back from
+ ** 32 bit space to 16 bit, as it contains flags which
+ ** applications are liable to keep checking.
+ */
+ else if ( pInstanceData = malloc_w(sizeof(INSTANCEDATA) ) ) {
+
+ DWORD dwNewFlags = CALLBACK_FUNCTION;
+
+ dprintf2(( "WM32waveInOpen: Allocated instance buffer at %8X",
+ pInstanceData ));
+ pInstanceData->dwCallback = DWORD32(parg16->f4);;
+ pInstanceData->dwCallbackInstance = DWORD32(parg16->f5);
+ pInstanceData->dwFlags = dwFlags;
+
+ dwNewFlags |= (dwFlags & WAVE_ALLOWSYNC);
+
+ ul = GETWORD16( (*mmAPI)( &Hand32, uDevID,
+ (LPWAVEFORMAT)lpWaveformData,
+ (DWORD)W32CommonDeviceOpen,
+ (DWORD)pInstanceData, dwNewFlags ) );
+ /*
+ ** If the call returns success update the 16 bit handle,
+ ** otherwise don't, and free the memory we malloc'd earlier, as
+ ** the callback that would have freed it will never get callled.
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ HWAVEIN16 Hand16 = GETHWAVEIN16(Hand32);
+
+ trace_wave(( "Handle -> %x", Hand16 ));
+ STOREWORD ( *lphWaveIn, Hand16 );
+ FLUSHVDMPTR( DWORD32(parg16->f1), sizeof(HWAVEIN), lphWaveIn );
+ }
+ else {
+
+ free_w(pInstanceData);
+ }
+
+ /*
+ ** Regardless of sucess or failure we need to free the pointer
+ ** to the 16 bit WaveIn handle.
+ */
+ FREEVDMPTR ( lphWaveIn );
+ }
+ else {
+ ul = (ULONG)MMSYSERR_NOMEM;
+ }
+ }
+ else {
+
+ ul = GETWORD16( (*mmAPI)( NULL, uDevID, (LPWAVEFORMAT)lpWaveformData,
+ DWORD32(parg16->f4),
+ DWORD32(parg16->f5), dwFlags) );
+ }
+
+ /*
+ ** Regardless of sucess or failure we need to free the pointer to the
+ ** 16 bit WaveFormatData.
+ */
+ FREEMISCPTR( lpWaveformData );
+
+
+exit_function:
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInClose
+*
+* This function closes the specified waveform input device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInClose(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEINCLOSE16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInClose", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINCLOSE16), parg16);
+
+ trace_wave(( "waveInClose( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)( HWAVEIN32(parg16->f1) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/**********************************************************************\
+*
+* WMM32waveInPrepareHeader
+*
+* This function prepares the specified waveform header.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInPrepareHeader(PVDMFRAME pFrame)
+{
+ register PWAVEINPREPAREHEADER3216 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ WAVEHDR wavehdr;
+
+
+ GET_MULTIMEDIA_API( "waveInPrepareHeader", mmAPI, MMSYSERR_NODRIVER );
+ GETARGPTR(pFrame, sizeof(WAVEINPREPAREHEADER3216), parg16);
+ trace_wave(( "waveInPrepareHeader( %x %x %x)", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), WORD32( parg16->f3 ) ));
+
+ GETWAVEHDR16(parg16->f2, &wavehdr);
+
+ ul = GETWORD16((*mmAPI)( HWAVEIN32(parg16->f1),
+ &wavehdr, WORD32(parg16->f3) ) );
+ /*
+ ** Only update the 16 bit structure if the call returns success
+ **
+ */
+ if ( !ul ) {
+ PUTWAVEHDR16(parg16->f2, &wavehdr);
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInUnprepareHeader
+*
+* This function prepares the specified waveform header.
+* This function cleans up the preparation performed by waveInPrepareHeader.
+* The function must be called after the device driver has finished with a
+* data block. You must call this function before freeing the data buffer.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInUnprepareHeader(PVDMFRAME pFrame)
+{
+ register PWAVEINUNPREPAREHEADER3216 parg16;
+ static FARPROC mmAPI = NULL;
+ ULONG ul;
+ WAVEHDR wavehdr;
+
+ GET_MULTIMEDIA_API( "waveInUnprepareHeader", mmAPI, MMSYSERR_NODRIVER );
+ GETARGPTR(pFrame, sizeof(WAVEINUNPREPAREHEADER3216), parg16);
+ trace_wave(( "waveInUnprepareHeader( %x %x %x)", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), WORD32( parg16->f3 ) ));
+
+ GETWAVEHDR16(parg16->f2, &wavehdr);
+
+ ul = GETWORD16((*mmAPI)( HWAVEIN32(parg16->f1),
+ &wavehdr, WORD32(parg16->f3) ) );
+ /*
+ ** Only update the 16 bit structure if the call returns success
+ */
+ if (!ul) {
+ PUTWAVEHDR16(parg16->f2, &wavehdr);
+ }
+
+ trace_wave(( "-> %ld\n", ul ));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInAddBuffer
+*
+* This function sends an input buffer to a waveform input device.
+* When the buffer is filled it is sent back to the application.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInAddBuffer(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PWAVEHDR32 pWavehdr32;
+ register PWAVEINADDBUFFER16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInAddBuffer", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINADDBUFFER16), parg16);
+
+ trace_wave(( "waveInAddBuffer( %x, %x, %x)", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** If the given size of the WAVEHDR structure is too small
+ ** or the lphdr is invalid return an error
+ **
+ */
+ if ( UINT32(parg16->f3) < sizeof(WAVEHDR16)
+ || HIWORD( DWORD32(parg16->f2) ) == 0 ) {
+
+ ul = (ULONG)MMSYSERR_INVALPARAM;
+ }
+ else {
+ if (pWavehdr32 = malloc_w(sizeof(WAVEHDR32) ) ) {
+
+ PWAVEHDR lpwhdr; /* used to simplify ptr stuff later on */
+#if DBG
+ AllocWaveCount++;
+ dprintf2(( "W>> %8X (%d)", pWavehdr32, AllocWaveCount ));
+#endif
+
+ /* Copy across the wave header stuff. Note that lpwhdr (a
+ ** 32 bit ptr to a 32 bit wave header) is used to make the
+ ** pointer stuff a bit less hairy.
+ **
+ ** pWavehdr32->Wavehdr is a 32 bit wave header
+ ** pWavehdr32->pWavehdr16 is a 16 bit ptr to a 16 bit wave header
+ ** pWavehdr32->pWavehdr32 is a 32 bit ptr to a 16 bit wave header
+ */
+ lpwhdr = &(pWavehdr32->Wavehdr);
+ pWavehdr32->pWavehdr16 = (PWAVEHDR16)DWORD32(parg16->f2);
+ pWavehdr32->pWavehdr32 = GETWAVEHDR16(DWORD32(parg16->f2), lpwhdr);
+
+ /*
+ ** GETWAVEHDR16 can return NULL, in which case we should set
+ ** lpwhdr to NULL too and call waveInAddBuffer only to get the
+ ** correct error code.
+ */
+ if ( pWavehdr32->pWavehdr32 == NULL ) {
+ lpwhdr = NULL;
+ }
+
+ ul = GETWORD16( (*mmAPI)( HWAVEIN32(parg16->f1),
+ lpwhdr, UINT32(parg16->f3) ) );
+ /*
+ ** If the call fails we need to free the memory we malloc'd
+ ** above, as the callback that would have freed it will never
+ ** get called.
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ /*
+ ** Make sure we reflect any changes that waveInAddBuffer did
+ ** to the WAVEHDR back to 16 bit land.
+ **
+ ** This is important because some apps (waveedit) poll the
+ ** WHDR_DONE bit !!
+ */
+ COPY_WAVEINHDR16_FLAGS( pWavehdr32->pWavehdr32,
+ pWavehdr32->Wavehdr );
+ }
+ else {
+#if DBG
+ AllocWaveCount--;
+ dprintf2(( "W<< \t%8X (%d)", pWavehdr32,
+ AllocWaveCount ));
+#endif
+ free_w( pWavehdr32 );
+ }
+ }
+ else {
+ ul = (ULONG)MMSYSERR_NOMEM;
+ }
+ }
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInStart
+*
+* This function starts input on the specified waveform input device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInStart(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEINSTART16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInStart", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINSTART16), parg16);
+
+ trace_wave(( "waveInStart( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)( HWAVEIN32(parg16->f1) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInStop
+*
+* This function stops waveform input.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInStop(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEINSTOP16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInStop", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINSTOP16), parg16);
+
+ trace_wave(( "waveInStop( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)( HWAVEIN32(parg16->f1) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInReset
+*
+* This function stops input on a given waveform input device and resets the
+* current position to 0. All pending buffers are marked as done and returned
+* to the application.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInReset(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEINRESET16 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInReset", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINRESET16), parg16);
+
+ trace_wave(( "waveInReset( %x )", WORD32( parg16->f1 ) ));
+ ul = GETWORD16((*mmAPI)( HWAVEIN32(parg16->f1) ));
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInGetPosition
+*
+* This function retrieves the current input position of the specified waveform
+* input device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInGetPosition(PVDMFRAME pFrame)
+{
+ register PWAVEINGETPOSITION16 parg16;
+ MMTIME mmtime;
+ ULONG ul = MMSYSERR_INVALPARAM;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInGetPosition", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINGETPOSITION16), parg16);
+
+ trace_wave(( "waveInGetPosition( %x, %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ), UINT32( parg16->f3 ) ));
+
+ /*
+ ** If the given size of the MMTIME structure is too small return an error
+ **
+ ** There is a problem here on MIPS. For some reason the MIPS
+ ** compiler thinks a MMTIME16 structure is 10 bytes big. We
+ ** have a pragma in wowmmed.h to align this structure on byte
+ ** boundaries therefore I guess this is a compiler bug!
+ **
+ ** If the input structure is not large enough we return immediately
+ */
+#ifdef MIPS_COMPILER_PACKING_BUG
+ if ( UINT32(parg16->f3) >= 8 ) {
+#else
+ if ( UINT32(parg16->f3) >= sizeof(MMTIME16) ) {
+#endif
+
+ ul = GETMMTIME16( parg16->f2, &mmtime );
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ ul = GETWORD16((*mmAPI)( HWAVEIN32(parg16->f1),
+ &mmtime, sizeof(MMTIME) ));
+ /*
+ ** Only update the 16 bit structure if the call returns success
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+ ul = PUTMMTIME16( parg16->f2, &mmtime );
+ }
+ }
+ }
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInGetID
+*
+* This function gets the device ID for a waveform input device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInGetID(PVDMFRAME pFrame)
+{
+ register PWAVEINGETID16 parg16;
+ ULONG ul;
+ UINT dwDeviceID32;
+ LPWORD lpwDeviceID16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInGetID", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINGETID16), parg16);
+ trace_wave(( "waveInGetID( %x, %x )", WORD32( parg16->f1 ),
+ DWORD32( parg16->f2 ) ));
+
+ ul = GETWORD16((*mmAPI)( HWAVEIN32(parg16->f1), &dwDeviceID32 ));
+
+ /*
+ ** Only copy the ID back to 16 bit space if the call was sucessful
+ **
+ */
+ if ( ul == MMSYSERR_NOERROR ) {
+
+ MMGETOPTPTR( parg16->f2, sizeof(WORD), lpwDeviceID16 );
+
+ if ( lpwDeviceID16 ) {
+ STOREWORD ( *lpwDeviceID16, dwDeviceID32 );
+ FLUSHVDMPTR( DWORD32(parg16->f2), sizeof(WORD), lpwDeviceID16 );
+ FREEVDMPTR ( lpwDeviceID16 );
+ }
+ else {
+ ul = MMSYSERR_INVALPARAM;
+ }
+ }
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* WMM32waveInMessage
+*
+* This function sends a message to a waveform input device.
+*
+\**********************************************************************/
+ULONG FASTCALL WMM32waveInMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWAVEINMESSAGE3216 parg16;
+ static FARPROC mmAPI = NULL;
+
+ GET_MULTIMEDIA_API( "waveInMessage", mmAPI, MMSYSERR_NODRIVER );
+
+ GETARGPTR(pFrame, sizeof(WAVEINMESSAGE16), parg16);
+
+
+ trace_wave(( "waveInMessage( %x, %x, %x, %x )", WORD32( parg16->f1 ),
+ UINT32( parg16->f2 ), DWORD32( parg16->f3 ),
+ DWORD32( parg16->f4 ) ));
+
+ if ( (UINT32(parg16->f2) >= DRV_BUFFER_LOW)
+ && (UINT32(parg16->f2) <= DRV_BUFFER_HIGH) ) {
+
+ LPDWORD lpdwParam1;
+ GETMISCPTR(parg16->f3, lpdwParam1);
+
+ ul = GETDWORD16((*mmAPI)( HWAVEIN32(parg16->f1), UINT32(parg16->f2),
+ (DWORD)lpdwParam1, DWORD32(parg16->f4) ));
+ FREEMISCPTR(lpdwParam1);
+
+ } else {
+ ul = GETDWORD16((*mmAPI)( HWAVEIN32(parg16->f1),
+ MAKELONG( WORD32(parg16->f2), 0xFFFF ),
+ DWORD32(parg16->f3), DWORD32(parg16->f4) ));
+ }
+ trace_wave(( "-> %ld\n", ul ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/**********************************************************************\
+*
+* W32CommonDeviceOpen
+*
+* This routine is the callback which is ALWAYS called by wave and midi
+* functions. This is done to ensure that the XXXXHDR structure keeps
+* getting copied back from 32 bit space to 16 bit, as it contains flags
+* which the application is liable to keep checking.
+*
+* The way this whole business works is that the wave/midi data stays in 16
+* bit space, but the XXXXHDR is copied to the 32 bit side, with the
+* address of the data thunked accordingly so that Robin's device driver
+* can still get at the data but we don't have the performance penalty of
+* copying it back and forth all the time, not least because it is liable
+* to be rather large...
+*
+* It also handles the tidying up of memory which is reserved to store
+* the XXXXHDR, and the instance data (HWND/Callback address; instance
+* data; flags) which the xxxxOpen calls pass to this routine, enabling
+* it to forward messages or call callback as required.
+*
+* This routine handles all the messages that get sent from Robin's
+* driver, and in fact thunks them back to the correct 16 bit form. In
+* theory there should be no MM_ format messages from the 16 bit side, so
+* I can zap 'em out of WMSG16. However the 32 bit side should thunk the
+* mesages correctly and forward them to the 16 bit side and thence to
+* the app.
+*
+* However... I discover that somewhere in the system the wParam Msg
+* parameter (which is 32 bits in Win32 and 16 bits in Win16) is having
+* the top 16 bits trashed (zeroed actually). As I pass a 32 bit handle
+* in it, to be thunked in WMDISP32 back to a 16 bit handle, the loss of
+* the top 16 bits is not conducive to correct thunking. Soooo, no more
+* thunking in WMDISP32 - I do it all here and Post the correct 16 bit
+* message.
+*
+* Hence WMTBL32 (the 32 bit message switch table) contains the
+* NoThunking entry for all the MM_ messages - I'll do 'em myself thank
+* you.
+*
+*
+* For the MM_WIM_DATA and MM_WOM_DONE message dwParam1 points to the
+* following data struture.
+*
+* P32HDR is a 32 bit pointer to the original 16 bit header
+* P16HDR is a 16 bit far pointer to the original 16 bit header
+*
+* If we need to refernece the original header we must do via the
+* P32HDR pointer.
+*
+* +---------+
+* | P32HDR +----->+---------+
+* +---------+ | 16 bit |
+* | P16HDR +----->| | This is the original
+* dwParam1 ----->+---------+ | Wave | wave header passed to
+* | 32 bit | | Header | us by the Win 16 app.
+* This is the 32 | | | |
+* bit wave | Wave | +---------+
+* header that we | Header |
+* thunked at | |
+* earlier. +---------+
+*
+*
+* We must ensure that the 32 bit structure is completely hidden from the
+* 16 bit application, ie. the 16 bit app only see's the wave header that it
+* passed to us earlier.
+*
+*
+* NOTE: dwParam2 is junk
+*
+*
+\**********************************************************************/
+VOID W32CommonDeviceOpen( HANDLE handle, UINT uMsg, DWORD dwInstance,
+ DWORD dwParam1, DWORD dwParam2 )
+{
+ PWAVEHDR32 pWavehdr32;
+ PMIDIHDR32 pMidihdr32;
+ PINSTANCEDATA pInstanceData;
+ WORD Handle;
+
+
+ switch (uMsg) {
+
+ /* ------------------------------------------------------------
+ ** MIDI INPUT MESSAGES
+ ** ------------------------------------------------------------
+ */
+
+ case MM_MIM_LONGDATA:
+ /*
+ ** This message is sent to a window when an input buffer has been
+ ** filled with MIDI system-exclusive data and is being returned to
+ ** the application.
+ */
+
+ case MM_MIM_LONGERROR:
+ /*
+ ** This message is sent to a window when an invalid MIDI
+ ** system-exclusive message is received.
+ */
+ pMidihdr32 = (PMIDIHDR32)( (PBYTE)dwParam1 - (sizeof(PMIDIHDR16) * 2) );
+ WOW32ASSERT( pMidihdr32 );
+ COPY_MIDIINHDR16_FLAGS( pMidihdr32->pMidihdr32, pMidihdr32->Midihdr );
+ dwParam1 = (DWORD)pMidihdr32->pMidihdr16;
+
+
+ case MM_MIM_DATA:
+ /*
+ ** This message is sent to a window when a MIDI message is
+ ** received by a MIDI input device.
+ */
+
+ case MM_MIM_ERROR:
+ /*
+ ** This message is sent to a window when an invalid MIDI message
+ ** is received.
+ */
+
+ case MM_MIM_OPEN:
+ /*
+ ** This message is sent to a window when a MIDI input device is opened.
+ ** We process this message the same way as MM_MIM_CLOSE (see below)
+ */
+
+ case MM_MIM_CLOSE:
+ /*
+ ** This message is sent to a window when a MIDI input device is
+ ** closed. The device handle is no longer valid once this message
+ ** has been sent.
+ */
+ Handle = GETHMIDIIN16(handle);
+ break;
+
+
+
+ /* ------------------------------------------------------------
+ ** MIDI OUTPUT MESSAGES
+ ** ------------------------------------------------------------
+ */
+
+ case MM_MOM_DONE:
+ /*
+ ** This message is sent to a window when the specified
+ ** system-exclusive buffer has been played and is being returned to
+ ** the application.
+ */
+ pMidihdr32 = (PMIDIHDR32)( (PBYTE)dwParam1 - (sizeof(PMIDIHDR16) * 2) );
+ WOW32ASSERT( pMidihdr32 );
+ COPY_MIDIOUTHDR16_FLAGS( pMidihdr32->pMidihdr32, pMidihdr32->Midihdr );
+ dwParam1 = (DWORD)pMidihdr32->pMidihdr16;
+
+
+ case MM_MOM_OPEN:
+ /*
+ ** This message is sent to a window when a MIDI output device is opened.
+ ** We process this message the same way as MM_MOM_CLOSE (see below)
+ */
+
+ case MM_MOM_CLOSE:
+ /*
+ ** This message is sent to a window when a MIDI output device is
+ ** closed. The device handle is no longer valid once this message
+ ** has been sent.
+ */
+ Handle = GETHMIDIOUT16(handle);
+ break;
+
+
+
+ /* ------------------------------------------------------------
+ ** WAVE INPUT MESSAGES
+ ** ------------------------------------------------------------
+ */
+
+ case MM_WIM_DATA:
+ /*
+ ** This message is sent to a window when waveform data is present
+ ** in the input buffer and the buffer is being returned to the
+ ** application. The message can be sent either when the buffer
+ ** is full, or after the waveInReset function is called.
+ */
+ pWavehdr32 = (PWAVEHDR32)( (PBYTE)dwParam1 - (sizeof(PWAVEHDR16) * 2));
+ WOW32ASSERT( pWavehdr32 );
+ COPY_WAVEINHDR16_FLAGS( pWavehdr32->pWavehdr32, pWavehdr32->Wavehdr );
+ dwParam1 = (DWORD)pWavehdr32->pWavehdr16;
+
+ case MM_WIM_OPEN:
+ /*
+ ** This message is sent to a window when a waveform input
+ ** device is opened.
+ **
+ ** We process this message the same way as MM_WIM_CLOSE (see below)
+ */
+
+ case MM_WIM_CLOSE:
+ /*
+ ** This message is sent to a window when a waveform input device is
+ ** closed. The device handle is no longer valid once the message has
+ ** been sent.
+ */
+ Handle = GETHWAVEIN16(handle);
+ break;
+
+
+
+ /* ------------------------------------------------------------
+ ** WAVE OUTPUT MESSAGES
+ ** ------------------------------------------------------------
+ */
+
+ case MM_WOM_DONE:
+ /*
+ ** This message is sent to a window when the specified output
+ ** buffer is being returned to the application. Buffers are returned
+ ** to the application when they have been played, or as the result of
+ ** a call to waveOutReset.
+ */
+ pWavehdr32 = (PWAVEHDR32)( (PBYTE)dwParam1 - (sizeof(PWAVEHDR16) * 2));
+ WOW32ASSERT( pWavehdr32 );
+ COPY_WAVEOUTHDR16_FLAGS( pWavehdr32->pWavehdr32, pWavehdr32->Wavehdr );
+ dwParam1 = (DWORD)pWavehdr32->pWavehdr16;
+
+ case MM_WOM_OPEN:
+ /*
+ ** This message is sent to a window when a waveform output device
+ ** is opened.
+ **
+ ** We process this message the same way as MM_WOM_CLOSE (see below)
+ */
+
+ case MM_WOM_CLOSE:
+ /*
+ ** This message is sent to a window when a waveform output device
+ ** is closed. The device handle is no longer valid once the
+ ** message has been sent.
+ */
+ Handle = GETHWAVEOUT16(handle);
+ break;
+
+#if DBG
+ default:
+ dprintf(( "Unknown message received in CallBack function " ));
+ dprintf(( "best call StephenE or MikeTri" ));
+ return;
+#endif
+
+ }
+
+
+ /*
+ ** Now make the CallBack, or PostMessage call depending
+ ** on the flags passed to original (wave|midi)(In|Out)Open call.
+ */
+ pInstanceData = (PINSTANCEDATA)dwInstance;
+ WOW32ASSERT( pInstanceData );
+
+ switch (pInstanceData->dwFlags & CALLBACK_TYPEMASK) {
+
+ case CALLBACK_WINDOW:
+ dprintf2(( "WINDOW callback identified" ));
+ PostMessage( HWND32( LOWORD(pInstanceData->dwCallback) ),
+ uMsg, Handle, dwParam1 );
+ break;
+
+
+ case CALLBACK_TASK:
+ case CALLBACK_FUNCTION: {
+
+ DWORD dwFlags;
+
+ if ( (pInstanceData->dwFlags & CALLBACK_TYPEMASK) == CALLBACK_TASK ) {
+ dprintf2(( "TASK callback identified" ));
+ dwFlags = DCB_TASK;
+ }
+ else {
+ dprintf2(( "FUNCTION callback identified" ));
+ dwFlags = DCB_FUNCTION;
+ }
+
+ WOW32DriverCallback( pInstanceData->dwCallback,
+ dwFlags,
+ Handle,
+ LOWORD( uMsg ),
+ pInstanceData->dwCallbackInstance,
+ dwParam1,
+ dwParam2 );
+
+ }
+ break;
+ }
+
+ /*
+ ** Now, free up any storage that was allocated during the waveOutOpen
+ ** and waveInOpen. This should only be freed during the MM_WOM_CLOSE or
+ ** MM_WIM_CLOSE message.
+ **
+ ** Also, free up any storage that was allocated during the waveOutWrite
+ ** and waveInAddBuffer call. This should only be freed during the
+ ** MM_WOM_DONE or MM_WIM_DATA message.
+ */
+ switch (uMsg) {
+
+ case MM_MIM_CLOSE:
+ case MM_MOM_CLOSE:
+ case MM_WIM_CLOSE:
+ case MM_WOM_CLOSE:
+ dprintf2(( "W32CommonDeviceOpen: Freeing device open buffer at %X",
+ pInstanceData ));
+ dprintf2(( "Alloc Midi count = %d", AllocMidiCount ));
+ dprintf2(( "Alloc Wave count = %d", AllocWaveCount ));
+ free_w( pInstanceData );
+ FREEHWAVEIN16( Handle );
+ break;
+
+ case MM_WIM_DATA:
+ case MM_WOM_DONE:
+# if DBG
+ AllocWaveCount--;
+ dprintf2(( "W<< \t%8X (%d)", pWavehdr32, AllocWaveCount ));
+# endif
+ free_w( pWavehdr32 );
+ break;
+
+ case MM_MIM_LONGDATA:
+ case MM_MIM_LONGERROR:
+ case MM_MOM_DONE:
+# if DBG
+ AllocMidiCount--;
+ dprintf2(( "M<< \t%8X (%d)", pMidihdr32, AllocMidiCount ));
+# endif
+ free_w( pMidihdr32 );
+ break;
+ }
+
+}
+
+#endif
diff --git a/private/mvdm/wow32/wmmstru1.c b/private/mvdm/wow32/wmmstru1.c
new file mode 100644
index 000000000..38a0158e1
--- /dev/null
+++ b/private/mvdm/wow32/wmmstru1.c
@@ -0,0 +1,1579 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMMSTRU1.C
+ * WOW32 16-bit MultiMedia structure conversion support
+ * Contains support for mciSendCommand Thunk message Parms.
+ * Also contains some debug support functions.
+ *
+ * History:
+ * Created 14-Jul-1992 by Stephen Estrop (stephene)
+ *
+--*/
+
+//
+// We define NO_STRICT so that the compiler doesn't moan and groan when
+// I use the FARPROC type for the Multi-Media api loading.
+//
+#define NO_STRICT
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if 0
+
+MODNAME(wmmstru1.c);
+
+#if DBG
+int mmDebugLevel = -1;
+
+MCI_MESSAGE_NAMES mciMessageNames[32] = {
+ { MCI_OPEN, "MCI_OPEN" },
+ { MCI_CLOSE, "MCI_CLOSE" },
+ { MCI_ESCAPE, "MCI_ESCAPE" },
+ { MCI_PLAY, "MCI_PLAY" },
+ { MCI_SEEK, "MCI_SEEK" },
+ { MCI_STOP, "MCI_STOP" },
+ { MCI_PAUSE, "MCI_PAUSE" },
+ { MCI_INFO, "MCI_INFO" },
+ { MCI_GETDEVCAPS, "MCI_GETDEVCAPS" },
+ { MCI_SPIN, "MCI_SPIN" },
+ { MCI_SET, "MCI_SET" },
+ { MCI_STEP, "MCI_STEP" },
+ { MCI_RECORD, "MCI_RECORD" },
+ { MCI_SYSINFO, "MCI_SYSINFO" },
+ { MCI_BREAK, "MCI_BREAK" },
+ { MCI_SOUND, "MCI_SOUND" },
+ { MCI_SAVE, "MCI_SAVE" },
+ { MCI_STATUS, "MCI_STATUS" },
+ { MCI_CUE, "MCI_CUE" },
+ { MCI_REALIZE, "MCI_REALIZE" },
+ { MCI_WINDOW, "MCI_WINDOW" },
+ { MCI_PUT, "MCI_PUT" },
+ { MCI_WHERE, "MCI_WHERE" },
+ { MCI_FREEZE, "MCI_FREEZE" },
+ { MCI_UNFREEZE, "MCI_UNFREEZE" },
+ { MCI_LOAD, "MCI_LOAD" },
+ { MCI_CUT, "MCI_CUT" },
+ { MCI_COPY, "MCI_COPY" },
+ { MCI_PASTE, "MCI_PASTE" },
+ { MCI_UPDATE, "MCI_UPDATE" },
+ { MCI_RESUME, "MCI_RESUME" },
+ { MCI_DELETE, "MCI_DELETE" }
+};
+#endif
+
+//
+// The following are required for the dynamic linking of Multi-Media code
+// from within WOW. They are all defined in wmmedia.c
+//
+
+extern FARPROC mmAPIEatCmdEntry;
+extern FARPROC mmAPIGetParamSize;
+extern FARPROC mmAPISendCmdW;
+extern FINDCMDITEM mmAPIFindCmdItem;
+
+/**********************************************************************\
+*
+* ThunkMciCommand16
+*
+* This function converts a 16 bit mci command request into an
+* equiverlant 32 bit request.
+*
+* The ideas behind this function were stolen from ThunkWMMsg16,
+* see wmsg16.c and mciDebugOut see mci.c
+*
+* We return 0 if the thunk was OK, any other value should be used as
+* an error code. If the thunk failed all allocated resources will
+* be freed by this function. If the thunk was sucessful (ie. returned 0)
+* UnThunkMciCommand16 MUST be called to free allocated resources.
+*
+* Here are the assumptions that I have used to perform the thunking:
+*
+* 1. MCI_OPEN is a special case.
+*
+* 2. If the message is NOT defined in mmsystem.h then it is treated as a
+* "user" command. If a user command table is associated with the given
+* device ID we use this command table as an aid to perform the thunking.
+* If a user command table is NOT associated with the device ID the
+* command does NOT GET THUNKED, we return straight away, calling
+* mciSendCommand only to get a relevant error code.
+*
+* 3. If the command IS defined in mmsystem.h we perfrom a "manual" thunk
+* of the command IF the associated PARMS structure contains ReservedX
+* fields. We mask out the associated flags as each field is thunked.
+*
+* 4. If there are any flags left then we use the command table
+* as an aid to perform the thunking.
+*
+\**********************************************************************/
+INT ThunkMciCommand16( MCIDEVICEID DeviceID, UINT OrigCommand, DWORD OrigFlags,
+ DWORD OrigParms, PDWORD pNewParms, LPWSTR *lplpCommand,
+ PUINT puTable )
+{
+
+
+#if DBG
+ register int i;
+ int n;
+
+ dprintf3(( "ThunkMciCommand16 :" ));
+ dprintf5(( " OrigDevice -> %lX", DeviceID ));
+
+ n = sizeof(mciMessageNames) / sizeof(MCI_MESSAGE_NAMES);
+ for ( i = 0; i < n; i++ ) {
+ if ( mciMessageNames[i].uMsg == OrigCommand ) {
+ break;
+ }
+ }
+ dprintf3(( "OrigCommand -> 0x%lX", (DWORD)OrigCommand ));
+
+ //
+ // Special case MCI_STATUS. I get loads of these from mplayer.
+ // I only want to display MCI_STATUS messages if the debug level is
+ // set to level 3, that way I won't get swamped with them.
+ //
+ if ( mciMessageNames[i].uMsg != MCI_STATUS ) {
+ if ( i != n ) {
+ dprintf2(( "Command Name -> %s", mciMessageNames[i].lpstMsgName ));
+ }
+ else {
+ dprintf2(( "Command Name -> UNKNOWN COMMAND (%x)", OrigCommand ));
+ }
+ }
+ else {
+ dprintf3(( "Command Name -> MCI_STATUS" ));
+ }
+
+ dprintf5(( "OrigFlags -> 0x%lX", OrigFlags ));
+ dprintf5(( "OrigParms -> 0x%lX", OrigParms ));
+#endif
+
+ //
+ // Get some storage for the Mci parameter block, and handle the
+ // notify window handle (if supplied).
+ //
+
+ if ( (*pNewParms = AllocMciParmBlock( &OrigFlags, OrigParms )) == 0L ) {
+ return MCIERR_OUT_OF_MEMORY;
+ }
+
+ //
+ // We thunk the MCI_OPEN command and all other commands that contain a
+ // "ReservedX" field in their PARMS structure here. We mask out each
+ // flag as it is processed, if any flags are left we use the command
+ // table to complete the thunk.
+ //
+ // The following commands have ReservedX fields:
+ // MCI_WINDOW
+ // MCI_SET
+ //
+ // This means that MOST COMMANDS GET THUNKED VIA THE COMMAND TABLE.
+ //
+ switch ( OrigCommand ) {
+
+ case MCI_OPEN:
+ //
+ // MCI_OPEN is a special case message that I don't
+ // how to deal with yet.
+ //
+ ThunkOpenCmd( &OrigFlags, OrigParms, *pNewParms );
+ return 0;
+
+ //
+ // The next four commands have Reserved padding fields
+ // these have to thunked manually.
+ //
+
+ case MCI_SET:
+ ThunkSetCmd( DeviceID, &OrigFlags, OrigParms, *pNewParms );
+ break;
+
+ case MCI_WINDOW:
+ ThunkWindowCmd( DeviceID, &OrigFlags, OrigParms, *pNewParms );
+ break;
+
+ //
+ // Have to special case this command because the command table
+ // is not correct.
+ //
+ case MCI_SETVIDEO:
+ ThunkSetVideoCmd( DeviceID, &OrigFlags, OrigParms, *pNewParms );
+ break;
+
+ //
+ // These two commands don't have any command extensions
+ // so we return immediately.
+ //
+ case MCI_SYSINFO:
+ ThunkSysInfoCmd( &OrigFlags, OrigParms, *pNewParms );
+ return 0;
+
+ case MCI_BREAK:
+ ThunkBreakCmd( &OrigFlags, OrigParms, *pNewParms );
+ return 0;
+ }
+
+ //
+ // Find the command table for the given command ID.
+ // We always load the command table this is because the command table is
+ // needed for UnThunking.
+ //
+ *lplpCommand = (*mmAPIFindCmdItem)( DeviceID, NULL, (LPWSTR)OrigCommand,
+ NULL, puTable );
+ //
+ // If the command table is not found we return straight away.
+ // Note that storage has been allocated for pNewParms and that the
+ // MCI_WAIT and MCI_NOTIFY flags have been thunked.
+ // We do not return an error here, but call mciSendCommand to
+ // let it determine a suitable error code, we must also call
+ // UnthunkMciCommand to free the allocated storage.
+ //
+ if ( *lplpCommand == NULL ) {
+ dprintf(( "Command table not found !!" ));
+ return 0;
+ }
+ dprintf4(( "Command table has been loaded -> 0x%lX", *lplpCommand ));
+
+ //
+ // If OrigFlags is not equal to 0 we still have work to do !
+ // Note that this will be true for the majority of cases.
+ //
+ if ( OrigFlags ) {
+
+ dprintf3(( "Thunking via command table" ));
+
+ //
+ // Now we thunk the command
+ //
+ return ThunkCommandViaTable( *lplpCommand, OrigFlags, OrigParms,
+ *pNewParms );
+ }
+
+ return 0;
+
+}
+
+/**********************************************************************\
+* AllocMciParmBlock
+*
+* Get some storage for the Mci parameter block. I always allocate
+* MCI_MAX_PARAM_SLOTS * DWORD amount as this allows for any command
+* extensions.
+*
+* As we know that the first dword field is a Window handle
+* this field is taken care of here. Also the MCI_WAIT flag is
+* masked out if it is set.
+*
+\**********************************************************************/
+DWORD AllocMciParmBlock( PDWORD pOrigFlags, DWORD OrigParms )
+{
+
+ LPMCI_GENERIC_PARMS lpGenParms;
+ PMCI_GENERIC_PARMS16 lpGenParmsOrig;
+
+ UINT AllocSize = sizeof(DWORD) * MCI_MAX_PARAM_SLOTS;
+
+ //
+ // Get, check and set the required storage.
+ //
+ lpGenParms = (LPMCI_GENERIC_PARMS)malloc_w( AllocSize );
+ if ( lpGenParms == NULL ) {
+ return 0L;
+ }
+ RtlZeroMemory( lpGenParms, AllocSize );
+ dprintf4(( "AllocMciParmBlock: Allocated storage -> 0x%lX", lpGenParms ));
+
+ //
+ // Look for the notify flag and thunk accordingly
+ //
+ if ( *pOrigFlags & MCI_NOTIFY ) {
+
+
+ GETVDMPTR( OrigParms, sizeof(MCI_GENERIC_PARMS16), lpGenParmsOrig );
+
+ dprintf4(( "AllocMciParmBlock: Got MCI_NOTIFY flag." ));
+
+ // Note FETCHWORD of a DWORD below, same as LOWORD(FETCHDWORD(dw)),
+ // only faster.
+ lpGenParms->dwCallback =
+ (DWORD)HWND32( FETCHWORD( lpGenParmsOrig->dwCallback ) );
+
+ FREEVDMPTR( lpGenParmsOrig );
+
+ *pOrigFlags ^= MCI_NOTIFY;
+ }
+
+ //
+ // If the MCI_WAIT flag is present, mask it out.
+ //
+ if ( *pOrigFlags & MCI_WAIT ) {
+ dprintf4(( "AllocMciParmBlock: Got MCI_WAIT flag." ));
+ *pOrigFlags ^= MCI_WAIT;
+ }
+
+ return (DWORD)lpGenParms;
+}
+
+/**********************************************************************\
+* ThunkOpenCmd
+*
+* Thunk the Open mci command parms.
+\**********************************************************************/
+DWORD ThunkOpenCmd( PDWORD pOrigFlags, DWORD OrigParms, DWORD pNewParms )
+{
+ //
+ // The purpose of this union is to aid the creation of a 32 bit
+ // Open Parms structure that is suitable for all known MCI devices.
+ //
+ typedef union {
+ MCI_OPEN_PARMS OpenParms;
+ MCI_WAVE_OPEN_PARMS OpenWaveParms;
+ MCI_ANIM_OPEN_PARMS OpenAnimParms; // Note: Animation and
+ MCI_OVLY_OPEN_PARMS OpenOvlyParms; // overlay parms are identical
+ } MCI_ALL_OPEN_PARMS, *PMCI_ALL_OPEN_PARMS;
+
+ //
+ // The following pointers will be used to point to
+ // the original 16-bit Parms structure.
+ //
+ PMCI_OPEN_PARMS16 lpOpenParms16;
+ PMCI_WAVE_OPEN_PARMS16 lpOpenWaveParms16;
+
+ //
+ // Note: MCI_ANIM_OPEN_PARMS16 and MCI_OVLY_OPEN_PARMS16 structures are
+ // identical.
+ //
+ PMCI_ANIM_OPEN_PARMS16 lpOpenAnimParms16;
+
+ //
+ // pOp will point to the 32 bit open Parms structure after
+ // we have finished all the thunking.
+ //
+ PMCI_ALL_OPEN_PARMS pOp = (PMCI_ALL_OPEN_PARMS)pNewParms;
+
+ //
+ // We first do the fields that are common to all open requests.
+ // Set up the VDM ptr for lpOpenParms16 to point to OrigParms
+ //
+ GETVDMPTR( OrigParms, sizeof(MCI_OPEN_PARMS16), lpOpenParms16 );
+
+ //
+ // Now scan our way thru all the known MCI_OPEN flags, thunking as
+ // necessary.
+ //
+ // Start at the Device Type field
+ //
+ if ( *pOrigFlags & MCI_OPEN_TYPE ) {
+ if ( *pOrigFlags & MCI_OPEN_TYPE_ID ) {
+
+ dprintf4(( "ThunkOpenCmd: Got MCI_OPEN_TYPE_ID flag." ));
+ pOp->OpenParms.lpstrDeviceType =
+ (LPSTR)( FETCHDWORD( lpOpenParms16->lpstrDeviceType ) );
+ dprintf5(( "lpstrDeviceType -> %ld", pOp->OpenParms.lpstrDeviceType ));
+
+ *pOrigFlags ^= (MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID);
+ }
+ else {
+ dprintf4(( "ThunkOpenCmd: Got MCI_OPEN_TYPE flag" ));
+ GETPSZPTR( lpOpenParms16->lpstrDeviceType,
+ pOp->OpenParms.lpstrDeviceType );
+ dprintf5(( "lpstrDeviceType -> %s", pOp->OpenParms.lpstrDeviceType ));
+ dprintf5(( "lpstrDeviceType -> 0x%lX", pOp->OpenParms.lpstrDeviceType ));
+
+ *pOrigFlags ^= MCI_OPEN_TYPE;
+ }
+ }
+
+ //
+ // Now do the Element Name field
+ //
+ if ( *pOrigFlags & MCI_OPEN_ELEMENT ) {
+ if ( *pOrigFlags & MCI_OPEN_ELEMENT_ID ) {
+
+ dprintf4(( "ThunkOpenCmd: Got MCI_OPEN_ELEMENT_ID flag" ));
+ pOp->OpenParms.lpstrElementName =
+ (LPSTR)( FETCHDWORD( lpOpenParms16->lpstrElementName ) );
+ dprintf5(( "lpstrElementName -> %ld", pOp->OpenParms.lpstrElementName ));
+
+ *pOrigFlags ^= (MCI_OPEN_ELEMENT | MCI_OPEN_ELEMENT_ID);
+ }
+ else {
+ dprintf4(( "ThunkOpenCmd: Got MCI_OPEN_ELEMENT flag" ));
+ GETPSZPTR( lpOpenParms16->lpstrElementName,
+ pOp->OpenParms.lpstrElementName );
+ dprintf5(( "lpstrElementName -> %s", pOp->OpenParms.lpstrElementName ));
+ dprintf5(( "lpstrElementName -> 0x%lX", pOp->OpenParms.lpstrElementName ));
+
+ *pOrigFlags ^= MCI_OPEN_ELEMENT;
+ }
+ }
+
+ //
+ // Now do the Alias Name field
+ //
+ if ( *pOrigFlags & MCI_OPEN_ALIAS ) {
+ dprintf4(( "ThunkOpenCmd: Got MCI_OPEN_ALIAS flag" ));
+ GETPSZPTR( lpOpenParms16->lpstrAlias, pOp->OpenParms.lpstrAlias );
+ dprintf5(( "lpstrAlias -> %s", pOp->OpenParms.lpstrAlias ));
+ dprintf5(( "lpstrAlias -> 0x%lX", pOp->OpenParms.lpstrAlias ));
+
+ *pOrigFlags ^= MCI_OPEN_ALIAS;
+ }
+
+ //
+ // Clear the MCI_OPEN_SHAREABLE flag if it is set
+ //
+ if ( *pOrigFlags & MCI_OPEN_SHAREABLE ) {
+ dprintf4(( "ThunkOpenCmd: Got MCI_OPEN_SHAREABLE flag." ));
+ *pOrigFlags ^= MCI_OPEN_SHAREABLE;
+ }
+
+ //
+ // Free the VDM pointer before returning
+ //
+ FREEVDMPTR( lpOpenParms16 );
+
+ //
+ // If we don't have any extended flags I can return now
+ //
+ if ( *pOrigFlags == 0 ) {
+ return (DWORD)pOp;
+ }
+
+ //
+ // If there are any flags left then these are intended for an extended
+ // form of MCI open. Three different forms are known, these being:
+ // MCI_ANIM_OPEN_PARMS
+ // MCI_OVLY_OPEN_PARMS
+ // MCI_WAVE_OPEN_PARMS
+ //
+ // If I could tell what sort of device I had I could thunk the
+ // extensions with no problems, but we don't have a device ID yet
+ // so I can't figure out what sort of device I have without parsing
+ // the parameters that I already know about.
+ //
+ // But, I am in luck; MCI_WAVE_OPEN_PARMS has one extended parameter
+ // dwBufferSeconds which has a MCI_WAVE_OPEN_BUFFER flag associated with
+ // it. This field is also a DWORD in the other two parms structures.
+ //
+
+ if ( *pOrigFlags & MCI_WAVE_OPEN_BUFFER ) {
+ //
+ // Set up the VDM ptr for lpOpenWaveParms16 to point to OrigParms
+ //
+ GETVDMPTR( OrigParms, sizeof(MCI_WAVE_OPEN_PARMS16),
+ lpOpenWaveParms16 );
+
+ dprintf4(( "ThunkOpenCmd: Got MCI_WAVE_OPEN_BUFFER flag." ));
+ pOp->OpenWaveParms.dwBufferSeconds =
+ FETCHDWORD( lpOpenWaveParms16->dwBufferSeconds );
+ dprintf5(( "dwBufferSeconds -> %ld", pOp->OpenWaveParms.dwBufferSeconds ));
+
+ //
+ // Free the VDM pointer before returning
+ //
+ FREEVDMPTR( lpOpenWaveParms16 );
+
+ *pOrigFlags ^= MCI_WAVE_OPEN_BUFFER;
+ }
+
+ //
+ // Now look for MCI_ANIM_OPEN_PARM and MCI_OVLY_OPEN_PARMS extensions.
+ //
+ if ( (*pOrigFlags & MCI_ANIM_OPEN_PARENT)
+ || (*pOrigFlags & MCI_ANIM_OPEN_WS) ) {
+
+ //
+ // Set up the VDM ptr for lpOpenAnimParms16 to point to OrigParms
+ //
+ GETVDMPTR( OrigParms, sizeof(MCI_ANIM_OPEN_PARMS16),
+ lpOpenAnimParms16 );
+
+ //
+ // Check MCI_ANIN_OPEN_PARENT flag, this also checks
+ // the MCI_OVLY_OPEN_PARENT flag too.
+ //
+ if ( *pOrigFlags & MCI_ANIM_OPEN_PARENT ) {
+ dprintf4(( "ThunkOpenCmd: Got MCI_Xxxx_OPEN_PARENT flag." ));
+ pOp->OpenAnimParms.hWndParent =
+ HWND32(FETCHWORD(lpOpenAnimParms16->hWndParent) );
+
+ *pOrigFlags ^= MCI_ANIM_OPEN_PARENT;
+ }
+
+ //
+ // Check MCI_ANIN_OPEN_WS flag, this also checks
+ // the MCI_OVLY_OPEN_WS flag too.
+ //
+ if ( *pOrigFlags & MCI_ANIM_OPEN_WS ) {
+ dprintf4(( "ThunkOpenCmd: Got MCI_Xxxx_OPEN_WS flag." ));
+ pOp->OpenAnimParms.dwStyle =
+ FETCHDWORD( lpOpenAnimParms16->dwStyle );
+ dprintf5(( "dwStyle -> %ld", pOp->OpenAnimParms.dwStyle ));
+
+ *pOrigFlags ^= MCI_ANIM_OPEN_WS;
+ }
+
+ //
+ // Free the VDM pointer before returning
+ //
+ FREEVDMPTR( lpOpenAnimParms16 );
+ }
+
+ //
+ // Check the MCI_ANIN_OPEN_NOSTATIC flag
+ //
+ if ( *pOrigFlags & MCI_ANIM_OPEN_NOSTATIC ) {
+ dprintf4(( "ThunkOpenCmd: Got MCI_ANIM_OPEN_NOSTATIC flag." ));
+ *pOrigFlags ^= MCI_ANIM_OPEN_NOSTATIC;
+ }
+
+ return (DWORD)pOp;
+}
+
+/**********************************************************************\
+* ThunkSetCmd
+*
+* Thunk the ThunkSetCmd mci command parms.
+*
+* The following are "basic" flags that all devices must support.
+* MCI_SET_AUDIO
+* MCI_SET_DOOR_CLOSED
+* MCI_SET_DOOR_OPEN
+* MCI_SET_TIME_FORMAT
+* MCI_SET_VIDEO
+* MCI_SET_ON
+* MCI_SET_OFF
+*
+* The following are "extended" flags that "sequencer" devices support.
+* MCI_SEQ_SET_MASTER
+* MCI_SEQ_SET_OFFSET
+* MCI_SEQ_SET_PORT
+* MCI_SEQ_SET_SLAVE
+* MCI_SEQ_SET_TEMPO
+*
+* The following are "extended" flags that "sequencer" devices support.
+* MCI_WAVE_INPUT
+* MCI_WAVE_OUTPUT
+* MCI_WAVE_SET_ANYINPUT
+* MCI_WAVE_SET_ANYOUTPUT
+* MCI_WAVE_SET_AVGBYTESPERSEC
+* MCI_WAVE_SET_BITSPERSAMPLES
+* MCI_WAVE_SET_BLOCKALIGN
+* MCI_WAVE_SET_CHANNELS
+* MCI_WAVE_SET_FORMAT_TAG
+* MCI_WAVE_SET_SAMPLESPERSEC
+*
+\**********************************************************************/
+DWORD ThunkSetCmd( MCIDEVICEID DeviceID, PDWORD pOrigFlags, DWORD OrigParms,
+ DWORD pNewParms )
+{
+ //
+ // This purpose of this union is to aid the creation of a 32 bit Set
+ // Parms structure that is suitable for all known MCI devices.
+ //
+ typedef union {
+ MCI_SET_PARMS SetParms;
+ MCI_WAVE_SET_PARMS SetWaveParms;
+ MCI_SEQ_SET_PARMS SetSeqParms;
+ } MCI_ALL_SET_PARMS, *PMCI_ALL_SET_PARMS;
+
+ //
+ // The following pointers will be used to point to the original
+ // 16-bit Parms structure.
+ //
+ PMCI_SET_PARMS16 lpSetParms16;
+ PMCI_WAVE_SET_PARMS16 lpSetWaveParms16;
+ PMCI_SEQ_SET_PARMS16 lpSetSeqParms16;
+
+ //
+ // pSet will point to the 32 bit Set Parms structure after
+ // we have finished all the thunking.
+ //
+ PMCI_ALL_SET_PARMS pSet = (PMCI_ALL_SET_PARMS)pNewParms;
+
+ //
+ // GetDevCaps is used to determine what sort of device are dealing
+ // with. We need this information to determine if we should use
+ // standard, wave or sequencer MCI_SET structure.
+ //
+ MCI_GETDEVCAPS_PARMS GetDevCaps;
+ DWORD dwRetVal;
+
+ //
+ // Set up the VDM ptr for lpSetParms16 to point to OrigParms
+ //
+ GETVDMPTR( OrigParms, sizeof(MCI_SET_PARMS16), lpSetParms16 );
+
+ //
+ // First do the fields that are common to all devices. Thunk the
+ // dwAudio field.
+ //
+ if ( *pOrigFlags & MCI_SET_AUDIO ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SET_AUDIO flag." ));
+ pSet->SetParms.dwAudio = FETCHDWORD( lpSetParms16->dwAudio );
+ dprintf5(( "dwAudio -> %ld", pSet->SetParms.dwAudio ));
+
+ *pOrigFlags ^= MCI_SET_AUDIO; // Mask out the flag
+ }
+
+ //
+ // Thunk the dwTimeFormat field.
+ //
+ if ( *pOrigFlags & MCI_SET_TIME_FORMAT ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SET_TIME_FORMAT flag." ));
+ pSet->SetParms.dwTimeFormat = FETCHDWORD( lpSetParms16->dwTimeFormat );
+ dprintf5(( "dwTimeFormat -> %ld", pSet->SetParms.dwTimeFormat ));
+
+ *pOrigFlags ^= MCI_SET_TIME_FORMAT; // Mask out the flag
+ }
+
+ //
+ // Mask out the MCI_SET_DOOR_CLOSED
+ //
+ if ( *pOrigFlags & MCI_SET_DOOR_CLOSED ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SET_DOOR_CLOSED flag." ));
+ *pOrigFlags ^= MCI_SET_DOOR_CLOSED; // Mask out the flag
+ }
+
+ //
+ // Mask out the MCI_SET_DOOR_OPEN
+ //
+ if ( *pOrigFlags & MCI_SET_DOOR_OPEN ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SET_DOOR_OPEN flag." ));
+ *pOrigFlags ^= MCI_SET_DOOR_OPEN; // Mask out the flag
+ }
+
+ //
+ // Mask out the MCI_SET_VIDEO
+ //
+ if ( *pOrigFlags & MCI_SET_VIDEO ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SET_VIDEO flag." ));
+ *pOrigFlags ^= MCI_SET_VIDEO; // Mask out the flag
+ }
+
+ //
+ // Mask out the MCI_SET_ON
+ //
+ if ( *pOrigFlags & MCI_SET_ON ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SET_ON flag." ));
+ *pOrigFlags ^= MCI_SET_ON; // Mask out the flag
+ }
+
+ //
+ // Mask out the MCI_SET_OFF
+ //
+ if ( *pOrigFlags & MCI_SET_OFF ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SET_OFF flag." ));
+ *pOrigFlags ^= MCI_SET_OFF; // Mask out the flag
+ }
+
+ //
+ // Free the VDM pointer as we have finished with it
+ //
+ FREEVDMPTR( lpSetParms16 );
+
+ //
+ // We have done all the standard flags. If there are any flags
+ // still set we must have an extended command.
+ //
+ if ( *pOrigFlags == 0 ) {
+ return (DWORD)pSet;
+ }
+
+ //
+ // Now we need to determine what type of device we are
+ // dealing with. We can do this by send an MCI_GETDEVCAPS
+ // command to the device. (We might as well use the Unicode
+ // version of mciSendCommand and avoid another thunk).
+ //
+ RtlZeroMemory( &GetDevCaps, sizeof(MCI_GETDEVCAPS_PARMS) );
+ GetDevCaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;
+ dwRetVal = (*mmAPISendCmdW)( DeviceID, MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM,
+ (DWORD)&GetDevCaps );
+
+ //
+ // What do we do if dwRetCode is not equal to 0 ? If this is the
+ // case it probably means that we have been given a duff device ID,
+ // anyway it is pointless to carry on with the thunk so I will clear
+ // the *pOrigFlags variable and return. This means that the 32 bit version
+ // of mciSendCommand will get called with only half the message thunked,
+ // but as there is probably already a problem with the device or
+ // the device ID is duff, mciSendCommand should be able to work out a
+ // suitable error code to return to the application.
+ //
+ if ( dwRetVal ) {
+ *pOrigFlags = 0;
+ return (DWORD)pSet;
+ }
+ switch ( GetDevCaps.dwReturn ) {
+ case MCI_DEVTYPE_WAVEFORM_AUDIO:
+ //
+ // Set up the VDM ptr for lpSetWaveParms16 to point to OrigParms
+ //
+ dprintf3(( "ThunkSetCmd: Got a WaveAudio device." ));
+ GETVDMPTR( OrigParms, sizeof(MCI_WAVE_SET_PARMS16),
+ lpSetWaveParms16 );
+ //
+ // Thunk the wInput field.
+ //
+ if ( *pOrigFlags & MCI_WAVE_INPUT ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_WAVE_INPUT flag." ));
+ pSet->SetWaveParms.wInput =
+ FETCHWORD( lpSetWaveParms16->wInput );
+ dprintf5(( "wInput -> %u", pSet->SetWaveParms.wInput ));
+ *pOrigFlags ^= MCI_WAVE_INPUT;
+ }
+
+ //
+ // Thunk the wOutput field.
+ //
+ if ( *pOrigFlags & MCI_WAVE_OUTPUT ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_WAVE_OUTPUT flag." ));
+ pSet->SetWaveParms.wOutput =
+ FETCHWORD( lpSetWaveParms16->wOutput );
+ dprintf5(( "wOutput -> %u", pSet->SetWaveParms.wOutput ));
+ *pOrigFlags ^= MCI_WAVE_OUTPUT;
+ }
+
+ //
+ // Thunk the wFormatTag field.
+ //
+ if ( *pOrigFlags & MCI_WAVE_SET_FORMATTAG ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_WAVE_SET_FORMATTAG flag." ));
+ pSet->SetWaveParms.wFormatTag =
+ FETCHWORD( lpSetWaveParms16->wFormatTag );
+ dprintf5(( "wFormatTag -> %u", pSet->SetWaveParms.wFormatTag ));
+ *pOrigFlags ^= MCI_WAVE_SET_FORMATTAG;
+ }
+
+ //
+ // Thunk the nChannels field.
+ //
+ if ( *pOrigFlags & MCI_WAVE_SET_CHANNELS ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_WAVE_SET_CHANNELS flag." ));
+ pSet->SetWaveParms.nChannels =
+ FETCHWORD( lpSetWaveParms16->nChannels );
+ dprintf5(( "nChannels -> %u", pSet->SetWaveParms.nChannels ));
+ *pOrigFlags ^= MCI_WAVE_SET_CHANNELS;
+ }
+
+ //
+ // Thunk the nSamplesPerSec field.
+ //
+ if ( *pOrigFlags & MCI_WAVE_SET_SAMPLESPERSEC ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_WAVE_SET_SAMPLESPERSEC flag." ));
+ pSet->SetWaveParms.nSamplesPerSec =
+ FETCHDWORD( lpSetWaveParms16->nSamplesPerSecond );
+ dprintf5(( "nSamplesPerSec -> %u", pSet->SetWaveParms.nSamplesPerSec ));
+ *pOrigFlags ^= MCI_WAVE_SET_SAMPLESPERSEC;
+ }
+
+ //
+ // Thunk the nAvgBytesPerSec field.
+ //
+ if ( *pOrigFlags & MCI_WAVE_SET_AVGBYTESPERSEC ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_WAVE_SET_AVGBYTESPERSEC flag." ));
+ pSet->SetWaveParms.nAvgBytesPerSec =
+ FETCHDWORD( lpSetWaveParms16->nAvgBytesPerSec );
+ dprintf5(( "nAvgBytesPerSec -> %u", pSet->SetWaveParms.nAvgBytesPerSec ));
+ *pOrigFlags ^= MCI_WAVE_SET_AVGBYTESPERSEC;
+ }
+
+ //
+ // Thunk the nBlockAlign field.
+ //
+ if ( *pOrigFlags & MCI_WAVE_SET_BLOCKALIGN ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_WAVE_SET_BLOCKALIGN flag." ));
+ pSet->SetWaveParms.nBlockAlign =
+ FETCHWORD( lpSetWaveParms16->nBlockAlign );
+ dprintf5(( "nBlockAlign -> %u", pSet->SetWaveParms.nBlockAlign ));
+ *pOrigFlags ^= MCI_WAVE_SET_BLOCKALIGN;
+ }
+
+ //
+ // Thunk the nBitsPerSample field.
+ //
+ if ( *pOrigFlags & MCI_WAVE_SET_BITSPERSAMPLE ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_WAVE_SET_BITSPERSAMPLE flag." ));
+ pSet->SetWaveParms.wBitsPerSample =
+ FETCHWORD( lpSetWaveParms16->wBitsPerSample );
+ dprintf5(( "wBitsPerSamples -> %u", pSet->SetWaveParms.wBitsPerSample ));
+ *pOrigFlags ^= MCI_WAVE_SET_BITSPERSAMPLE;
+ }
+
+ FREEVDMPTR( lpSetWaveParms16 );
+ break;
+
+ case MCI_DEVTYPE_SEQUENCER:
+ //
+ // Set up the VDM ptr for lpSetSeqParms16 to point to OrigParms
+ //
+ dprintf3(( "ThunkSetCmd: Got a Sequencer device." ));
+ GETVDMPTR( OrigParms, sizeof(MCI_WAVE_SET_PARMS16),
+ lpSetSeqParms16 );
+
+ //
+ // Thunk the dwMaster field.
+ //
+ if ( *pOrigFlags & MCI_SEQ_SET_MASTER ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SEQ_SET_MASTER flag." ));
+ pSet->SetSeqParms.dwMaster =
+ FETCHDWORD( lpSetSeqParms16->dwMaster );
+ dprintf5(( "dwMaster -> %ld", pSet->SetSeqParms.dwMaster ));
+ *pOrigFlags ^= MCI_SEQ_SET_MASTER;
+ }
+
+ //
+ // Thunk the dwPort field.
+ //
+ if ( *pOrigFlags & MCI_SEQ_SET_PORT ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SEQ_SET_PORT flag." ));
+ pSet->SetSeqParms.dwPort =
+ FETCHDWORD( lpSetSeqParms16->dwPort );
+ dprintf5(( "dwPort -> %ld", pSet->SetSeqParms.dwPort ));
+ *pOrigFlags ^= MCI_SEQ_SET_PORT;
+ }
+
+ //
+ // Thunk the dwOffset field.
+ //
+ if ( *pOrigFlags & MCI_SEQ_SET_OFFSET ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SEQ_SET_OFFSET flag." ));
+ pSet->SetSeqParms.dwOffset=
+ FETCHDWORD( lpSetSeqParms16->dwOffset );
+ dprintf5(( "dwOffset -> %ld", pSet->SetSeqParms.dwOffset ));
+ *pOrigFlags ^= MCI_SEQ_SET_OFFSET;
+ }
+
+ //
+ // Thunk the dwSlave field.
+ //
+ if ( *pOrigFlags & MCI_SEQ_SET_SLAVE ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SEQ_SET_SLAVE flag." ));
+ pSet->SetSeqParms.dwSlave =
+ FETCHDWORD( lpSetSeqParms16->dwSlave );
+ dprintf5(( "dwSlave -> %ld", pSet->SetSeqParms.dwSlave ));
+ *pOrigFlags ^= MCI_SEQ_SET_SLAVE;
+ }
+
+ //
+ // Thunk the dwTempo field.
+ //
+ if ( *pOrigFlags & MCI_SEQ_SET_TEMPO ) {
+ dprintf4(( "ThunkSetCmd: Got MCI_SEQ_SET_TEMPO flag." ));
+ pSet->SetSeqParms.dwTempo =
+ FETCHDWORD( lpSetSeqParms16->dwTempo );
+ dprintf5(( "dwTempo -> %ld", pSet->SetSeqParms.dwTempo ));
+ *pOrigFlags ^= MCI_SEQ_SET_TEMPO;
+ }
+
+ FREEVDMPTR( lpSetSeqParms16 );
+ break;
+ }
+
+ return (DWORD)pSet;
+}
+
+/**********************************************************************\
+* ThunkSetVideoCmd
+*
+* Thunk the SetVideo mci command parms.
+*
+\**********************************************************************/
+DWORD ThunkSetVideoCmd( MCIDEVICEID DeviceID, PDWORD pOrigFlags,
+ DWORD OrigParms, DWORD pNewParms )
+{
+
+ //
+ // The following pointers will be used to point to the original
+ // 16-bit Parms structure.
+ //
+ LPMCI_DGV_SETVIDEO_PARMS lpSetParms16;
+
+ //
+ // pSet will point to the 32 bit SetVideo Parms structure after
+ // we have finished all the thunking.
+ //
+ LPMCI_DGV_SETVIDEO_PARMS pSet = (LPMCI_DGV_SETVIDEO_PARMS)pNewParms;
+
+ //
+ // Set up the VDM ptr for lpSetParms16 to point to OrigParms
+ //
+ GETVDMPTR( OrigParms, sizeof(MCI_DGV_SETVIDEO_PARMS), lpSetParms16 );
+
+ if ( *pOrigFlags & MCI_DGV_SETVIDEO_ITEM ) {
+
+ dprintf4(( "ThunkSetVideoCmd: Got MCI_DGV_SETVIDEO_ITEM flag." ));
+ pSet->dwItem = FETCHDWORD( lpSetParms16->dwItem );
+ dprintf5(( "dwItem -> %ld", pSet->dwItem ));
+ *pOrigFlags ^= MCI_DGV_SETVIDEO_ITEM; // Mask out the flag
+ }
+
+ if ( *pOrigFlags & MCI_DGV_SETVIDEO_VALUE ) {
+
+ if ( pSet->dwItem == MCI_DGV_SETVIDEO_PALHANDLE ) {
+
+ HPAL16 hpal16;
+
+ dprintf4(( "ThunkSetVideoCmd: Got MCI_DGV_SETVIDEO_PALHANLE." ));
+
+ hpal16 = (HPAL16)LOWORD( FETCHDWORD( lpSetParms16->dwValue ) );
+ pSet->dwValue = (DWORD)HPALETTE32( hpal16 );
+ dprintf5(( "\t-> 0x%X", hpal16 ));
+
+ }
+ else {
+ dprintf4(( "ThunkSetVideoCmd: Got an MCI_INTEGER." ));
+ pSet->dwValue = FETCHDWORD( lpSetParms16->dwValue );
+ dprintf5(( "dwValue -> %ld", pSet->dwValue ));
+ }
+
+ *pOrigFlags ^= MCI_DGV_SETVIDEO_VALUE; // Mask out the flag
+ }
+
+ //
+ // Turn off the MCI_SET_ON FLAG.
+ //
+ if ( *pOrigFlags & MCI_SET_ON ) {
+ dprintf4(( "ThunkSetVideoCmd: Got MCI_SET_ON flag." ));
+ *pOrigFlags ^= MCI_SET_ON; // Mask out the flag
+ }
+
+ //
+ // Turn off the MCI_SET_OFF FLAG.
+ //
+ if ( *pOrigFlags & MCI_SET_OFF ) {
+ dprintf4(( "ThunkSetVideoCmd: Got MCI_SET_OFF flag." ));
+ *pOrigFlags ^= MCI_SET_OFF; // Mask out the flag
+ }
+
+ return (DWORD)pSet;
+}
+
+
+/**********************************************************************\
+* ThunkSysInfoCmd
+*
+* Thunk the SysInfo mci command parms.
+\**********************************************************************/
+DWORD ThunkSysInfoCmd( PDWORD pOrigFlags, DWORD OrigParms, DWORD pNewParms )
+{
+ //
+ // lpSysInfoParms16 points to the 16 bit parameter block
+ // passed to us by the WOW application.
+ //
+ PMCI_SYSINFO_PARMS16 lpSysInfoParms16;
+
+ //
+ // pSys will point to the 32 bit SysInfo Parms structure after
+ // we have finished all the thunking.
+ //
+ PMCI_SYSINFO_PARMS pSys = (PMCI_SYSINFO_PARMS)pNewParms;
+
+ //
+ // Set up the VDM ptr for lpSysInfoParms16 to point to OrigParms
+ //
+ GETVDMPTR( OrigParms, sizeof(MCI_SYSINFO_PARMS16), lpSysInfoParms16 );
+
+ //
+ // Thunk the dwRetSize, dwNumber and wDeviceType parameters.
+ //
+ pSys->dwRetSize = FETCHDWORD( lpSysInfoParms16->dwRetSize );
+ dprintf5(( "dwRetSize -> %ld", pSys->dwRetSize ));
+
+ pSys->dwNumber = FETCHDWORD( lpSysInfoParms16->dwNumber );
+ dprintf5(( "dwNumber -> %ld", pSys->dwNumber ));
+
+ pSys->wDeviceType = (DWORD)FETCHWORD( lpSysInfoParms16->wDeviceType );
+ dprintf5(( "wDeviceType -> %ld", pSys->wDeviceType ));
+
+ //
+ // Thunk lpstrReturn
+ //
+ if ( pSys->dwRetSize > 0 ) {
+ GETVDMPTR( lpSysInfoParms16->lpstrReturn, pSys->dwRetSize,
+ pSys->lpstrReturn );
+ dprintf5(( "lpstrReturn -> 0x%lX", lpSysInfoParms16->lpstrReturn ));
+ }
+ else {
+ dprintf1(( "ThunkSysInfoCmd: lpstrReturn is 0 bytes long !!!" ));
+
+ /* lpstrReturn has been set to NULL by RtlZeroMemory above */
+ }
+
+ //
+ // Free the VDM pointer as we have finished with it
+ //
+ FREEVDMPTR( lpSysInfoParms16 );
+ return (DWORD)pSys;
+
+}
+
+/**********************************************************************\
+* ThunkBreakCmd
+*
+* Thunk the Break mci command parms.
+\**********************************************************************/
+DWORD ThunkBreakCmd( PDWORD pOrigFlags, DWORD OrigParms, DWORD pNewParms )
+{
+ //
+ // lpBreakParms16 points to the 16 bit parameter block
+ // passed to us by the WOW application.
+ //
+ PMCI_BREAK_PARMS16 lpBreakParms16;
+
+ //
+ // pBrk will point to the 32 bit Break Parms structure after
+ // we have finished all the thunking.
+ //
+ PMCI_BREAK_PARMS pBrk = (PMCI_BREAK_PARMS)pNewParms;
+
+ //
+ // Set up the VDM ptr for lpBreakParms16 to point to OrigParms
+ //
+ GETVDMPTR( OrigParms, sizeof(MCI_BREAK_PARMS16), lpBreakParms16 );
+
+ //
+ // Check for the MCI_BREAK_KEY flag
+ //
+ if ( *pOrigFlags & MCI_BREAK_KEY ) {
+ dprintf4(( "ThunkBreakCmd: Got MCI_BREAK_KEY flag." ));
+ pBrk->nVirtKey = (int)FETCHWORD( lpBreakParms16->nVirtKey );
+ dprintf5(( "nVirtKey -> %d", pBrk->nVirtKey ));
+ }
+
+ //
+ // Check for the MCI_BREAK_HWND flag
+ //
+ if ( *pOrigFlags & MCI_BREAK_HWND ) {
+ dprintf4(( "ThunkBreakCmd: Got MCI_BREAK_HWND flag." ));
+ pBrk->hwndBreak = HWND32(FETCHWORD(lpBreakParms16->hwndBreak));
+ }
+
+ //
+ // Free the VDM pointer as we have finished with it
+ //
+ FREEVDMPTR( lpBreakParms16 );
+ return (DWORD)pBrk;
+
+}
+
+/**********************************************************************\
+* ThunkWindowCmd
+*
+* Thunk the mci Window command parms.
+\**********************************************************************/
+DWORD ThunkWindowCmd( MCIDEVICEID DeviceID, PDWORD pOrigFlags, DWORD OrigParms,
+ DWORD pNewParms )
+{
+ //
+ // lpAni will point to the 32 bit Anim Window Parms
+ // structure after we have finished all the thunking.
+ //
+ PMCI_ANIM_WINDOW_PARMS lpAni = (PMCI_ANIM_WINDOW_PARMS)pNewParms;
+
+ //
+ // lpAniParms16 point to the 16 bit parameter block
+ // passed to us by the WOW application.
+ //
+ PMCI_ANIM_WINDOW_PARMS16 lpAniParms16;
+
+ //
+ // GetDevCaps is used to determine what sort of device are dealing
+ // with. We need this information to determine if we should use
+ // overlay or animation MCI_WINDOW structure.
+ //
+ MCI_GETDEVCAPS_PARMS GetDevCaps;
+ DWORD dwRetVal;
+
+ //
+ // Now we need to determine what type of device we are
+ // dealing with. We can do this by send an MCI_GETDEVCAPS
+ // command to the device. (We might as well use the Unicode
+ // version of mciSendCommand and avoid another thunk).
+ //
+ RtlZeroMemory( &GetDevCaps, sizeof(MCI_GETDEVCAPS_PARMS) );
+ GetDevCaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;
+ dwRetVal = (*mmAPISendCmdW)( DeviceID, MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM,
+ (DWORD)&GetDevCaps );
+ //
+ // What do we do if dwRetCode is not equal to 0 ? If this is the
+ // case it probably means that we have been given a duff device ID,
+ // anyway it is pointless to carry on with the thunk so I will clear
+ // the *pOrigFlags variable and return. This means that the 32 bit version
+ // of mciSendCommand will get called with only half the message thunked,
+ // but as there is probably already a problem with the device or
+ // the device ID is duff, mciSendCommand should be able to work out a
+ // suitable error code to return to the application.
+ //
+ if ( dwRetVal ) {
+ *pOrigFlags = 0;
+ return pNewParms;
+ }
+
+ //
+ // Do we have an Animation or Overlay device type ?
+ // Because Animation and Overlay have identical flags and
+ // parms structures they can share the same code.
+ //
+ if ( GetDevCaps.dwReturn == MCI_DEVTYPE_ANIMATION
+ || GetDevCaps.dwReturn == MCI_DEVTYPE_OVERLAY
+ || GetDevCaps.dwReturn == MCI_DEVTYPE_DIGITAL_VIDEO ) {
+
+ //
+ // Set up the VDM ptr for lpWineParms16 to point to OrigParms
+ //
+ GETVDMPTR( OrigParms, sizeof(MCI_ANIM_WINDOW_PARMS16),
+ lpAniParms16 );
+
+ //
+ // Check for the MCI_ANIM_WINDOW_TEXT
+ //
+ if ( *pOrigFlags & MCI_ANIM_WINDOW_TEXT ) {
+ dprintf4(( "ThunkWindowCmd: Got MCI_Xxxx_WINDOW_TEXT flag." ));
+
+ GETPSZPTR( lpAniParms16->lpstrText, lpAni->lpstrText );
+
+ dprintf5(( "lpstrText -> %s", lpAni->lpstrText ));
+ dprintf5(( "lpstrText -> 0x%lX", lpAni->lpstrText ));
+ *pOrigFlags ^= MCI_ANIM_WINDOW_TEXT;
+
+ }
+
+ //
+ // Check for the MCI_ANIM_WINDOW_HWND flag
+ //
+ if ( *pOrigFlags & MCI_ANIM_WINDOW_HWND ) {
+ dprintf4(( "ThunkWindowCmd: Got MCI_Xxxx_WINDOW_HWND flag." ));
+ lpAni->hWnd = HWND32( FETCHWORD( lpAniParms16->hWnd ) );
+ dprintf5(( "hWnd -> 0x%lX", lpAni->hWnd ));
+ *pOrigFlags ^= MCI_ANIM_WINDOW_HWND;
+ }
+
+ //
+ // Check for the MCI_ANIM_WINDOW_STATE flag
+ //
+ if ( *pOrigFlags & MCI_ANIM_WINDOW_STATE ) {
+ dprintf4(( "ThunkWindowCmd: Got MCI_Xxxx_WINDOW_STATE flag." ));
+ lpAni->nCmdShow = FETCHWORD( lpAniParms16->nCmdShow );
+ dprintf5(( "nCmdShow -> 0x%lX", lpAni->nCmdShow ));
+ *pOrigFlags ^= MCI_ANIM_WINDOW_STATE;
+ }
+
+ //
+ // Check for the MCI_ANIM_WINDOW_DISABLE_STRETCH flag
+ //
+ if ( *pOrigFlags & MCI_ANIM_WINDOW_DISABLE_STRETCH ) {
+ dprintf4(( "ThunkWindowCmd: Got MCI_Xxxx_WINDOW_DISABLE_STRETCH flag." ));
+ *pOrigFlags ^= MCI_ANIM_WINDOW_DISABLE_STRETCH;
+ }
+
+ //
+ // Check for the MCI_ANIM_WINDOW_ENABLE_STRETCH flag
+ //
+ if ( *pOrigFlags & MCI_ANIM_WINDOW_ENABLE_STRETCH ) {
+ dprintf4(( "ThunkWindowCmd: Got MCI_Xxxx_WINDOW_ENABLE_STRETCH flag." ));
+ *pOrigFlags ^= MCI_ANIM_WINDOW_ENABLE_STRETCH;
+ }
+
+ //
+ // Free the VDM pointer as we have finished with it
+ //
+ FREEVDMPTR( lpAniParms16 );
+ return (DWORD)lpAni;
+
+ }
+
+ return pNewParms;
+}
+
+
+/**********************************************************************\
+* ThunkCommandViaTable
+*
+\**********************************************************************/
+INT ThunkCommandViaTable( LPWSTR lpCommand, DWORD dwFlags, DWORD OrigParms,
+ DWORD pNewParms )
+{
+
+#if DBG
+ static LPSTR f_name = "ThunkCommandViaTable: ";
+#endif
+
+ LPWSTR lpFirstParameter;
+
+ UINT wID;
+ DWORD dwValue;
+
+ UINT wOffset16, wOffset1stParm16;
+ UINT wOffset32, wOffset1stParm32;
+
+ UINT wParamSize;
+
+ DWORD dwParm16;
+ PDWORD pdwOrig16;
+ PDWORD pdwParm32;
+
+ DWORD dwMask = 1;
+
+ //
+ // Calculate the size of this command parameter block in terms
+ // of bytes, then get a VDM pointer to the OrigParms.
+ //
+ GETVDMPTR( OrigParms, GetSizeOfParameter( lpCommand ), pdwOrig16 );
+ dprintf3(( "%s16 bit Parms -> %lX", f_name, pdwOrig16 ));
+
+ //
+ // Skip past command entry
+ //
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand +
+ (*mmAPIEatCmdEntry)( lpCommand, NULL, NULL ));
+ //
+ // Get the next entry
+ //
+ lpFirstParameter = lpCommand;
+
+ //
+ // Skip past the DWORD return value
+ //
+ wOffset1stParm32 = wOffset1stParm16 = 4;
+
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand +
+ (*mmAPIEatCmdEntry)( lpCommand, &dwValue, &wID ));
+ //
+ // If it is a return value, skip it
+ //
+ if ( wID == MCI_RETURN ) {
+
+ //
+ // Look for a string return type, these are a special case.
+ //
+ if ( dwValue == MCI_STRING ) {
+
+ DWORD dwStrlen;
+ LPSTR *lplpStr;
+
+ //
+ // Get string pointer and length
+ //
+ dwParm16 = FETCHDWORD(*(LPDWORD)((LPBYTE)pdwOrig16 + 4));
+ dwStrlen = FETCHDWORD(*(LPDWORD)((LPBYTE)pdwOrig16 + 8));
+
+ //
+ // Copy string pointer
+ //
+ lplpStr = (LPSTR *)((LPBYTE)pNewParms + 4);
+ if ( dwStrlen > 0 ) {
+ GETVDMPTR( dwParm16, dwStrlen, *lplpStr );
+ dprintf5(( "%sReturn string -> 0x%lX", f_name, *lplpStr ));
+ dprintf5(( "%sReturn length -> 0x%lX", f_name, dwStrlen ));
+ }
+
+ //
+ // Copy string length
+ //
+ pdwParm32 = (LPDWORD)((LPBYTE)pNewParms + 8);
+ *pdwParm32 = dwStrlen;
+ }
+
+ //
+ // Adjust the offset of the first parameter. Remember that RECTS
+ // are a different size in 16-bit world.
+ //
+ wParamSize = (*mmAPIGetParamSize)( dwValue, wID );
+ wOffset1stParm16 += (dwValue == MCI_RECT ? sizeof(RECT16) : wParamSize);
+ wOffset1stParm32 += wParamSize;
+
+ //
+ // Save the new first parameter
+ //
+ lpFirstParameter = lpCommand;
+ }
+
+ //
+ // Walk through each flag
+ //
+ while ( dwMask != 0 ) {
+
+ //
+ // Is this bit set?
+ //
+ if ( (dwFlags & dwMask) != 0 ) {
+
+ wOffset16 = wOffset1stParm16;
+ wOffset32 = wOffset1stParm32;
+ lpCommand = (LPWSTR)((LPBYTE)lpFirstParameter +
+ (*mmAPIEatCmdEntry)( lpFirstParameter,
+ &dwValue, &wID ));
+
+ //
+ // What parameter uses this bit?
+ //
+ while ( wID != MCI_END_COMMAND && dwValue != dwMask ) {
+
+ wParamSize = (*mmAPIGetParamSize)( dwValue, wID );
+ wOffset16 += (wID == MCI_RECT ? sizeof( RECT16 ) : wParamSize);
+ wOffset32 += wParamSize;
+
+ if ( wID == MCI_CONSTANT ) {
+
+ while ( wID != MCI_END_CONSTANT ) {
+
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand +
+ (*mmAPIEatCmdEntry)( lpCommand, NULL, &wID ));
+ }
+ }
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand +
+ (*mmAPIEatCmdEntry)( lpCommand, &dwValue, &wID ));
+ }
+
+ if ( wID != MCI_END_COMMAND ) {
+
+ //
+ // Thunk the argument if there is one. The argument is at
+ // wOffset16 from the start of OrigParms.
+ // This offset is in bytes.
+ //
+ dprintf5(( "%sOffset 16 -> 0x%lX", f_name, wOffset16 ));
+ dprintf5(( "%sOffset 32 -> 0x%lX", f_name, wOffset32 ));
+
+ if ( wID != MCI_FLAG ) {
+ dwParm16 = FETCHDWORD(*(LPDWORD)((LPBYTE)pdwOrig16 + wOffset16));
+ pdwParm32 = (LPDWORD)((LPBYTE)pNewParms + wOffset32);
+ }
+
+ switch ( wID ) {
+
+ case MCI_STRING:
+ {
+ LPSTR str16 = (LPSTR)dwParm16;
+ LPSTR str32 = (LPSTR)*pdwParm32;
+ dprintf4(( "%sGot STRING flag -> 0x%lX", f_name, dwMask ));
+ GETPSZPTR( str16, str32 );
+ dprintf5(( "%s\t-> 0x%lX", f_name, *pdwParm32 ));
+ dprintf5(( "%s\t-> %s", f_name, *pdwParm32 ));
+ }
+ break;
+
+ case MCI_HWND:
+ {
+ HWND16 hwnd16;
+ dprintf4(( "%sGot HWND flag -> 0x%lX", f_name, dwMask ));
+ hwnd16 = (HWND16)LOWORD( dwParm16 );
+ *pdwParm32 = (DWORD)HWND32( hwnd16 );
+ dprintf5(( "\t-> 0x%X", hwnd16 ));
+ }
+ break;
+
+ case MCI_HPAL:
+ {
+ HPAL16 hpal16;
+ dprintf4(( "%sGot HPAL flag -> 0x%lX", f_name, dwMask ));
+ hpal16 = (HPAL16)LOWORD( dwParm16 );
+ *pdwParm32 = (DWORD)HPALETTE32( hpal16 );
+ dprintf5(( "\t-> 0x%X", hpal16 ));
+ }
+ break;
+
+ case MCI_HDC:
+ {
+ HDC16 hdc16;
+ dprintf4(( "%sGot HDC flag -> 0x%lX", f_name, dwMask ));
+ hdc16 = (HDC16)LOWORD( dwParm16 );
+ *pdwParm32 = (DWORD)HDC32( hdc16 );
+ dprintf5(( "\t-> 0x%X", hdc16 ));
+ }
+ break;
+
+ case MCI_RECT:
+ {
+ PRECT16 pRect16 = (PRECT16)((LPBYTE)pdwOrig16 + wOffset16);
+ PRECT pRect32 = (PRECT)pdwParm32;
+
+ dprintf4(( "%sGot RECT flag -> 0x%lX", f_name, dwMask ));
+ pRect32->top = (LONG)pRect16->top;
+ pRect32->bottom = (LONG)pRect16->bottom;
+ pRect32->left = (LONG)pRect16->left;
+ pRect32->right = (LONG)pRect16->right;
+ }
+ break;
+
+ case MCI_CONSTANT:
+ case MCI_INTEGER:
+ dprintf4(( "%sGot INTEGER flag -> 0x%lX", f_name, dwMask ));
+ *pdwParm32 = dwParm16;
+ dprintf5(( "\t-> 0x%lX", dwParm16 ));
+ break;
+ }
+ }
+ }
+
+ //
+ // Go to the next flag
+ //
+ dwMask <<= 1;
+ }
+
+ //
+ // Free the VDM pointer as we have finished with it
+ //
+ FREEVDMPTR( pdwOrig16 );
+ return 0;
+}
+
+/**********************************************************************\
+* GetSizeOfParameter
+*
+\**********************************************************************/
+UINT GetSizeOfParameter( LPWSTR lpCommand )
+{
+
+#if DBG
+ static LPSTR f_name = "GetSizeOfParameter";
+#endif
+
+ UINT wOffset;
+ UINT wID;
+ DWORD dwValue;
+
+ //
+ // Skip past command entry
+ //
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand + (*mmAPIEatCmdEntry)( lpCommand,
+ NULL, NULL ));
+ //
+ // Skip past the DWORD return value
+ //
+ wOffset = 4;
+
+ //
+ // Get the first parameter slot entry
+ //
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand +
+ (*mmAPIEatCmdEntry)( lpCommand, &dwValue, &wID ));
+ //
+ // If it is a return value, skip it
+ //
+ if ( wID == MCI_RETURN ) {
+
+ //
+ // Don't forget that RECT's are smaller in 16-bit world.
+ // Other parameters are OK though
+ //
+ if ( dwValue == MCI_RECT ) {
+ wOffset += sizeof( RECT16 );
+ }
+ else {
+ wOffset += (*mmAPIGetParamSize)( dwValue, wID );
+ }
+
+ //
+ // Get first proper entry that is not a return field.
+ //
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand +
+ (*mmAPIEatCmdEntry)( lpCommand, &dwValue, &wID ));
+ }
+
+ //
+ // What parameter uses this bit?
+ //
+ while ( wID != MCI_END_COMMAND ) {
+
+ //
+ // Don't forget that RECT's are smaller in 16-bit world.
+ // Other parameters are OK though
+ //
+ if ( wID == MCI_RECT ) {
+ wOffset += sizeof( RECT16 );
+ }
+ else {
+ wOffset += (*mmAPIGetParamSize)( dwValue, wID );
+ }
+
+ //
+ // If we have a constant we need to skip the entries in
+ // the command table.
+ //
+ if ( wID == MCI_CONSTANT ) {
+
+ while ( wID != MCI_END_CONSTANT ) {
+
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand
+ + (*mmAPIEatCmdEntry)( lpCommand, NULL, &wID ));
+ }
+ }
+
+ //
+ // Get the next entry
+ //
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand
+ + (*mmAPIEatCmdEntry)( lpCommand, &dwValue, &wID ));
+ }
+
+ dprintf4(( "%sSizeof Cmd Params -> %u bytes", f_name, wOffset ));
+ return wOffset;
+}
+
+
+#if DBG
+/*--------------------------------------------------------------------*\
+ MCI WOW DEBUGGING FUNCTIONS
+\*--------------------------------------------------------------------*/
+
+/**********************************************************************\
+ * wow32MciDebugOutput
+ *
+ * Output a formated message to the debug terminal.
+ *
+\**********************************************************************/
+VOID wow32MciDebugOutput( LPSTR lpszFormatStr, ... )
+{
+ CHAR buf[256];
+ UINT n;
+ va_list va;
+
+ va_start(va, lpszFormatStr);
+ n = vsprintf(buf, lpszFormatStr, va);
+ va_end(va);
+
+ buf[n++] = '\n';
+ buf[n] = 0;
+ OutputDebugString(buf);
+}
+
+/**********************************************************************\
+ * wow32MciSetDebugLevel
+ *
+ * Query and set the debug level.
+\**********************************************************************/
+VOID wow32MciSetDebugLevel( VOID )
+{
+
+ int DebugLevel;
+
+ //
+ // First see if a specific WOW32MCI key has been defined.
+ // If one hasn't been defined DebugLevel will be set to '999'.
+ //
+ DebugLevel = (int)GetProfileInt( "MMDEBUG", "WOW32MCI", 999 );
+
+ //
+ // If DebugLevel == '999' then an WOW32MCI key has not been defined,
+ // so try a "WOW32" key. This time if the key has not been defined
+ // set the debug level to 0, ie. no debugging info should be
+ // displayed.
+ //
+ if ( DebugLevel == 999 ) {
+ DebugLevel = (int)GetProfileInt( "MMDEBUG", "WOW32", 0 );
+ }
+
+ mmDebugLevel = DebugLevel;
+}
+#endif
+#endif
diff --git a/private/mvdm/wow32/wmmstru2.c b/private/mvdm/wow32/wmmstru2.c
new file mode 100644
index 000000000..600870144
--- /dev/null
+++ b/private/mvdm/wow32/wmmstru2.c
@@ -0,0 +1,539 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMMSTRU2.C
+ * WOW32 16-bit MultiMedia structure conversion support
+ * Contains support for mciSendCommand UnThunk message Parms.
+ *
+ * History:
+ * Created 17-Jul-1992 by Stephen Estrop (stephene)
+ *
+--*/
+
+//
+// We define NO_STRICT so that the compiler doesn't moan and groan when
+// I use the FARPROC type for the Multi-Media api loading.
+//
+#define NO_STRICT
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if 0
+
+MODNAME(wmmstru2.c);
+
+//
+// The following are required for the dynamic linking of Multi-Media code
+// from within WOW. They are all defined in wmmedia.c
+//
+
+extern FARPROC mmAPIEatCmdEntry;
+extern FARPROC mmAPIGetParamSize;
+extern FARPROC mmAPIUnlockCmdTable;
+extern FARPROC mmAPISendCmdW;
+
+/**********************************************************************\
+*
+* UnThunkMciCommand16
+*
+* This function "unthunks" a 32 bit mci send command request.
+*
+* The ideas behind this function were stolen from UnThunkWMMsg16,
+* see wmsg16.c
+*
+\**********************************************************************/
+INT UnThunkMciCommand16( MCIDEVICEID devID, UINT OrigCommand, DWORD OrigFlags,
+ DWORD OrigParms, DWORD NewParms, LPWSTR lpCommand,
+ UINT uTable )
+{
+ BOOL fReturnValNotThunked = FALSE;
+
+#if DBG
+ static LPSTR f_name = "UnThunkMciCommand16: ";
+ register int i;
+ int n;
+
+ dprintf3(( "UnThunkMciCommand :" ));
+ n = sizeof(mciMessageNames) / sizeof(MCI_MESSAGE_NAMES);
+ for ( i = 0; i < n; i++ ) {
+ if ( mciMessageNames[i].uMsg == OrigCommand ) {
+ break;
+ }
+ }
+ dprintf3(( "OrigCommand -> %lX", (DWORD)OrigCommand ));
+ dprintf3(( " Name -> %s", i != n ? mciMessageNames[i].lpstMsgName : "Unkown Name" ));
+
+ dprintf5(( " OrigFlags -> %lX", OrigFlags ));
+ dprintf5(( " OrigParms -> %lX", OrigParms ));
+ dprintf5(( " NewParms -> %lX", NewParms ));
+
+ //
+ // If NewParms is 0 we shouldn't be here, I haven't got an assert
+ // macro, but the following we do the same thing.
+ //
+ if ( NewParms == 0 ) {
+ dprintf(( "%scalled with NewParms == NULL !!", f_name ));
+ dprintf(( "Call StephenE NOW !!" ));
+ DebugBreak();
+ }
+#endif
+
+ //
+ // We have to do a manual unthunk of MCI_SYSINFO because the
+ // command table is not consistent. As a command table should be
+ // available now we can load it and then use it to unthunk MCI_OPEN.
+ //
+ switch ( OrigCommand ) {
+
+ case MCI_OPEN:
+ UnThunkOpenCmd( OrigFlags, OrigParms, NewParms );
+ break;
+
+ case MCI_SYSINFO:
+ UnThunkSysInfoCmd( OrigFlags, OrigParms, NewParms );
+ break;
+
+ case MCI_STATUS:
+ UnThunkStatusCmd( devID, OrigFlags, OrigParms, NewParms );
+ break;
+
+ default:
+ fReturnValNotThunked = TRUE;
+ break;
+ }
+
+ //
+ // Do we have a command table ? It is possible that we have
+ // a custom command but we did not find a custom command table, in which
+ // case we should just free the pNewParms storage.
+ //
+ if ( lpCommand != NULL ) {
+
+ //
+ // We now parse the custom command table to see if there is a
+ // return field in the parms structure.
+ //
+ dprintf3(( "%sUnthunking via command table", f_name ));
+ UnThunkCommandViaTable( lpCommand, OrigFlags, OrigParms,
+ NewParms, fReturnValNotThunked );
+
+ //
+ // Now we have finished with the command table we should unlock it.
+ //
+ dprintf4(( "%sUnlocking custom command table", f_name ));
+ (*mmAPIUnlockCmdTable)( uTable );
+ }
+
+ //
+ // All that needs to be done now is to free the storage
+ // that was allocated during the ThunkXxxCmd function.
+ //
+ dprintf4(( "%sFreeing storage.", f_name ));
+ free_w( (PBYTE)NewParms );
+ return 0;
+}
+
+
+/**********************************************************************\
+* UnThunkOpenCmd
+*
+* UnThunk the Open mci command parms.
+\**********************************************************************/
+VOID UnThunkOpenCmd( DWORD OrigFlags, DWORD OrigParms, DWORD NewParms )
+{
+
+#if DBG
+ static LPSTR f_name = "UnThunkOpenCmd: ";
+#endif
+
+ LPMCI_OPEN_PARMS lpOpeParms = (LPMCI_OPEN_PARMS)NewParms;
+ PMCI_OPEN_PARMS16 lpOpeParms16;
+ WORD wDevice;
+
+ dprintf4(( "%sCopying Device ID.", f_name ));
+
+ GETVDMPTR( OrigParms, sizeof(MCI_OPEN_PARMS16), lpOpeParms16 );
+ wDevice = LOWORD( lpOpeParms->wDeviceID );
+ STOREWORD( lpOpeParms16->wDeviceID, wDevice );
+ FLUSHVDMPTR( OrigParms, sizeof(MCI_OPEN_PARMS16), lpOpeParms16 );
+ FREEVDMPTR( lpOpeParms16 );
+
+ dprintf5(( "wDeviceID -> %u", wDevice ));
+
+ if ( (OrigParms & MCI_OPEN_TYPE) && !(OrigParms & MCI_OPEN_TYPE_ID ) ) {
+
+ dprintf3(( "%sFreeing a STRING pointer", f_name ));
+ FREEPSZPTR( lpOpeParms->lpstrDeviceType );
+ }
+
+ if ( (OrigParms & MCI_OPEN_ELEMENT)
+ && !(OrigParms & MCI_OPEN_ELEMENT_ID ) ) {
+
+ dprintf3(( "%sFreeing a STRING pointer", f_name ));
+ FREEPSZPTR( lpOpeParms->lpstrElementName );
+ }
+}
+
+
+/**********************************************************************\
+* UnThunkSysInfoCmd
+*
+* UnThunk the SysInfo mci command parms.
+\**********************************************************************/
+VOID UnThunkSysInfoCmd( DWORD OrigFlags, DWORD OrigParms, DWORD NewParms )
+{
+
+#if DBG
+ static LPSTR f_name = "UnThunkSysInfoCmd: ";
+#endif
+
+ LPMCI_SYSINFO_PARMS lpSysParms = (LPMCI_SYSINFO_PARMS)NewParms;
+
+ //
+ // Had better check that we did actually allocate
+ // a pointer.
+ //
+ if ( lpSysParms->lpstrReturn && lpSysParms->dwRetSize ) {
+
+#if DBG
+ if ( !(OrigFlags & MCI_SYSINFO_QUANTITY) ) {
+ dprintf5(( "lpstrReturn -> %s", lpSysParms->lpstrReturn ));
+ }
+ else {
+ dprintf5(( "lpstrReturn -> %d", *(LPDWORD)lpSysParms->lpstrReturn ));
+ }
+#endif
+
+ //
+ // Free lpSysParms->lpstrReturn;
+ //
+ dprintf4(( "%sFreeing lpstrReturn", f_name ));
+ FREEVDMPTR( lpSysParms->lpstrReturn );
+ }
+}
+
+
+/**********************************************************************\
+* UnThunkMciStatus
+*
+* UnThunk the Status mci command parms.
+\**********************************************************************/
+VOID UnThunkStatusCmd( MCIDEVICEID devID, DWORD OrigFlags,
+ DWORD OrigParms, DWORD NewParms )
+{
+#if DBG
+ static LPSTR f_name = "UnThunkStatusCmd: ";
+#endif
+
+ MCI_GETDEVCAPS_PARMS GetDevCaps;
+ DWORD dwRetVal;
+ DWORD dwParm16;
+ PDWORD pdwOrig16;
+ PDWORD pdwParm32;
+ int iReturnType = MCI_INTEGER;
+
+ /*
+ ** If the MCI_STATUS_ITEM flag is not specified don't bother
+ ** doing any unthunking.
+ */
+ if ( !(OrigFlags & MCI_STATUS_ITEM) ) {
+ return;
+ }
+
+ /*
+ ** We need to determine what type of device we are
+ ** dealing with. We can do this by send an MCI_GETDEVCAPS
+ ** command to the device. (We might as well use the Unicode
+ ** version of mciSendCommand and avoid another thunk).
+ */
+ RtlZeroMemory( &GetDevCaps, sizeof(MCI_GETDEVCAPS_PARMS) );
+ GetDevCaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;
+ dwRetVal = (*mmAPISendCmdW)( devID, MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM,
+ (DWORD)&GetDevCaps );
+ /*
+ ** If we can't get the DevCaps then we are doomed.
+ */
+ if ( dwRetVal ) {
+ dprintf(("%sFailure to get devcaps", f_name));
+ return;
+ }
+
+ /*
+ ** Determine the dwReturn type.
+ */
+ switch ( GetDevCaps.dwReturn ) {
+
+ case MCI_DEVTYPE_ANIMATION:
+ switch ( ((LPDWORD)NewParms)[2] ) {
+
+ case MCI_ANIM_STATUS_HWND:
+ iReturnType = MCI_HWND;
+ break;
+
+ case MCI_ANIM_STATUS_HPAL:
+ iReturnType = MCI_HPAL;
+ break;
+ }
+ break;
+
+ case MCI_DEVTYPE_OVERLAY:
+ if ( ((LPDWORD)NewParms)[2] == MCI_OVLY_STATUS_HWND ) {
+ iReturnType = MCI_HWND;
+ }
+ break;
+
+ case MCI_DEVTYPE_DIGITAL_VIDEO:
+ switch ( ((LPDWORD)NewParms)[2] ) {
+
+ case MCI_DGV_STATUS_HWND:
+ iReturnType = MCI_HWND;
+ break;
+
+ case MCI_DGV_STATUS_HPAL:
+ iReturnType = MCI_HPAL;
+ break;
+ }
+ break;
+ }
+
+
+ /*
+ ** Thunk the dwReturn value according to the required type
+ */
+ GETVDMPTR( OrigParms, sizeof( MCI_STATUS_PARMS), pdwOrig16 );
+ pdwParm32 = (LPDWORD)((LPBYTE)NewParms + 4);
+
+ switch ( iReturnType ) {
+ case MCI_HPAL:
+ dprintf4(( "%sFound an HPAL return field", f_name ));
+ dwParm16 = MAKELONG( GETHPALETTE16( (HPALETTE)*pdwParm32 ), 0 );
+ STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), dwParm16 );
+ dprintf5(( "HDC32 -> 0x%lX", *pdwParm32 ));
+ dprintf5(( "HDC16 -> 0x%lX", dwParm16 ));
+ break;
+
+ case MCI_HWND:
+ dprintf4(( "%sFound an HWND return field", f_name ));
+ dwParm16 = MAKELONG( GETHWND16( (HWND)*pdwParm32 ), 0 );
+ STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), dwParm16 );
+ dprintf5(( "HWND32 -> 0x%lX", *pdwParm32 ));
+ dprintf5(( "HWND16 -> 0x%lX", dwParm16 ));
+ break;
+
+ case MCI_INTEGER:
+ dprintf4(( "%sFound an INTEGER return field", f_name ));
+ STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), *pdwParm32 );
+ dprintf5(( "INTEGER -> %ld", *pdwParm32 ));
+ break;
+
+ // no default: all possible cases accounted for
+ }
+
+ /*
+ ** Free the VDM pointer as we have finished with it
+ */
+ FLUSHVDMPTR( OrigParms, sizeof( MCI_STATUS_PARMS), pdwOrig16 );
+ FREEVDMPTR( pdwOrig16 );
+
+}
+/**********************************************************************\
+* UnThunkCommandViaTable
+*
+* Thunks the return field if there is one and then frees and pointers
+* that were got via GETVDMPTR or GETPSZPTR.
+\**********************************************************************/
+INT UnThunkCommandViaTable( LPWSTR lpCommand, DWORD dwFlags, DWORD OrigParms,
+ DWORD pNewParms, BOOL fReturnValNotThunked )
+{
+
+#if DBG
+ static LPSTR f_name = "UnThunkCommandViaTable: ";
+#endif
+
+ LPWSTR lpFirstParameter;
+
+ UINT wID;
+ DWORD dwValue;
+
+ UINT wOffset32, wOffset1stParm32;
+
+ DWORD dwParm16;
+ DWORD Size;
+ PDWORD pdwOrig16;
+ PDWORD pdwParm32;
+
+ DWORD dwMask = 1;
+
+ //
+ // Calculate the size of this command parameter block in terms
+ // of bytes, then get a VDM pointer to the OrigParms.
+ //
+ Size = GetSizeOfParameter( lpCommand );
+
+ //
+ // Skip past command entry
+ //
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand +
+ (*mmAPIEatCmdEntry)( lpCommand, NULL, NULL ));
+ //
+ // Get the next entry
+ //
+ lpFirstParameter = lpCommand;
+
+ //
+ // Skip past the DWORD return value
+ //
+ wOffset1stParm32 = 4;
+
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand +
+ (*mmAPIEatCmdEntry)( lpCommand, &dwValue, &wID ));
+ //
+ // If it is a return value, skip it
+ //
+ if ( (wID == MCI_RETURN) && (fReturnValNotThunked) ) {
+
+ GETVDMPTR( OrigParms, Size, pdwOrig16 );
+ pdwParm32 = (LPDWORD)((LPBYTE)pNewParms + 4);
+
+ //
+ // Look for a string return type, these are a special case.
+ //
+ switch ( dwValue ) {
+
+ case MCI_STRING:
+ dprintf4(( "%sFound a STRING return field", f_name ));
+ //
+ // Get string pointer and length
+ //
+ Size = *(LPDWORD)((LPBYTE)pNewParms + 8);
+
+ //
+ // Get the 32 bit string pointer
+ //
+ if ( Size > 0 ) {
+
+ dprintf4(( "%sFreeing a return STRING pointer", f_name ));
+ dprintf5(( "STRING -> %s", (LPSTR)*pdwParm32 ));
+ FREEVDMPTR( (LPSTR)*pdwParm32 );
+ }
+ break;
+
+ case MCI_RECT:
+ {
+ PRECT pRect32 = (PRECT)((LPBYTE)pNewParms + 4);
+ PRECT16 pRect16 = (PRECT16)((LPBYTE)pdwOrig16 + 4);
+
+ dprintf4(( "%sFound a RECT return field", f_name ));
+ STORESHORT( pRect16->top, (SHORT)pRect32->top );
+ STORESHORT( pRect16->bottom, (SHORT)pRect32->bottom );
+ STORESHORT( pRect16->left, (SHORT)pRect32->left );
+ STORESHORT( pRect16->right, (SHORT)pRect32->right );
+ }
+ break;
+
+ case MCI_INTEGER:
+ //
+ // Get the 32 bit return integer and store it in the
+ // 16 bit parameter structure.
+ //
+ dprintf4(( "%sFound an INTEGER return field", f_name ));
+ STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), *pdwParm32 );
+ dprintf5(( "INTEGER -> %ld", *pdwParm32 ));
+ break;
+
+ case MCI_HWND:
+ dprintf4(( "%sFound an HWND return field", f_name ));
+ dwParm16 = MAKELONG( GETHWND16( (HWND)*pdwParm32 ), 0 );
+ STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), dwParm16 );
+ dprintf5(( "HWND32 -> 0x%lX", *pdwParm32 ));
+ dprintf5(( "HWND16 -> 0x%lX", dwParm16 ));
+ break;
+
+ case MCI_HPAL:
+ dprintf4(( "%sFound an HPAL return field", f_name ));
+ dwParm16 = MAKELONG( GETHPALETTE16( (HPALETTE)*pdwParm32 ), 0 );
+ STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), dwParm16 );
+ dprintf5(( "HDC32 -> 0x%lX", *pdwParm32 ));
+ dprintf5(( "HDC16 -> 0x%lX", dwParm16 ));
+ break;
+
+ case MCI_HDC:
+ dprintf4(( "%sFound an HDC return field", f_name ));
+ dwParm16 = MAKELONG( GETHDC16( (HDC)*pdwParm32 ), 0 );
+ STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), dwParm16 );
+ dprintf5(( "HDC32 -> 0x%lX", *pdwParm32 ));
+ dprintf5(( "HDC16 -> 0x%lX", dwParm16 ));
+ break;
+ }
+
+ //
+ // Free the VDM pointer as we have finished with it
+ //
+ FLUSHVDMPTR( OrigParms, Size, pdwOrig16 );
+ FREEVDMPTR( pdwOrig16 );
+
+ //
+ // Adjust the offset of the first parameter.
+ //
+ wOffset1stParm32 = (*mmAPIGetParamSize)( dwValue, wID );
+
+ //
+ // Save the new first parameter
+ //
+ lpFirstParameter = lpCommand;
+ }
+
+ //
+ // Walk through each flag looking for strings to free
+ //
+ while ( dwMask != 0 ) {
+
+ //
+ // Is this bit set?
+ //
+ if ( (dwFlags & dwMask) != 0 ) {
+
+ wOffset32 = wOffset1stParm32;
+ lpCommand = (LPWSTR)((LPBYTE)lpFirstParameter +
+ (*mmAPIEatCmdEntry)( lpFirstParameter,
+ &dwValue, &wID ));
+
+ //
+ // What parameter uses this bit?
+ //
+ while ( wID != MCI_END_COMMAND && dwValue != dwMask ) {
+
+ wOffset32 = (*mmAPIGetParamSize)( dwValue, wID );
+
+ if ( wID == MCI_CONSTANT ) {
+
+ while ( wID != MCI_END_CONSTANT ) {
+
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand +
+ (*mmAPIEatCmdEntry)( lpCommand, NULL, &wID ));
+ }
+ }
+ lpCommand = (LPWSTR)((LPBYTE)lpCommand +
+ (*mmAPIEatCmdEntry)( lpCommand, &dwValue, &wID ));
+ }
+
+ if ( wID == MCI_STRING ) {
+ dprintf4(( "%sFreeing a STRING pointer", f_name ));
+ pdwParm32 = (LPDWORD)((LPBYTE)pNewParms + wOffset32);
+ FREEPSZPTR( (LPSTR)*pdwParm32 );
+ }
+ }
+
+ //
+ // Go to the next flag
+ //
+ dwMask <<= 1;
+ }
+
+ return 0;
+}
+#endif
diff --git a/private/mvdm/wow32/wmmstruc.c b/private/mvdm/wow32/wmmstruc.c
new file mode 100644
index 000000000..8c10cae89
--- /dev/null
+++ b/private/mvdm/wow32/wmmstruc.c
@@ -0,0 +1,762 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMMSTRUC.C
+ *
+ *
+ * MultiMedia Structure copying functions (modelled after WSTRUC.C by jeffpar)
+ *
+ * For input structures, there are GETxxxx16 macros; for output structures
+ * there are PUTxxxx16 macros. Most or all of these macros will simply call
+ * the corresponding function below.
+ *
+ *
+ * WOW32 16-bit MultiMedia structure conversion support
+ *
+ * History:
+ * Created 13-Feb-1992 by Mike Tricker (miketri)
+ * Changed 16-Jul-1992 by Mike Tricker (miketri) Sorted out the Caps structure copies
+ * Changed 08-Oct-1992 by StephenE Made the thunks safe on MIPS
+ *
+ * Basically doing a GETVDMPTR of a null pointer is bad on MIPS, so is
+ * trying to get a pointer to zero bytes. On Intel these GETXXX macros
+ * don't really do anything.
+ *
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if 0
+MODNAME(wmmstruc.c);
+
+
+
+
+/**********************************************************************\
+ * getmmtime16
+ *
+ * Thunks an MMTIME structure from 16 bit to 32 bit space.
+ *
+ * Used by:
+ * waveOutGetPosition
+ * waveInGetPosition
+ * timeGetSystemTime
+ *
+\**********************************************************************/
+ULONG getmmtime16 (VPMMTIME16 vpmmt, LPMMTIME lpmmt)
+{
+ register PMMTIME16 pmmt16;
+
+#ifdef MIPS_COMPILER_PACKING_BUG
+ MMGETOPTPTR(vpmmt, 8, pmmt16);
+#else
+ MMGETOPTPTR(vpmmt, sizeof(MMTIME16), pmmt16);
+#endif
+
+ if ( pmmt16 == NULL ) {
+ dprintf1(( "getmmtime16 MMGETOPTPTR returned a NULL pointer" ));
+ return MMSYSERR_INVALPARAM;
+ }
+
+ lpmmt->wType = (UINT)FETCHWORD(pmmt16->wType);
+
+ switch ( lpmmt->wType ) {
+ case TIME_MS:
+ lpmmt->u.ms = FETCHDWORD(pmmt16->u.ms);
+ break;
+
+ case TIME_SAMPLES:
+ lpmmt->u.sample = FETCHDWORD(pmmt16->u.sample);
+ break;
+
+ case TIME_BYTES:
+ lpmmt->u.cb = FETCHDWORD(pmmt16->u.cb);
+ break;
+
+ case TIME_SMPTE:
+ lpmmt->u.smpte.hour = pmmt16->u.smpte.hour;
+ lpmmt->u.smpte.min = pmmt16->u.smpte.min;
+ lpmmt->u.smpte.sec = pmmt16->u.smpte.sec;
+ lpmmt->u.smpte.frame = pmmt16->u.smpte.frame;
+ lpmmt->u.smpte.fps = pmmt16->u.smpte.fps;
+ lpmmt->u.smpte.dummy = pmmt16->u.smpte.dummy;
+ break;
+
+ case TIME_MIDI:
+ lpmmt->u.midi.songptrpos = FETCHDWORD(pmmt16->u.midi.songptrpos);
+ break;
+ }
+
+ FREEVDMPTR(pmmt16);
+ return MMSYSERR_NOERROR;
+}
+
+/**********************************************************************\
+ * Thunks an MMTIME structure from 32 bit back to 16 bit space.
+ *
+ * Used by:
+ * waveOutGetPosition
+ * waveInGetPosition
+ * timeGetSystemTime
+\**********************************************************************/
+ULONG putmmtime16 (VPMMTIME16 vpmmt, LPMMTIME lpmmt)
+{
+ register PMMTIME16 pmmt16;
+
+
+#ifdef MIPS_COMPILER_PACKING_BUG
+ MMGETOPTPTR(vpmmt, 8, pmmt16);
+#else
+ MMGETOPTPTR(vpmmt, sizeof(MMTIME16), pmmt16);
+#endif
+
+ if ( pmmt16 == NULL ) {
+ dprintf1(( "putmmtime16 MMGETOPTPTR returned a NULL pointer" ));
+ return MMSYSERR_INVALPARAM;
+ }
+
+ STOREWORD(pmmt16->wType, (WORD)lpmmt->wType);
+
+ switch ( pmmt16->wType ) {
+
+ case TIME_MS:
+ STOREDWORD(pmmt16->u.ms, lpmmt->u.ms);
+ dprintf2(( "Time in MS is %x", lpmmt->u.ms ));
+ break;
+
+ case TIME_SAMPLES:
+ STOREDWORD(pmmt16->u.sample, lpmmt->u.sample);
+ dprintf2(( "Time in samples is %x", lpmmt->u.sample ));
+ break;
+
+ case TIME_BYTES:
+ STOREDWORD(pmmt16->u.cb, lpmmt->u.cb);
+ dprintf2(( "Time in bytes is %x", lpmmt->u.cb ));
+ break;
+
+ case TIME_SMPTE:
+ pmmt16->u.smpte.hour = lpmmt->u.smpte.hour;
+ pmmt16->u.smpte.min = lpmmt->u.smpte.min;
+ pmmt16->u.smpte.sec = lpmmt->u.smpte.sec;
+ pmmt16->u.smpte.frame = lpmmt->u.smpte.frame;
+ pmmt16->u.smpte.fps = lpmmt->u.smpte.fps;
+ pmmt16->u.smpte.dummy = lpmmt->u.smpte.dummy;
+ break;
+
+ case TIME_MIDI:
+ STOREDWORD(pmmt16->u.midi.songptrpos, lpmmt->u.midi.songptrpos);
+ dprintf2(( "Time in midi is %x", lpmmt->u.midi.songptrpos ));
+ break;
+ }
+
+#ifdef MIPS_COMPILER_PACKING_BUG
+ FLUSHVDMPTR(vpmmt, 8, pmmt16);
+#else
+ FLUSHVDMPTR(vpmmt, sizeof(MMTIME16), pmmt16);
+#endif
+ FREEVDMPTR(pmmt16);
+
+ return MMSYSERR_NOERROR;
+
+}
+
+/**********************************************************************\
+* Thunks a WAVEHDR structure from 16 bit to 32 bit space.
+*
+* Used by:
+* waveOutPrepareHeader
+* waveOutUnprepareHeader
+* waveOutWrite
+* waveInPrepareHeader
+* waveInUnprepareHeader
+* waveInAddBuffer
+*
+* Returns a 32 bit pointer to the 16 bit wave header. This wave header
+* should have been locked down by wave(In|Out)PrepareHeader. Therefore,
+* it is to store this pointer for use during the WOM_DONE callback message.
+*
+* With the WAVEHDR and MIDIHDR structs I am assured by Robin that the ->lpNext
+* field is only used by the driver, and is therefore in 32 bit space. It
+* therefore doesn't matter what gets passed back and forth (I hope !).
+*
+\**********************************************************************/
+PWAVEHDR16 getwavehdr16( VPWAVEHDR16 vpwhdr, LPWAVEHDR lpwhdr )
+{
+ register PWAVEHDR16 pwhdr16;
+
+ MMGETOPTPTR(vpwhdr, sizeof(WAVEHDR16), pwhdr16);
+ if ( pwhdr16 == NULL ) {
+ dprintf1(( "getwavehdr16 MMGETOPTPTR returned an invalid pointer" ));
+ return NULL;
+ }
+
+ if ( HIWORD(FETCHDWORD( pwhdr16->lpData )) != 0 ) {
+ GETMISCPTR(pwhdr16->lpData, lpwhdr->lpData);
+ }
+ else {
+ dprintf1(( "getwavehdr16 passed an invalid pointer to data" ));
+ lpwhdr->lpData = (VPSTR)NULL;
+ }
+
+ lpwhdr->dwBufferLength = FETCHDWORD(pwhdr16->dwBufferLength);
+ dprintf4(( "getwavehdr16: buffer length = %X", lpwhdr->dwBufferLength ));
+
+ lpwhdr->dwBytesRecorded = FETCHDWORD(pwhdr16->dwBytesRecorded);
+ lpwhdr->dwUser = FETCHDWORD(pwhdr16->dwUser);
+ lpwhdr->dwFlags = FETCHDWORD(pwhdr16->dwFlags);
+ lpwhdr->dwLoops = FETCHDWORD(pwhdr16->dwLoops);
+ lpwhdr->lpNext = (PWAVEHDR)FETCHDWORD(pwhdr16->lpNext);
+ lpwhdr->reserved = FETCHDWORD(pwhdr16->reserved);
+
+ return pwhdr16;
+}
+
+/**********************************************************************\
+* Thunks a WAVEHDR structure from 32 bit back to 16 bit space.
+*
+* Used by:
+* waveOutPrepareHeader
+* waveOutUnprepareHeader
+* waveOutWrite
+* waveInPrepareHeader
+* waveInUnprepareHeader
+* waveInAddBuffer
+*
+*
+* With the WAVEHDR and MIDIHDR structs I am assured by Robin that the ->lpNext
+* field is only used by the driver, and is therefore in 32 bit space. It
+* therefore doesn't matter what gets passed back and forth (I hope !).
+*
+\**********************************************************************/
+VOID putwavehdr16 (VPWAVEHDR16 vpwhdr, LPWAVEHDR lpwhdr)
+{
+ register PWAVEHDR16 pwhdr16;
+
+ MMGETOPTPTR(vpwhdr, sizeof(WAVEHDR16), pwhdr16);
+ if ( pwhdr16 == NULL ) {
+ dprintf1(( "getwavehdr16 MMGETOPTPTR returned a NULL pointer" ));
+ return;
+ }
+
+ STOREDWORD(pwhdr16->dwBufferLength, lpwhdr->dwBufferLength);
+ STOREDWORD(pwhdr16->dwBytesRecorded, lpwhdr->dwBytesRecorded);
+ STOREDWORD(pwhdr16->dwUser, lpwhdr->dwUser);
+ STOREDWORD(pwhdr16->dwFlags, lpwhdr->dwFlags);
+ STOREDWORD(pwhdr16->dwLoops, lpwhdr->dwLoops);
+ STOREDWORD(pwhdr16->lpNext, lpwhdr->lpNext);
+ STOREDWORD(pwhdr16->reserved, lpwhdr->reserved);
+
+ FLUSHVDMPTR(vpwhdr, sizeof(WAVEHDR16), pwhdr16);
+ FREEVDMPTR(pwhdr16);
+}
+
+
+/**********************************************************************\
+ * Thunks a WAVEOUTCAPS structure from 32 bit back to 16 bit space.
+ *
+ * Used by:
+ * waveOutGetDevCaps
+ *
+ * Remember that the ->vDriverVersion is a WORD in 16bit land and a UINT in
+ * 32 bit. This applies to WAVEIN/OUTCAPS, MIDIIN/OUTCAPS and AUXCAPS.
+ *
+\**********************************************************************/
+ULONG putwaveoutcaps16 (VPWAVEOUTCAPS16 vpwoc, LPWAVEOUTCAPS lpwoc, UINT uSize)
+{
+ INT i;
+ WAVEOUTCAPS16 Temp;
+ PWAVEOUTCAPS16 pwoc16;
+
+ /*
+ ** Just in case the app specified a NULL pointer. We have already
+ ** validated that uSize is not zero.
+ */
+
+ MMGETOPTPTR( vpwoc, min(uSize, sizeof(WAVEOUTCAPS16)), pwoc16 );
+ if ( pwoc16 == NULL ) {
+ dprintf1(( "putwaveoutcaps16 MMGETOPTPTR returned a NULL pointer" ));
+ return MMSYSERR_INVALPARAM;
+ }
+
+ STOREWORD(Temp.wMid, lpwoc->wMid);
+ STOREWORD(Temp.wPid, lpwoc->wPid);
+ STOREWORD(Temp.vDriverVersion, (WORD)lpwoc->vDriverVersion);
+
+ /*
+ ** The product name string should be null terminated, but we want
+ ** the whole string anyway, so copy the whole MAXPNAMELEN bytes.
+ */
+ i = 0;
+ while (i < MAXPNAMELEN) {
+ Temp.szPname[i] = lpwoc->szPname[i++];
+ }
+
+ STOREDWORD(Temp.dwFormats, lpwoc->dwFormats);
+ STOREWORD(Temp.wChannels, lpwoc->wChannels);
+ STOREDWORD(Temp.dwSupport, lpwoc->dwSupport);
+
+ RtlCopyMemory( (LPVOID)pwoc16, &Temp, min(uSize, sizeof(WAVEOUTCAPS16)) );
+
+ FLUSHVDMPTR(vpwoc, min(uSize, sizeof(WAVEOUTCAPS16)), pwoc16);
+ FREEVDMPTR(pwoc16);
+
+ return MMSYSERR_NOERROR;
+
+}
+
+
+/**********************************************************************\
+ * Thunks a WAVEINCAPS structure from 32 bit back to 16 bit space.
+ *
+ * Used by:
+ * waveInGetDevCaps
+ *
+ * Remember that the ->vDriverVersion is a WORD in 16bit land and a UINT in
+ * 32 bit. This applies to WAVEIN/OUTCAPS, MIDIIN/OUTCAPS and AUXCAPS.
+ *
+\**********************************************************************/
+ULONG putwaveincaps16 (VPWAVEINCAPS16 vpwic, LPWAVEINCAPS lpwic, UINT uSize)
+{
+ INT i;
+ WAVEINCAPS16 Temp;
+ PWAVEINCAPS16 pwic16;
+
+ /*
+ ** Just in case the app specified a NULL pointer. We have already
+ ** validated that uSize is not zero.
+ */
+
+ MMGETOPTPTR(vpwic, min(uSize, sizeof(WAVEINCAPS16)), pwic16);
+ if ( pwic16 == NULL ) {
+ dprintf1(( "putwaveincaps16 MMGETOPTPTR returned a NULL pointer" ));
+ return MMSYSERR_INVALPARAM;
+ }
+
+ STOREWORD(Temp.wMid, lpwic->wMid);
+ STOREWORD(Temp.wPid, lpwic->wPid);
+ STOREWORD(Temp.vDriverVersion, (WORD)lpwic->vDriverVersion);
+
+ /*
+ ** The product name string should be null terminated,
+ ** but we want the whole string anyway, so copy the whole
+ ** MAXPNAMELEN bytes.
+ */
+ i = 0;
+ while (i < MAXPNAMELEN) {
+ Temp.szPname[i] = lpwic->szPname[i++];
+ }
+
+ STOREDWORD(Temp.dwFormats, lpwic->dwFormats);
+ STOREWORD(Temp.wChannels, lpwic->wChannels);
+
+ RtlCopyMemory( (LPVOID)pwic16, &Temp, min(uSize, sizeof(WAVEINCAPS16)) );
+
+ FLUSHVDMPTR(vpwic, min(uSize, sizeof(WAVEINCAPS16)), pwic16);
+ FREEVDMPTR(pwic16);
+
+ return MMSYSERR_NOERROR;
+
+}
+
+/**********************************************************************\
+ * Thunks a MIDIHDR structure from 16 bit to 32 bit space.
+ *
+ * Used by:
+ * midiOutLongMsg
+ * midiInAddBuffer
+ * midiOutPrepareHdr
+ * midiOutUnprepareHdr
+ * midiInPrepareHdr
+ * midiInUnprepareHdr
+ *
+\**********************************************************************/
+PMIDIHDR16 getmidihdr16 (VPMIDIHDR16 vpmhdr, LPMIDIHDR lpmhdr)
+{
+ PMIDIHDR16 pmhdr16;
+
+ MMGETOPTPTR(vpmhdr, sizeof(MIDIHDR16), pmhdr16);
+ if ( pmhdr16 == NULL ) {
+ dprintf1(( "getmidihdr MMGETOPTPTR returned a NULL pointer" ));
+ return NULL;
+ }
+
+ if ( HIWORD(FETCHDWORD( pmhdr16->lpData )) != 0 ) {
+ GETMISCPTR(pmhdr16->lpData, lpmhdr->lpData);
+ }
+ else {
+ dprintf1(( "getmidihdr16 passed a NULL pointer to data" ));
+ lpmhdr->lpData = (VPSTR)NULL;
+ }
+
+ lpmhdr->dwBufferLength = FETCHDWORD(pmhdr16->dwBufferLength);
+ dprintf4(( "getmidihdr16: buffer length = %X", lpmhdr->dwBufferLength ));
+
+ lpmhdr->dwBytesRecorded = FETCHDWORD(pmhdr16->dwBytesRecorded);
+ lpmhdr->dwUser = FETCHDWORD(pmhdr16->dwUser);
+ lpmhdr->dwFlags = FETCHDWORD(pmhdr16->dwFlags);
+ lpmhdr->lpNext = (PMIDIHDR)FETCHDWORD(pmhdr16->lpNext);
+ lpmhdr->reserved = FETCHDWORD(pmhdr16->reserved);
+
+ return pmhdr16;
+}
+
+/**********************************************************************\
+* Thunks a MIDIHDR structure from 32 bit to 16 bit space.
+*
+* Used by:
+* midiOutLongMsg
+* midiInAddBuffer
+* midiOutPrepareHdr
+* midiOutUnprepareHdr
+* midiInPrepareHdr
+* midiInUnprepareHdr
+*
+\**********************************************************************/
+VOID putmidihdr16 (VPMIDIHDR16 vpmhdr, LPMIDIHDR lpmhdr)
+{
+ register PMIDIHDR16 pmhdr16;
+
+ MMGETOPTPTR(vpmhdr, sizeof(MIDIHDR16), pmhdr16);
+ if ( pmhdr16 == NULL ) {
+ dprintf1(( "putmidihdr MMGETOPTPTR returned a NULL pointer" ));
+ return;
+ }
+
+ STOREDWORD(pmhdr16->dwBufferLength, lpmhdr->dwBufferLength);
+ STOREDWORD(pmhdr16->dwBytesRecorded, lpmhdr->dwBytesRecorded);
+ STOREDWORD(pmhdr16->dwUser, lpmhdr->dwUser);
+ STOREDWORD(pmhdr16->dwFlags, lpmhdr->dwFlags);
+ STOREDWORD(pmhdr16->lpNext, lpmhdr->lpNext);
+ STOREDWORD(pmhdr16->reserved, lpmhdr->reserved);
+
+ FLUSHVDMPTR(vpmhdr, sizeof(MIDIHDR16), pmhdr16);
+ FREEVDMPTR(pmhdr16);
+}
+
+
+/**********************************************************************\
+ * Thunks an AUXCAPS structure from 32 bit back to 16 bit space.
+ *
+ * Used by:
+ * auxGetDevCaps
+ *
+ * Remember that the ->vDriverVersion is a WORD in 16bit land and a UINT in
+ * 32 bit. This applies to WAVEIN/OUTCAPS, MIDIIN/OUTCAPS and AUXCAPS.
+ *
+\**********************************************************************/
+ULONG putauxcaps16 (VPAUXCAPS16 vpauxc, LPAUXCAPS lpauxc, UINT uSize)
+{
+ INT i;
+ AUXCAPS16 Temp;
+ PAUXCAPS16 pauxc16;
+
+ /*
+ ** Just in case the app specified a NULL pointer. We have already
+ ** validated that uSize is not zero.
+ */
+
+ MMGETOPTPTR(vpauxc, min(uSize, sizeof(AUXCAPS16)), pauxc16);
+ if ( pauxc16 == NULL ) {
+ dprintf1(( "putauxcaps16 MMGETOPTPTR returned a NULL pointer" ));
+ return MMSYSERR_INVALPARAM;
+ }
+
+ STOREWORD(Temp.wMid, lpauxc->wMid);
+ STOREWORD(Temp.wPid, lpauxc->wPid);
+ STOREWORD(Temp.vDriverVersion, (WORD)lpauxc->vDriverVersion);
+
+ /*
+ ** The product name string should be null terminated,
+ ** but we want the whole string anyway, so copy the whole
+ ** MAXPNAMELEN bytes.
+ */
+
+ i = 0;
+ while (i < MAXPNAMELEN) {
+ Temp.szPname[i] = lpauxc->szPname[i++];
+ }
+
+ STOREWORD(Temp.wTechnology, lpauxc->wTechnology);
+ STOREDWORD(Temp.dwSupport, lpauxc->dwSupport);
+
+ RtlCopyMemory( (LPVOID)pauxc16, &Temp, min(uSize, sizeof(AUXCAPS16)) );
+
+ FLUSHVDMPTR(vpauxc, min(uSize, sizeof(AUXCAPS16)), pauxc16);
+ FREEVDMPTR(pauxc16);
+ return MMSYSERR_NOERROR;
+}
+
+/**********************************************************************\
+ * Thunks a TIMECAPS structure from 32 bit back to 16 bit space.
+ *
+ * Used by:
+ * timeGetDevCaps
+ *
+\**********************************************************************/
+ULONG puttimecaps16(VPTIMECAPS16 vptimec, LPTIMECAPS lptimec, UINT uSize)
+{
+ PTIMECAPS16 ptimec16;
+ TIMECAPS16 Temp;
+
+ /*
+ ** Just in case the app specified a NULL pointer. We have already
+ ** validated that uSize is not zero.
+ */
+
+ MMGETOPTPTR(vptimec, min(uSize, sizeof(TIMECAPS16)), ptimec16);
+ if ( ptimec16 == NULL ) {
+ dprintf1(( "puttimecaps16 MMGETOPTPTR returned a NULL pointer" ));
+ return MMSYSERR_INVALPARAM;
+ }
+
+ //
+ // Under NT, the minimum time period is about 15ms. But Win3.1 on a 386
+ // always returns 1ms. Encarta doesn't even bother testing the
+ // CD-ROM's speed if the minimum period is > 2ms, it just assumes
+ // it is too slow. So here we lie to WOW apps and always tell
+ // them 1ms just like Win3.1.
+ // John Vert (jvert) 17-Jun-1993
+ //
+ STOREWORD( Temp.wPeriodMin, 1 );
+
+ /*
+ ** In windows 3.1 the wPeriodMax value is 0xFFFF which is the
+ ** max value you can store in a word. In windows NT the
+ ** wPeriodMax is 0xF4240 (1000 seconds).
+ **
+ ** If we just cast the 32 bit value down to a 16bit value we
+ ** end up with 0x4240 which very small compared to real 32 bit
+ ** value.
+ **
+ ** Therefore I will take the minimum of wPeriodMax and 0xFFFF
+ ** that way will should remain consistant with Win 3.1 if
+ ** wPeriodMax is greater than 0xFFFF.
+ */
+ STOREWORD(Temp.wPeriodMax, (WORD)min( 0xFFFF, lptimec->wPeriodMax) );
+
+ RtlCopyMemory( (LPVOID)ptimec16, &Temp, min(uSize, sizeof(TIMECAPS16)) );
+
+ FLUSHVDMPTR(vptimec, min(uSize, sizeof(TIMECAPS16)), ptimec16);
+ FREEVDMPTR(ptimec16);
+ return MMSYSERR_NOERROR;
+}
+
+
+
+
+/**********************************************************************\
+ * Thunks a MIDIINCAPS structure from 32 bit back to 16 bit space.
+ *
+ * Used by:
+ * midiInGetDevCaps
+ *
+ * OK - heres the scoop:
+ *
+ * Robin observed that it is valid (in theory) to copy back more bytes than
+ * JUST those contained in the MIDIINCAPS16 structure...
+ * Unfortunately that would probably blow this lot clean out of the water, so
+ * we aren't going to worry about that possibility for now.
+ * We will thunk the ENTIRE structure (not least 'cos we ALWAYS request it in
+ * the 32 bit call), then copy the required number, <= sizeof(MIDIINCAPS16)
+ * back to the 16 bit app.
+ *
+ * pTemp is the pointer to our local copy of the complete MIDIOUTCAPS16
+\**********************************************************************/
+ULONG putmidiincaps16 (VPMIDIINCAPS16 vpmic, LPMIDIINCAPS lpmic, UINT uSize)
+{
+
+ INT i;
+ MIDIINCAPS16 Temp;
+ PMIDIINCAPS16 pmic16;
+
+ /*
+ ** Just in case the app specified a NULL pointer. We have already
+ ** validated that uSize is not zero.
+ */
+
+ MMGETOPTPTR(vpmic, min(uSize, sizeof(MIDIINCAPS16)), pmic16);
+ if ( pmic16 == NULL ) {
+ dprintf1(( "putmidiincaps16 MMGETOPTPTR returned a NULL pointer" ));
+ return MMSYSERR_INVALPARAM;
+ }
+
+ STOREWORD(Temp.wMid, lpmic->wMid);
+ STOREWORD(Temp.wPid, lpmic->wPid);
+ STOREWORD(Temp.vDriverVersion, (WORD)lpmic->vDriverVersion);
+
+ /*
+ ** The product name string should be null terminated, but we want the whole
+ ** string anyway, so copy the whole MAXPNAMELEN bytes.
+ */
+ i = 0;
+ while (i < MAXPNAMELEN) {
+ Temp.szPname[i] = lpmic->szPname[i++];
+ }
+
+ RtlCopyMemory( (LPVOID)pmic16, &Temp, min(uSize, sizeof(MIDIINCAPS16)) );
+
+ FLUSHVDMPTR(vpmic, min(uSize, sizeof(MIDIINCAPS16)), pmic16);
+ FREEVDMPTR(pmic16);
+ return MMSYSERR_NOERROR;
+}
+
+
+
+/**********************************************************************\
+ * Thunks a MIDIOUTCAPS structure from 32 bit back to 16 bit space.
+ *
+ *
+ * OK - heres the scoop:
+ *
+ * Robin observed that it is valid (in theory) to copy back more bytes than
+ * JUST those contained in the MIDIOUTCAPS16 structure...
+ * Unfortunately that would probably blow this lot clean out of the water, so
+ * we aren't going to worry about that possibility for now.
+ * We will thunk the ENTIRE structure (not least 'cos we ALWAYS request it in
+ * the 32 bit call), then copy the required number, <= sizeof(MIDIOUTCAPS16)
+ * back to the 16 bit app.
+ *
+ * pTemp is the pointer to our local copy of the complete MIDIOUTCAPS16
+ *
+ * Used by:
+ * midiOutGetDevCaps
+ *
+\**********************************************************************/
+ULONG putmidioutcaps16 (VPMIDIOUTCAPS16 vpmoc, LPMIDIOUTCAPS lpmoc, UINT uSize)
+{
+
+ INT i;
+ MIDIOUTCAPS16 Temp;
+ PMIDIOUTCAPS16 pmoc16;
+
+ /*
+ ** Just in case the app specified a NULL pointer. We have already
+ ** validated that uSize is not zero.
+ */
+
+ MMGETOPTPTR(vpmoc, min(uSize, sizeof(MIDIINCAPS16)), pmoc16);
+ if ( pmoc16 == NULL ) {
+ dprintf1(( "putmidioutcaps16 MMGETOPTPTR returned a NULL pointer" ));
+ return MMSYSERR_INVALPARAM;
+ }
+
+ STOREWORD(Temp.wMid, lpmoc->wMid);
+ STOREWORD(Temp.wPid, lpmoc->wPid);
+ STOREWORD(Temp.vDriverVersion, (WORD)lpmoc->vDriverVersion);
+
+ /*
+ ** The product name string should be null terminated, but we want the whole
+ ** string anyway, so copy the whole MAXPNAMELEN bytes.
+ */
+ i = 0;
+ while (i < MAXPNAMELEN) {
+ Temp.szPname[i] = lpmoc->szPname[i++];
+ }
+
+ STOREWORD(Temp.wTechnology, lpmoc->wTechnology);
+ STOREWORD(Temp.wVoices, lpmoc->wVoices);
+ STOREWORD(Temp.wNotes, lpmoc->wNotes);
+ STOREWORD(Temp.wChannelMask, lpmoc->wChannelMask);
+ STOREDWORD(Temp.dwSupport, lpmoc->dwSupport);
+
+ RtlCopyMemory( (LPVOID)pmoc16, &Temp, min(uSize, sizeof(MIDIOUTCAPS16)) );
+
+ FLUSHVDMPTR(vpmoc, min(uSize, sizeof(MIDIOUTCAPS16)), pmoc16);
+ FREEVDMPTR(pmoc16);
+ return MMSYSERR_NOERROR;
+}
+
+
+
+
+/**********************************************************************\
+ * Thunks a JOYCAPS structure from 32 bit back to 16 bit space.
+ *
+ * Used by:
+ * joyGetDevCaps
+ *
+\**********************************************************************/
+ULONG putjoycaps16 (VPJOYCAPS16 vpjoyc, LPJOYCAPS lpjoyc, UINT uSize)
+{
+ INT i;
+ JOYCAPS16 Temp;
+ PJOYCAPS16 pjoyc16;
+
+ /*
+ ** Just in case the app specified a NULL pointer. We have already
+ ** validated that uSize is not zero.
+ */
+
+ MMGETOPTPTR(vpjoyc, min(uSize, sizeof(JOYCAPS16)), pjoyc16);
+ if ( pjoyc16 == NULL ) {
+ dprintf1(( "putjoycaps16 MMGETOPTPTR returned a NULL pointer" ));
+ return JOYERR_PARMS;
+ }
+
+ STOREWORD(Temp.wMid, lpjoyc->wMid);
+ STOREWORD(Temp.wPid, lpjoyc->wPid);
+
+ /*
+ ** The product name string should be null terminated,
+ ** but we want the whole string anyway, so copy the
+ ** whole MAXPNAMELEN bytes.
+ */
+
+ i = 0;
+ while (i < MAXPNAMELEN) {
+ Temp.szPname[i] = lpjoyc->szPname[i++];
+ }
+
+ STOREWORD(Temp.wXmin, lpjoyc->wXmin);
+ STOREWORD(Temp.wXmax, lpjoyc->wXmax);
+ STOREWORD(Temp.wYmin, lpjoyc->wYmin);
+ STOREWORD(Temp.wYmax, lpjoyc->wYmax);
+ STOREWORD(Temp.wZmin, lpjoyc->wZmin);
+ STOREWORD(Temp.wZmax, lpjoyc->wZmax);
+ STOREWORD(Temp.wNumButtons, lpjoyc->wNumButtons);
+ STOREWORD(Temp.wPeriodMin, lpjoyc->wPeriodMin);
+ STOREWORD(Temp.wPeriodMax, lpjoyc->wPeriodMax);
+
+ RtlCopyMemory( (LPVOID)pjoyc16, &Temp, min(uSize, sizeof(JOYCAPS16)) );
+
+ FLUSHVDMPTR(vpjoyc, min(uSize, sizeof(JOYCAPS16) ), pjoyc16);
+ FREEVDMPTR(pjoyc16);
+ return JOYERR_NOERROR;
+}
+
+
+/**********************************************************************\
+ * Thunks a JOYINFO structure from 32 bit back to 16 bit space.
+ *
+ * Used by:
+ * joyGetPos
+ *
+\**********************************************************************/
+ULONG putjoyinfo16 (VPJOYINFO16 vpjoyi, LPJOYINFO lpjoyi)
+{
+ PJOYINFO16 pjoyi16;
+
+ /*
+ ** Protect against NULL pointers
+ */
+
+ MMGETOPTPTR(vpjoyi, sizeof(JOYINFO16), pjoyi16);
+ if ( pjoyi16 == NULL ) {
+ dprintf1(( "putjoyinfo16 MMGETOPTPTR returned a NULL pointer" ));
+ return JOYERR_PARMS;
+ }
+
+ STOREWORD(pjoyi16->wXpos, lpjoyi->wXpos);
+ STOREWORD(pjoyi16->wYpos, lpjoyi->wYpos);
+ STOREWORD(pjoyi16->wZpos, lpjoyi->wZpos);
+ STOREWORD(pjoyi16->wButtons, lpjoyi->wButtons);
+
+ FLUSHVDMPTR(vpjoyi, sizeof(JOYINFO16), pjoyi16);
+ FREEVDMPTR(pjoyi16);
+ return JOYERR_NOERROR;
+}
+#endif
diff --git a/private/mvdm/wow32/wmmstruc.h b/private/mvdm/wow32/wmmstruc.h
new file mode 100644
index 000000000..58d6f3533
--- /dev/null
+++ b/private/mvdm/wow32/wmmstruc.h
@@ -0,0 +1,146 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMMSTRUC.H
+ * WOW32 16-bit MultiMedia structure conversion support
+ *
+ * History:
+ * Created 13-Feb-1992 by Mike Tricker (miketri) after jeffpar
+ *
+--*/
+
+
+/*++
+
+ Hack to make the code work with current MIPS compiler, whereby the compiler
+ can't work out the correct size of a MMTIME16 structure.
+
+--*/
+#define MIPS_COMPILER_PACKING_BUG
+
+/**********************************************************************\
+*
+* The following macros are used to set or clear the done bit in a
+* 16 bit wave|midi header structure.
+*
+\**********************************************************************/
+#define COPY_WAVEOUTHDR16_FLAGS( x, y ) \
+{ \
+ PWAVEHDR16 pWavHdr; \
+ DWORD dw; \
+ \
+ pWavHdr = (x); \
+ dw = (y).dwFlags; \
+ STOREDWORD( pWavHdr->dwFlags, dw ); \
+}
+
+
+#define COPY_MIDIOUTHDR16_FLAGS( x, y ) \
+{ \
+ PMIDIHDR16 pMidHdr; \
+ DWORD dw; \
+ \
+ pMidHdr = (x); \
+ dw = (y).dwFlags; \
+ STOREDWORD( pMidHdr->dwFlags, dw ); \
+}
+
+#define COPY_WAVEINHDR16_FLAGS( x, y ) \
+{ \
+ PWAVEHDR16 pWavHdr; \
+ DWORD dw; \
+ \
+ pWavHdr = (x); \
+ dw = (y).dwFlags; \
+ STOREDWORD( pWavHdr->dwFlags, dw ); \
+ dw = (y).dwBytesRecorded; \
+ STOREDWORD( pWavHdr->dwBytesRecorded, dw ); \
+}
+
+
+#define COPY_MIDIINHDR16_FLAGS( x, y ) \
+{ \
+ PMIDIHDR16 pMidHdr; \
+ DWORD dw; \
+ \
+ pMidHdr = (x); \
+ dw = (y).dwFlags; \
+ STOREDWORD( pMidHdr->dwFlags, dw ); \
+ dw = (y).dwBytesRecorded; \
+ STOREDWORD( pMidHdr->dwBytesRecorded, dw ); \
+}
+
+
+/*++
+
+ Call definitions
+
+--*/
+
+#define GETMMTIME16(vp,lp) getmmtime16(FETCHDWORD(vp),lp)
+#define GETWAVEHDR16(vp,lp) getwavehdr16(FETCHDWORD(vp), lp)
+#define GETMIDIHDR16(vp,lp) getmidihdr16(FETCHDWORD(vp), lp)
+
+#define PUTMMTIME16(vp,lp) putmmtime16(FETCHDWORD(vp),lp)
+#define PUTWAVEHDR16(vp,lp) putwavehdr16(FETCHDWORD(vp), lp)
+#define PUTWAVEFORMAT16(vp,lp) putwaveformat16(FETCHDWORD(vp), lp)
+#define PUTWAVEOUTCAPS16(vp,lp,c) putwaveoutcaps16(FETCHDWORD(vp), lp, c)
+#define PUTWAVEINCAPS16(vp,lp,c) putwaveincaps16(FETCHDWORD(vp), lp, c)
+#define PUTMIDIHDR16(vp,lp) putmidihdr16(FETCHDWORD(vp), lp)
+#define PUTAUXCAPS16(vp,lp,c) putauxcaps16(FETCHDWORD(vp), lp, c)
+#define PUTTIMECAPS16(vp,lp,c) puttimecaps16(FETCHDWORD(vp), lp, c)
+#define PUTMIDIINCAPS16(vp,lp,c) putmidiincaps16(FETCHDWORD(vp), lp, c)
+#define PUTMIDIOUTCAPS16(vp,lp,c) putmidioutcaps16(FETCHDWORD(vp), lp, c)
+#define PUTJOYCAPS16(vp,lp,c) putjoycaps16(FETCHDWORD(vp), lp, c)
+#define PUTJOYINFO16(vp,lp) putjoyinfo16(FETCHDWORD(vp), lp)
+
+#ifndef DEBUG
+#define FREEMMTIME(p)
+#define FREEWAVEHDR(p)
+#define FREEWAVEOUTCAPS(p)
+#define FREEWAVEINCAPS(p)
+#define FREEMIDIHDR(p)
+#define FREEAUXCAPS(p)
+#define FREETIMECAPS(p)
+#define FREEMIDIINCAPS(p)
+#define FREEMIDIOUTCAPS(p)
+#define FREEJOYCAPS(p)
+#define FREEJOYINFO(p)
+#else
+#define FREEMMTIME(p) p=NULL
+#define FREEWAVEHDR(p) p=NULL
+#define FREEWAVEOUTCAPS(p) p=NULL
+#define FREEWAVEINCAPS(p) p=NULL
+#define FREEMIDIHDR(p) p=NULL
+#define FREEAUXCAPS(p) p=NULL
+#define FREETIMECAPS(p) p=NULL
+#define FREEMIDIINCAPS(p) p=NULL
+#define FREEMIDIOUTCAPS(p) p=NULL
+#define FREEJOYCAPS(p) p=NULL
+#define FREEJOYINFO(p) p=NULL
+#endif
+
+/*++
+
+ Function prototypes
+
+--*/
+PWAVEHDR16 getwavehdr16(VPWAVEHDR16 vpwhdr, LPWAVEHDR lpwhdr);
+VOID putwavehdr16(VPWAVEHDR16 vpwhdr, LPWAVEHDR lpwhdr);
+
+PMIDIHDR16 getmidihdr16(VPMIDIHDR16 vpmhdr, LPMIDIHDR lpmhdr);
+VOID putmidihdr16(VPMIDIHDR16 vpmhdr, LPMIDIHDR lpmhdr);
+
+ULONG getmmtime16 (VPMMTIME16 vpmmt, LPMMTIME lpmmt);
+ULONG putmmtime16 (VPMMTIME16 vpmmt, LPMMTIME lpmmt);
+ULONG putwaveoutcaps16 (VPWAVEOUTCAPS16 vpwoc, LPWAVEOUTCAPS lpwoc, UINT uSize);
+ULONG putwaveincaps16 (VPWAVEINCAPS16 vpwic, LPWAVEINCAPS lpwic, UINT uSize);
+ULONG putauxcaps16 (VPAUXCAPS16 vpauxc, LPAUXCAPS lpauxc, UINT uSize);
+ULONG puttimecaps16 (VPTIMECAPS16 vptimec, LPTIMECAPS lptimec, UINT uSize);
+ULONG putmidiincaps16 (VPMIDIINCAPS16 vpmic, LPMIDIINCAPS lpmic, UINT uSize);
+ULONG putmidioutcaps16 (VPMIDIOUTCAPS16 vpmoc, LPMIDIOUTCAPS lpmoc, UINT uSize);
+ULONG putjoycaps16 (VPJOYCAPS16 vpjoyc, LPJOYCAPS lpjoyc, UINT uSize);
+ULONG putjoyinfo16 (VPJOYINFO16 vpjoyi, LPJOYINFO lpjoyi);
diff --git a/private/mvdm/wow32/wmmtbl.h b/private/mvdm/wow32/wmmtbl.h
new file mode 100644
index 000000000..395d76cc7
--- /dev/null
+++ b/private/mvdm/wow32/wmmtbl.h
@@ -0,0 +1,23 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMMTBL.H
+ * WOW32 16-bit MultiMedia API tables
+ *
+ * History:
+ * Created 21-Jan-1992 by Mike Tricker (miketri), after jeffpar
+--*/
+
+
+
+/* MMEDIA dispatch table
+ */
+extern W32 aw32MMED[];
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iMMEDMax;
+#endif
diff --git a/private/mvdm/wow32/wmmtbl2.h b/private/mvdm/wow32/wmmtbl2.h
new file mode 100644
index 000000000..cff8ec2a6
--- /dev/null
+++ b/private/mvdm/wow32/wmmtbl2.h
@@ -0,0 +1,18 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMMTBL2.h
+ * WOW32 16-bit MultiMedia API tables
+ *
+ * History:
+ * Created 21-Jan-1992 by Mike Tricker (miketri], after jeffpar
+ * Gutted 21-Feb-1995 by Dave Hart, after anonymous SYSUK1/SYSUK8
+--*/
+
+
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_MMEDIA, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_MMEDIA, 0)},
+ {W32FUN(WMM32CallProc32, "MMCallProc32", MOD_MMEDIA, sizeof(MMCALLPROC3216))},
diff --git a/private/mvdm/wow32/wmsg16.c b/private/mvdm/wow32/wmsg16.c
new file mode 100644
index 000000000..2ea8462c4
--- /dev/null
+++ b/private/mvdm/wow32/wmsg16.c
@@ -0,0 +1,1534 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSG16.C
+ * WOW32 16-bit message thunks
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+ * Changed 12-May-1992 by Mike Tricker (miketri) to add MultiMedia (un)thunks and messages
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wmtbl32.h"
+
+MODNAME(wmsg16.c);
+
+#define WIN30_STM_SETICON 0x400
+#define WIN30_STM_GETICON 0x401
+
+#define WIN30_EM_LINESCROLL 0x406 // WM_USER+6
+#define WIN30_EM_GETTHUMB 0x40e // WM_USER+14
+
+// See WARNING below!
+LPFNTHUNKMSG16 apfnThunkMsg16[] = {
+ ThunkWMMsg16, // WOWCLASS_WIN16
+ ThunkWMMsg16, // WOWCLASS_WIN16
+ ThunkBMMsg16, // WOWCLASS_BUTTON
+ ThunkCBMsg16, // WOWCLASS_COMBOBOX
+ ThunkEMMsg16, // WOWCLASS_EDIT
+ ThunkLBMsg16, // WOWCLASS_LISTBOX
+ ThunkWMMsg16, // WOWCLASS_MDICLIENT
+ ThunkSBMMsg16, // WOWCLASS_SCROLLBAR
+ ThunkSTMsg16, // WOWCLASS_STATIC (presumably no messages generated)
+ ThunkWMMsg16, // WOWCLASS_DESKTOP
+ ThunkWMMsg16, // WOWCLASS_DIALOG
+ ThunkWMMsg16, // WOWCLASS_ICONTITLE
+ ThunkMNMsg16, // WOWCLASS_MENU
+ ThunkWMMsg16, // WOWCLASS_SWITCHWND
+ ThunkLBMsg16 // WOWCLASS_COMBOLBOX
+};
+// See WARNING below!
+LPFNUNTHUNKMSG16 apfnUnThunkMsg16[] = {
+ UnThunkWMMsg16, // WOWCLASS_WIN16
+ UnThunkWMMsg16, // WOWCLASS_WIN16
+ UnThunkBMMsg16, // WOWCLASS_BUTTON
+ UnThunkCBMsg16, // WOWCLASS_COMBOBOX
+ UnThunkEMMsg16, // WOWCLASS_EDIT
+ UnThunkLBMsg16, // WOWCLASS_LISTBOX
+ UnThunkWMMsg16, // WOWCLASS_MDICLIENT
+ UnThunkSBMMsg16,// WOWCLASS_SCROLLBAR
+ UnThunkSTMsg16, // WOWCLASS_STATIC (presumably no messages generated)
+ UnThunkWMMsg16, // WOWCLASS_DESKTOP
+ UnThunkWMMsg16, // WOWCLASS_DIALOG
+ UnThunkWMMsg16, // WOWCLASS_ICONTITLE
+ UnThunkMNMsg16, // WOWCLASS_MENU
+ UnThunkWMMsg16, // WOWCLASS_SWITCHWND
+ UnThunkLBMsg16 // WOWCLASS_COMBOLBOX
+};
+//
+// WARNING! The above sequence and values must be maintained otherwise the
+// #defines in WALIAS.H must be changed. Same goes for table in WALIAS.C.
+//
+
+
+#ifdef DEBUG
+
+//
+// This function returns a pointer to a static buffer containing a generated
+// string. If the function is called twice and generates a string in both
+// cases, the second call will overwrite the buffer of the first call. If
+// this becomes a problem for us it would be easy to use an array of N
+// static buffers which are cycled through.
+//
+
+PSZ GetWMMsgName(UINT uMsg)
+{
+ static char szStaticBuf[128];
+ PSZ pszMsgName;
+
+ uMsg = LOWORD(uMsg);
+
+ pszMsgName = (uMsg < (unsigned)iMsgMax) ? aw32Msg[uMsg].lpszW32 : NULL;
+
+ if (!pszMsgName) {
+
+ if (uMsg < WM_USER) {
+ sprintf(szStaticBuf, "(Unknown 0x%x)", uMsg);
+ } else if (uMsg < 0xc000) {
+ sprintf(szStaticBuf, "(WM_USER+0x%x)", uMsg - WM_USER);
+ } else {
+ char szAtomName[100];
+
+ if ( ! GlobalGetAtomName((ATOM)uMsg, szAtomName, sizeof szAtomName) &&
+ ! GetAtomName((ATOM)uMsg, szAtomName, sizeof szAtomName) ) {
+ szAtomName[0] = 0;
+ }
+
+ sprintf(szStaticBuf, "(Atom 0x%x '%s')", uMsg, szAtomName);
+ }
+
+ pszMsgName = szStaticBuf;
+ }
+
+ return pszMsgName;
+}
+
+#endif
+
+
+// WARNING: This function may cause 16-bit memory movement, invalidating
+// flat pointers.
+HWND FASTCALL ThunkMsg16(LPMSGPARAMEX lpmpex)
+{
+ BOOL f;
+ register PWW pww = NULL;
+ INT iClass;
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ lpmpex->uMsg = wMsg;
+ lpmpex->uParam = INT32(lpmpex->Parm16.WndProc.wParam); // Sign extend
+ lpmpex->lParam =lpmpex->Parm16.WndProc.lParam;
+ lpmpex->hwnd = HWND32(lpmpex->Parm16.WndProc.hwnd);
+
+
+ if (wMsg < WM_USER) {
+ iClass = (aw32Msg[wMsg].lpfnM32 == WM32NoThunking) ?
+ WOWCLASS_NOTHUNK : WOWCLASS_WIN16;
+ }
+ else {
+ pww = FindPWW(lpmpex->hwnd, WOWCLASS_UNKNOWN);
+ if (pww) {
+ iClass = (lpmpex->iMsgThunkClass) ?
+ lpmpex->iMsgThunkClass : pww->iClass;
+ }
+ else {
+ iClass = 0;
+ }
+ }
+
+ lpmpex->iClass = iClass;
+ if (iClass == WOWCLASS_NOTHUNK) {
+ f = TRUE;
+ }
+ else {
+ lpmpex->lpfnUnThunk16 = apfnUnThunkMsg16[iClass]; // for optimization
+ lpmpex->pww = pww;
+ WOW32ASSERT(iClass <= NUMEL(apfnThunkMsg16));
+ f = (apfnThunkMsg16[iClass])(lpmpex);
+ }
+
+ WOW32ASSERTMSG(f, " WARNING Will Robinson: 16-bit message thunk failure\n");
+
+ return (f) ? lpmpex->hwnd : (HWND)NULL;
+
+}
+
+VOID FASTCALL UnThunkMsg16(LPMSGPARAMEX lpmpex)
+{
+ if (MSG16NEEDSTHUNKING(lpmpex)) {
+ (lpmpex->lpfnUnThunk16)(lpmpex);
+ }
+ return;
+}
+
+
+BOOL FASTCALL ThunkWMMsg16(LPMSGPARAMEX lpmpex)
+{
+
+ WORD wParam = lpmpex->Parm16.WndProc.wParam;
+ LONG lParam = lpmpex->Parm16.WndProc.lParam;
+ PLONG plParamNew = &lpmpex->lParam;
+
+ LOGDEBUG(6,(" Thunking 16-bit window message %s(%04x)\n", (LPSZ)GetWMMsgName(lpmpex->Parm16.WndProc.wMsg), lpmpex->Parm16.WndProc.wMsg));
+
+ switch(lpmpex->Parm16.WndProc.wMsg) {
+
+ case WM_ACTIVATE: // 006h, <SLPre, LS>
+ case WM_VKEYTOITEM: // 02Eh, <SLPre,SLPost,LS>
+ case WM_CHARTOITEM: // 02Fh, <SLPre,SLPost,LS>
+ case WM_NCACTIVATE: // 086h, <SLPre, LS>
+ case WM_BEGINDRAG: // 22Ch, <SLPre, LS>
+ HIW(lpmpex->uParam) = HIWORD(lParam);
+ *plParamNew = (LONG)HWND32(LOWORD(lParam));
+ break;
+
+ case WM_COMMAND: // 111h, <SLPre, LS>
+ {
+ LONG lParamNew;
+
+ /*
+ ** Some messages cannot be translated into 32-bit messages. If they
+ ** cannot, we leave the lParam as it is, else we replace lParam with
+ ** the correct HWND.
+ */
+
+ HIW(lpmpex->uParam) = HIWORD(lParam);
+
+ lParamNew = FULLHWND32(LOWORD(lParam));
+ if (lParamNew) {
+ *plParamNew = lParamNew;
+ }
+
+ }
+ break;
+
+ case WM_SETFONT:
+ lpmpex->uParam = (LONG) HFONT32(wParam);
+ break;
+
+ case WM_SETTEXT: // 00Ch, <SLPre,SLPost >
+ case WM_WININICHANGE: // 01Ah, <SLPre, LS>
+ case WM_DEVMODECHANGE: // 01Bh, <SLPre, LS>
+ {
+ LONG lParamMap;
+
+ GETPSZPTR(lParam, (LPSZ)lParamMap);
+ *plParamNew = (LONG)AddParamMap(lParamMap, lParam);
+ if (lParamMap != *plParamNew) {
+ FREEPSZPTR((LPSZ)lParamMap);
+ }
+
+ }
+ break;
+
+ case WM_ACTIVATEAPP: // 01Ch
+ if (lParam) {
+ *plParamNew = (LONG)HTASK32(LOWORD(lParam));
+ }
+ break;
+
+ case WM_GETTEXT: // 00Dh, <SLPre,SLPost,LS>
+ //
+ // SDM (standard dialog manager) used by WinRaid among others
+ // has a bug where it claims it has 0x7fff bytes available
+ // in the buffer on WM_GETTEXT, when in fact it has much less.
+ // Below we intentionally defeat the limit check if the
+ // sender claims 0x7fff bytes as the size. This is done on
+ // the checked build only since the free build doesn't perform
+ // limit checks.
+ // DaveHart/ChandanC 9-Nov-93
+ //
+#ifdef DEBUG
+ GETVDMPTR(lParam, (wParam == 0x7fff) ? 0 : wParam, (LPSZ)*plParamNew);
+#else
+ GETVDMPTR(lParam, wParam, (LPSZ)*plParamNew);
+#endif
+ break;
+
+ case WM_GETMINMAXINFO: // 024h, <SLPre,SLPost,LS>,MINMAXINFOSTRUCT
+ *plParamNew = (LONG)lpmpex->MsgBuffer;
+ ThunkWMGetMinMaxInfo16(lParam, (LPPOINT *)plParamNew);
+ break;
+
+ case WM_MDIGETACTIVE:
+ //
+ // not extremely important if it fails
+ //
+ *plParamNew = (LONG)&(lpmpex->MsgBuffer[0].msg.lParam);
+ lpmpex->uParam = 0;
+ break;
+
+ case WM_GETDLGCODE:
+ // NTRaid1 #9949 - Excel passes ptr to msg struct in lparam
+ // Approach 3.1 also does this a-craigj
+ if (lParam) {
+ *plParamNew = (LONG)lpmpex->MsgBuffer;
+ W32CopyMsgStruct( (VPMSG16)lParam,(LPMSG)*plParamNew, TRUE);
+ }
+ break;
+
+ case WM_NEXTDLGCTL: // 028h
+ if (lParam)
+ lpmpex->uParam = (UINT) HWND32(wParam);
+ break;
+
+ case WM_DRAWITEM: // 02Bh notused, DRAWITEMSTRUCT
+ if (lParam) {
+ *plParamNew = (LONG)lpmpex->MsgBuffer;
+ getdrawitem16((VPDRAWITEMSTRUCT16)lParam, (PDRAWITEMSTRUCT)*plParamNew);
+ }
+ break;
+
+ case WM_MEASUREITEM: // 02Ch notused, MEASUREITEMSTRUCT
+ if (lParam) {
+ *plParamNew = (LONG)lpmpex->MsgBuffer;
+ getmeasureitem16((VPMEASUREITEMSTRUCT16)lParam, (PMEASUREITEMSTRUCT)*plParamNew, lpmpex->Parm16.WndProc.hwnd);
+ }
+ break;
+
+ case WM_DELETEITEM: // 02Dh notused, DELETEITEMSTRUCT
+ if (lParam) {
+ *plParamNew = (LONG)lpmpex->MsgBuffer;
+ getdeleteitem16((VPDELETEITEMSTRUCT16)lParam, (PDELETEITEMSTRUCT)*plParamNew);
+ }
+ break;
+
+ case WM_COMPAREITEM: // 039h
+ if (lParam) {
+ *plParamNew = (LONG)lpmpex->MsgBuffer;
+ getcompareitem16((VPCOMPAREITEMSTRUCT16)lParam, (PCOMPAREITEMSTRUCT)*plParamNew);
+ }
+ break;
+
+ case WM_WINHELP: // 038h private internal message
+ if (lParam) {
+ // lparam is LPHLP16, but we need only the size of data, the first word.
+ // lparam32 is LPHLP. LPHLP and LPHLP16 are identical.
+
+ PWORD16 lpT;
+ GETVDMPTR(lParam, 0, lpT);
+ if (lpT) {
+ // assert: cbData is a WORD and is the 1st field in LPHLP struct
+ WOW32ASSERT((OFFSETOF(HLP,cbData) == 0) &&
+ (sizeof(((LPHLP)NULL)->cbData) == sizeof(WORD)));
+ *plParamNew = (LONG)((*lpT > sizeof(lpmpex->MsgBuffer)) ?
+ malloc_w(*lpT) : lpmpex->MsgBuffer);
+ if (*plParamNew) {
+ RtlCopyMemory((PVOID)*plParamNew, lpT, *lpT);
+ }
+ }
+ FREEVDMPTR(lpT);
+ }
+ break;
+
+ case WM_NCCALCSIZE: // 083h, <SLPre,SLPost,LS>,RECT
+ if (lParam) {
+ *plParamNew = (LONG)lpmpex->MsgBuffer;
+ getrect16((VPRECT16)lParam, (LPRECT)*plParamNew);
+ if (wParam) {
+ PNCCALCSIZE_PARAMS16 pnc16;
+ PNCCALCSIZE_PARAMS16 lpnc16;
+ LPNCCALCSIZE_PARAMS lpnc;
+
+
+ lpnc = (LPNCCALCSIZE_PARAMS)*plParamNew;
+ pnc16 = (PNCCALCSIZE_PARAMS16)lParam;
+ getrect16((VPRECT16)(&pnc16->rgrc[1]), &lpnc->rgrc[1]);
+ getrect16((VPRECT16)(&pnc16->rgrc[2]), &lpnc->rgrc[2]);
+
+ lpnc->lppos = (LPWINDOWPOS)(lpnc+1);
+
+ GETVDMPTR( pnc16, sizeof(NCCALCSIZE_PARAMS16), lpnc16 );
+
+ getwindowpos16( (VPWINDOWPOS16)lpnc16->lppos, lpnc->lppos );
+
+ FREEVDMPTR( lpnc16 );
+ }
+ }
+ break;
+
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ *plParamNew = (LONG) HWND32(HIWORD(lParam));
+#if 0
+ if ((wParam == SB_THUMBPOSITION) || (wParam == SB_THUMBTRACK)) {
+ HIW(lpmpex->uParam) = LOWORD(lParam);
+ }
+ else if (wParam > SB_ENDSCROLL) {
+#else
+
+ //
+ // Ventura Publisher v4.1 setup program uses nPos on messages other
+ // than SB_THUMBPOSITION and SB_THUMBTRACK. it doesn't hurt to
+ // carry this word over.
+ //
+
+ if (wParam <= SB_ENDSCROLL) {
+
+ HIW(lpmpex->uParam) = LOWORD(lParam);
+
+ } else {
+#endif
+
+ // implies wParam is NOT an SB_* scrollbar code.
+ // this could be EM_GETTHUMB or EM_LINESCROLL
+
+ // expensive way would be to check for class etc. Instead we
+ // assume that wParam is one of the above EM_message and verify
+ // that it is indeed so.
+
+ if (wParam == WIN30_EM_GETTHUMB)
+ lpmpex->uParam = EM_GETTHUMB;
+ else if (wParam == WIN30_EM_LINESCROLL)
+ lpmpex->uParam = EM_LINESCROLL;
+ }
+ break;
+
+ case WM_PARENTNOTIFY:
+ if ((wParam == WM_CREATE) || (wParam == WM_DESTROY)) {
+ HIW(lpmpex->uParam) = HIWORD(lParam);
+ *plParamNew = (LONG) HWND32(LOWORD(lParam));
+ }
+ break;
+
+ case WM_MENUCHAR: // 120h
+ LOW(lpmpex->uParam) = wParam;
+ HIW(lpmpex->uParam) = LOWORD(lParam);
+ *plParamNew = (LONG) HMENU32(HIWORD(lParam));
+ break;
+
+ case WM_SETFOCUS: // 007h, <SLPre, LS>
+ case WM_KILLFOCUS: // 008h, <SLPre, LS>
+ case WM_SETCURSOR: // 020h, <SLPre, LS>
+ case WM_INITDIALOG: // 110h, <SLPre,SLPost,LS>
+ case WM_MOUSEACTIVATE: // 021h, <SLPre,SLPost,LS>
+ case WM_MDIDESTROY: // 221h, <SLPre, LS>
+ case WM_MDIRESTORE: // 223h, <SLPre, LS>
+ case WM_MDINEXT: // 224h, <SLPre, LS>
+ case WM_MDIMAXIMIZE: // 225h, <SLPre, LS>
+ case WM_VSCROLLCLIPBOARD: // 30Ah, <SLPre, LS>
+ case WM_HSCROLLCLIPBOARD: // 30Eh, <SLPre, LS>
+ case WM_PALETTECHANGED: // 311h, <SLPre, LS>
+ case WM_PALETTEISCHANGING:
+ lpmpex->uParam = (UINT)HWND32(wParam);
+ break;
+
+ case WM_DDE_REQUEST:
+ case WM_DDE_TERMINATE:
+ case WM_DDE_UNADVISE:
+ lpmpex->uParam = (UINT)FULLHWND32(wParam);
+ break;
+
+ case WM_ASKCBFORMATNAME:
+ /* BUGBUGBUG -- neither thunk or unthunk should be necessary,
+ since the system does not process this message in DefWindowProc
+ FritzS */
+ lpmpex->uParam = (UINT) wParam;
+
+ if (!(*plParamNew = (LPARAM)malloc_w(wParam))) {
+ LOGDEBUG (0, ("WOW::WMSG16: WM_ASKCBFORMAT : Couldn't allocate 32 bit memory !\n"));
+ WOW32ASSERT (FALSE);
+ return FALSE;
+ } else {
+ getstr16((VPSZ)lParam, (LPSZ)(*plParamNew), wParam);
+ }
+ break;
+
+ case WM_PAINTCLIPBOARD:
+ case WM_SIZECLIPBOARD:
+ {
+ HANDLE hMem32 = NULL;
+ VPVOID vp = 0;
+ HAND16 hMem16 = 0;
+ LPVOID lpMem32 = NULL;
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ lpmpex->uParam = (UINT) HWND32(wParam);
+
+ hMem16 = LOWORD(lParam);
+
+ vp = GlobalLock16(hMem16, NULL);
+ if (vp) {
+ hMem32 = GlobalAlloc (GMEM_DDESHARE, (wMsg == WM_SIZECLIPBOARD) ?
+ sizeof(RECT) : sizeof(PAINTSTRUCT));
+ if (hMem32) {
+ if (lpMem32 = GlobalLock(hMem32)) {
+ if (wMsg == WM_SIZECLIPBOARD) {
+ GETRECT16(vp, (LPRECT)lpMem32);
+ }
+ else {
+ getpaintstruct16(vp, (LPPAINTSTRUCT)lpMem32);
+ }
+ GlobalUnlock((HANDLE) hMem32);
+ }
+ else {
+ GlobalFree(hMem32);
+ hMem32 = NULL;
+ LOGDEBUG (0, ("WOW::WMSG16: WM_SIZE/PAINTCLIPBOARD : Couldn't lock 32 bit handle !\n"));
+ WOW32ASSERT (FALSE);
+ }
+ }
+ else {
+ LOGDEBUG (0, ("WOW::WMSG16: WM_SIZE/PAINTCLIPBOARD : Couldn't allocate memory !\n"));
+ WOW32ASSERT (FALSE);
+ }
+
+ GlobalUnlock16(hMem16);
+ }
+ else {
+ LOGDEBUG (0, ("WOW::WMSG16: WM_SIZE/PAINTCLIPBOARD : Couldn't lock 16 bit handle !\n"));
+ WOW32ASSERT (FALSE);
+ }
+
+ *plParamNew = (LONG) hMem32;
+ }
+ break;
+
+ case WM_MDIACTIVATE:
+ {
+ BOOL fHwndIsMdiChild;
+
+ if (lpmpex->iMsgThunkClass != WOWCLASS_MDICLIENT) {
+ PWW pww;
+ HWND hwnd32;
+
+ // AMIPRO sends this message to its own window. If we thunk the
+ // message the usual way, we will lose the information in
+ // wParam and won't be able to regenerate the original message
+ // when it comes back via w32win16wndproc. So the solution is
+ // to determine this case and not thunk the message at all.
+ // - nanduri
+
+ // HYPERION sends this to its own DIALOG window. Added
+ // WOWCLASS_DIALOG check. - sanfords
+
+ //
+ // Expensive checks.
+ // No thunking If hwnd16 is of WOWCLASS and NOT MDICHILD.
+ //
+
+ hwnd32 = HWND32(lpmpex->Parm16.WndProc.hwnd);
+ if (pww = (PWW)GetWindowLong(hwnd32, GWL_WOWWORDS)) {
+ if ((pww->iClass == WOWCLASS_WIN16 ||
+ pww->iClass == WOWCLASS_DIALOG)
+ && (!(pww->dwExStyle & WS_EX_MDICHILD))) {
+ lpmpex->uMsg = WM_MDIACTIVATE | WOWPRIVATEMSG;
+ break;
+ }
+
+ }
+ }
+
+
+ //
+ // see the comment in 32-16 thunk for this message.
+ //
+
+ if (lParam) {
+
+ //
+ // Corel Chart doesn't set lParam to zero.
+ // Instead HIWORD(lParam) = 0 and LOWORD(lParam) = wParam
+ // If we do the normal child window processing, focus won't
+ // change, because the wrong window handle will be in the
+ // wParam for the 32 bit message. This would not be a problem,
+ // except that win32 swapped the positions of the activate and
+ // deactivate handles for the WM_MDIACTIVATE messages sent
+ // to the child window. Under win31, the non-zero lParam is
+ // ignored.
+ //
+ if ((CURRENTPTD()->dwWOWCompatFlags & WOWCF_WMMDIACTIVATEBUG) && (HIWORD(lParam) == 0) && (wParam == LOWORD(lParam))){
+ fHwndIsMdiChild = FALSE;
+ } else {
+ fHwndIsMdiChild = TRUE;
+ }
+ }
+ else {
+ if (wParam && (lpmpex->Parm16.WndProc.hwnd == (HWND16)wParam)) {
+ fHwndIsMdiChild = TRUE;
+ }
+ else {
+ fHwndIsMdiChild = FALSE;
+ }
+
+ }
+
+ if (fHwndIsMdiChild) {
+ lpmpex->uParam = (UINT)FULLHWND32(HIWORD(lParam));
+ *plParamNew = (UINT)FULLHWND32(LOWORD(lParam));
+
+ }
+ else {
+ lpmpex->uParam = (UINT)FULLHWND32(wParam);
+ *plParamNew = (UINT)0;
+ }
+ }
+ break;
+
+ case WM_MDISETMENU: // 230h
+
+ // Refresh if wParam of WM_MDISETMENU is TRUE (the refresh flag)
+ //
+ if (wParam) {
+ lpmpex->uMsg = WM_MDIREFRESHMENU;
+ }
+ lpmpex->uParam = (UINT)HMENU32(LOWORD(lParam));
+ *plParamNew = (UINT)HMENU32(HIWORD(lParam));
+ break;
+
+ case WIN31_MM_CALCSCROLL: // 10ACh
+ if (lpmpex->iClass == WOWCLASS_MDICLIENT) {
+ lpmpex->uMsg = MM_CALCSCROLL;
+ }
+ break;
+
+ case WM_MDITILE: // 226h
+ /* if wParam contains garbage from Win3.0 apps */
+ if(wParam & ~(MDITILE_VERTICAL|MDITILE_HORIZONTAL|MDITILE_SKIPDISABLED))
+ lpmpex->uParam = MDITILE_SKIPDISABLED;
+ break;
+
+
+ case WM_MDICASCADE: // 227h
+ lpmpex->uParam = MDITILE_SKIPDISABLED;
+ break;
+
+ case WM_ERASEBKGND: // 014h, < SLPost >
+ case WM_ICONERASEBKGND: // 027h
+ lpmpex->uParam = (UINT)HDC32(wParam);
+ break;
+
+ case WM_CTLCOLOR:
+
+ // HIWORD(lParam) need not be a standard index. The app can pass any
+ // value (PowerBuilder does so. MSGolf passes this message to
+ // DefDlgProc() with HIWORD(lParam) == 62,66,67).
+ //
+ // If not in known range, leave it as WM_CTLCOLOR. There is code in
+ // xxxDefWindowProc() & xxxDefDlgProc() that recognize this & return
+ // us the value returned by the app when it processed this message.
+
+ if (HIWORD(lParam) <= (WORD)(WM_CTLCOLORSTATIC - WM_CTLCOLORMSGBOX)) {
+ lpmpex->hwnd = (HWND)FULLHWND32(GETHWND16(lpmpex->hwnd));
+ lpmpex->uMsg = WM_CTLCOLORMSGBOX + HIWORD(lParam);
+ lpmpex->uParam = (UINT)HDC32(wParam);
+ *plParamNew = (LONG)HWND32(LOWORD(lParam));
+ }
+ break;
+
+
+ case WM_SYSCOMMAND:
+ case WM_SETREDRAW: // 027h
+ lpmpex->uParam = wParam;
+ break;
+
+ case WM_INITMENU:
+ case WM_INITMENUPOPUP: // 117h
+ lpmpex->uParam = (UINT)HMENU32(wParam);
+ break;
+
+ case WM_NCCREATE:
+ case WM_CREATE:
+ {
+ register LPCREATESTRUCT lpCreateStruct;
+ register PCREATESTRUCT16 lpCreateStruct16;
+
+ if (HIWORD(lParam)) {
+
+ HWND hwnd32;
+ PWW pww = NULL;
+
+ lpCreateStruct = (LPCREATESTRUCT) lpmpex->MsgBuffer;
+ // ChandanC check the return value !!!
+
+ GETVDMPTR(lParam, sizeof(CREATESTRUCT16), lpCreateStruct16);
+
+ lpCreateStruct->lpCreateParams = (LPSTR)FETCHDWORD(lpCreateStruct16->vpCreateParams);
+ lpCreateStruct->hInstance = HMODINST32(lpCreateStruct16->hInstance);
+ lpCreateStruct->hMenu = HMENU32(lpCreateStruct16->hMenu);
+ lpCreateStruct->hwndParent = HWND32(lpCreateStruct16->hwndParent);
+ lpCreateStruct->cy = (SHORT) lpCreateStruct16->cy;
+ lpCreateStruct->cx = (SHORT) lpCreateStruct16->cx;
+ lpCreateStruct->y = (SHORT) lpCreateStruct16->y;
+ lpCreateStruct->x = (SHORT) lpCreateStruct16->x;
+ lpCreateStruct->style = lpCreateStruct16->dwStyle;
+ GETPSZPTR(lpCreateStruct16->vpszWindow, lpCreateStruct->lpszName);
+ GETPSZIDPTR(lpCreateStruct16->vpszClass, lpCreateStruct->lpszClass);
+ lpCreateStruct->dwExStyle = lpCreateStruct16->dwExStyle;
+
+ *plParamNew = (LONG) lpCreateStruct;
+
+ FREEVDMPTR(lpCreateStruct16);
+
+ hwnd32 = HWND32(lpmpex->Parm16.WndProc.hwnd);
+ pww = (PWW)GetWindowLong(hwnd32, GWL_WOWWORDS);
+ if (lpCreateStruct->lpCreateParams && pww && (pww->dwExStyle & WS_EX_MDICHILD)) {
+ FinishThunkingWMCreateMDIChild16(*plParamNew,
+ (LPMDICREATESTRUCT)(lpCreateStruct+1));
+ }
+ }
+ }
+ break;
+
+ case WM_PAINT:
+ case WM_NCPAINT:
+ // 1 is MAXREGION special code in Win 3.1
+ lpmpex->uParam = (wParam == 1) ? 1 : (UINT)HDC32(wParam);
+ break;
+
+ case WM_ENTERIDLE:
+ if ((wParam == MSGF_DIALOGBOX) || (wParam == MSGF_MENU)) {
+ *plParamNew = (LONG) HWND32(LOWORD(lParam));
+ }
+ break;
+
+ case WM_MENUSELECT:
+ // Copy menu flags
+ HIW(lpmpex->uParam) = LOWORD(lParam);
+
+ // Copy "main" menu
+ *plParamNew = (LONG) HMENU32(HIWORD(lParam));
+
+ if (LOWORD(lParam) == 0xFFFF || !(LOWORD(lParam) & MF_POPUP)) {
+ LOW(lpmpex->uParam) = wParam; // copy ID
+ } else {
+ // convert menu to index
+ LOW(lpmpex->uParam) =
+ (WORD)(pfnOut.pfnGetMenuIndex)((HMENU)*plParamNew, HMENU32(wParam));
+ }
+ break;
+
+ case WM_MDICREATE: // 220h, <SLPre,SLPost,LS>
+ *plParamNew = (LONG)lpmpex->MsgBuffer;
+ ThunkWMMDICreate16(lParam, (LPMDICREATESTRUCT *)plParamNew);
+ break;
+
+ // BUGBUG 25-Aug-91 JeffPar: Use of the Kludge variables was a temporary
+ // measure, and only works for messages sent by Win32; for any WM
+ // messages sent by 16-bit apps themselves, this will not work. Ultimately,
+ // any messages you see being thunked in wmsg32.c will need equivalent
+ // thunks here as well.
+
+
+ case WM_DDE_INITIATE:
+ lpmpex->uParam = (LONG) FULLHWND32(wParam);
+ WI32DDEAddInitiator((HAND16) wParam);
+ break;
+
+ case WM_DDE_ACK:
+ {
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+ HWND16 hwnd16 = lpmpex->Parm16.WndProc.hwnd;
+
+ lpmpex->uParam = (LONG) FULLHWND32(wParam);
+
+ if (WI32DDEInitiate((HWND16) hwnd16)) {
+ *plParamNew = lParam;
+ }
+ else {
+ HANDLE h32;
+
+ if (fWhoCalled == WOWDDE_POSTMESSAGE) {
+ if (h32 = DDEFindPair32(wParam, hwnd16, (HAND16) HIWORD(lParam))) {
+ *plParamNew = PackDDElParam(wMsg, (LONG) (DWORD) LOWORD(lParam), (LONG) h32);
+ }
+ else {
+ *plParamNew = PackDDElParam(wMsg, (LONG) (DWORD) LOWORD(lParam), (LONG) (DWORD) HIWORD(lParam));
+ }
+ }
+ else {
+ if (fThunkDDEmsg) {
+ if (h32 = DDEFindPair32(wParam, hwnd16, (HAND16) HIWORD(lParam))) {
+ *plParamNew = PackDDElParam(wMsg, (LONG) (DWORD) LOWORD(lParam), (LONG) h32);
+ }
+ else {
+ *plParamNew = PackDDElParam(wMsg, (LONG) (DWORD) LOWORD(lParam), (LONG) (DWORD) HIWORD(lParam));
+ }
+
+ }
+ else {
+ *plParamNew = W32GetHookDDEMsglParam();
+ }
+ }
+ }
+ }
+ break;
+
+ case WM_DDE_POKE:
+ {
+ DDEINFO DdeInfo;
+ HANDLE h32;
+ HWND16 hwnd16 = lpmpex->Parm16.WndProc.hwnd;
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ lpmpex->uParam = (LONG) FULLHWND32(wParam);
+
+ if (fWhoCalled == WOWDDE_POSTMESSAGE) {
+ if (h32 = DDEFindPair32(hwnd16, wParam, (HAND16) LOWORD(lParam))) {
+ DDEDeletehandle(LOWORD(lParam), h32);
+ GlobalFree(h32);
+ }
+ DdeInfo.Msg = wMsg;
+ h32 = DDECopyhData32(hwnd16, wParam, (HAND16) LOWORD(lParam), &DdeInfo);
+ // WARNING: 16-bit memory may have moved
+ DdeInfo.Flags = DDE_PACKET;
+ DdeInfo.h16 = 0;
+ DDEAddhandle(hwnd16, wParam, (HAND16)LOWORD(lParam), h32, &DdeInfo);
+ *plParamNew = PackDDElParam(wMsg, (LONG) h32, (LONG) HIWORD(lParam));
+ }
+ else {
+ if (fThunkDDEmsg) {
+ if (!(h32 = DDEFindPair32(hwnd16, wParam, (HAND16) LOWORD(lParam)))) {
+ LOGDEBUG (0, ("WOW::WMSG16: WM_DDE_POKE : Can't find h32 !\n"));
+ }
+ *plParamNew = PackDDElParam(wMsg, (LONG) h32, (LONG) HIWORD(lParam));
+ }
+ else {
+ *plParamNew = W32GetHookDDEMsglParam();
+ }
+ }
+ }
+ break;
+
+
+
+ case WM_DDE_ADVISE:
+ {
+ DDEINFO DdeInfo;
+ HANDLE h32;
+ INT cb;
+ VPVOID vp;
+ LPBYTE lpMem16;
+ LPBYTE lpMem32;
+ HWND16 hwnd16 = lpmpex->Parm16.WndProc.hwnd;
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ lpmpex->uParam = (LONG) FULLHWND32(wParam);
+
+ if (fWhoCalled == WOWDDE_POSTMESSAGE) {
+ if (h32 = DDEFindPair32(hwnd16, wParam, (HAND16) LOWORD(lParam))) {
+ DDEDeletehandle(LOWORD(lParam), h32);
+ GlobalFree(h32);
+ }
+ h32 = GlobalAlloc(GMEM_DDESHARE, sizeof(DDEADVISE));
+ if (h32 == NULL) {
+ return 0;
+ }
+ lpMem32 = GlobalLock(h32);
+ vp = GlobalLock16(LOWORD(lParam), &cb);
+ GETMISCPTR(vp, lpMem16);
+ RtlCopyMemory(lpMem32, lpMem16, sizeof(DDEADVISE));
+ FREEMISCPTR(lpMem16);
+ GlobalUnlock(h32);
+ GlobalUnlock16(LOWORD(lParam));
+ DdeInfo.Msg = wMsg;
+ DdeInfo.Format = 0;
+ DdeInfo.Flags = DDE_PACKET;
+ DdeInfo.h16 = 0;
+ DDEAddhandle(hwnd16, wParam, (HAND16)LOWORD(lParam), h32, &DdeInfo);
+ *plParamNew = PackDDElParam(wMsg, (LONG) h32, (LONG) HIWORD(lParam));
+ }
+ else {
+ if (fThunkDDEmsg) {
+ if (!(h32 = DDEFindPair32(hwnd16, wParam, (HAND16) LOWORD(lParam)))) {
+ LOGDEBUG (0, ("WOW::WMSG16: WM_DDE_ADVISE : Can't find h32 !\n"));
+ }
+ *plParamNew = PackDDElParam(wMsg, (LONG) h32, (LONG) HIWORD(lParam));
+ }
+ else {
+ *plParamNew = W32GetHookDDEMsglParam();
+ }
+ }
+ }
+ break;
+
+ case WM_DDE_DATA:
+ {
+ DDEINFO DdeInfo;
+ HANDLE h32;
+ HWND16 hwnd16 = lpmpex->Parm16.WndProc.hwnd;
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ lpmpex->uParam = (LONG) FULLHWND32(wParam);
+
+ if (fWhoCalled == WOWDDE_POSTMESSAGE) {
+ if (h32 = DDEFindPair32(hwnd16, wParam, (HAND16) LOWORD(lParam))) {
+ DDEDeletehandle(LOWORD(lParam), h32);
+ GlobalFree(h32);
+ }
+
+ if (!LOWORD(lParam)) {
+ h32 = 0;
+ }
+ else {
+ DdeInfo.Msg = wMsg;
+ h32 = DDECopyhData32(hwnd16, wParam, (HAND16) LOWORD(lParam), &DdeInfo);
+ // WARNING: 16-bit memory may have moved
+ DdeInfo.Flags = DDE_PACKET;
+ DdeInfo.h16 = 0;
+ DDEAddhandle(hwnd16, wParam, (HAND16)LOWORD(lParam), h32, &DdeInfo);
+ }
+
+ *plParamNew = PackDDElParam(wMsg, (LONG) h32, (LONG) HIWORD(lParam));
+ }
+ else {
+ if (fThunkDDEmsg) {
+ if (!LOWORD(lParam)) {
+ h32 = 0;
+ }
+ else {
+ if (!(h32 = DDEFindPair32(hwnd16, wParam, (HAND16) LOWORD(lParam)))) {
+ LOGDEBUG (0, ("WOW::WMSG16: WM_DDE_DATA : Can't find h32 !\n"));
+ }
+ }
+ *plParamNew = PackDDElParam(wMsg, (LONG) h32, (LONG) HIWORD(lParam));
+ }
+ else {
+ *plParamNew = W32GetHookDDEMsglParam();
+ }
+ }
+ }
+ break;
+
+ case WM_DDE_EXECUTE:
+ {
+ DDEINFO DdeInfo;
+ HANDLE h32;
+ HAND16 h16;
+ INT cb;
+ VPVOID vp;
+ VPVOID vp1;
+ LPBYTE lpMem16;
+ LPBYTE lpMem32;
+ HWND16 hwnd16 = lpmpex->Parm16.WndProc.hwnd;
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ lpmpex->uParam = (LONG) FULLHWND32(wParam);
+
+ if (fWhoCalled == WOWDDE_POSTMESSAGE) {
+ vp = GlobalLock16(HIWORD(lParam), &cb);
+
+ GETMISCPTR(vp, lpMem16);
+ h32 = GlobalAlloc(GMEM_DDESHARE, cb);
+ if (h32) {
+ lpMem32 = GlobalLock(h32);
+ RtlCopyMemory(lpMem32, lpMem16, cb);
+ GlobalUnlock(h32);
+ FREEMISCPTR(lpMem16);
+ //
+ // The alias is checked to make bad apps do WM_DDE_EXECUTE
+ // correctly. One such app is SuperPrint. This app issues
+ // multiple WM_DDE_EXECUTEs without waiting for WM_DDE_ACK to
+ // come. Also, it uses the same h16 on these messages.
+ // We get around this problem by generating a unique h16-h32
+ // pairing each time. And freeing h16 when the WM_DDE_ACK comes.
+ // In WM32DDEAck, we need to free this h16 because we allocated
+ // this one. Apply this hack only if the h16 is valid. Caere
+ // OmniPage passes hard coded constants in HIWORD(lParam).
+ //
+ // SunilP, ChandanC 4-30-93
+ //
+ if (vp && DDEFindPair32(hwnd16, wParam, (HAND16) HIWORD(lParam))) {
+ vp1 = GlobalAllocLock16(GMEM_DDESHARE, cb, &h16);
+ if (vp1) {
+ GETMISCPTR(vp1, lpMem16);
+ RtlCopyMemory(lpMem16, lpMem32, cb);
+ FLUSHVDMPTR(vp1, cb, lpMem16);
+ FREEMISCPTR(lpMem16);
+ GlobalUnlock16(h16);
+
+ DdeInfo.Msg = wMsg;
+ DdeInfo.Format = 0;
+ DdeInfo.Flags = DDE_EXECUTE_FREE_H16 | DDE_PACKET;
+ DdeInfo.h16 = (HAND16) HIWORD(lParam);
+ DDEAddhandle(hwnd16, wParam, h16, h32, &DdeInfo);
+ }
+ else {
+ LOGDEBUG (0, ("WOW::WMSG16: WM_DDE_EXECUTE : Can't allocate h16 !\n"));
+ }
+ }
+ else {
+ DdeInfo.Msg = wMsg;
+ DdeInfo.Format = 0;
+ DdeInfo.Flags = DDE_PACKET;
+ DdeInfo.h16 = 0;
+ DDEAddhandle(hwnd16, wParam, (HAND16)HIWORD(lParam), h32, &DdeInfo);
+ }
+ }
+ else {
+ GlobalUnlock16(HIWORD(lParam));
+ }
+ GlobalUnlock16(HIWORD(lParam));
+ }
+ else {
+ if (!(h32 = DDEFindPair32(hwnd16, wParam, (HAND16) HIWORD(lParam)))) {
+ LOGDEBUG (0, ("WOW::WMSG16: WM_DDE_EXECUTE : Can't find h32 !\n"));
+ }
+ }
+
+ *plParamNew = (ULONG)h32;
+ }
+ break;
+
+
+
+ case WM_COPYDATA:
+ {
+ LPBYTE lpMem16;
+ LPBYTE lpMem32;
+ PCOPYDATASTRUCT16 lpCDS16;
+ PCOPYDATASTRUCT lpCDS32 = NULL;
+ PCPDATA pTemp;
+ HWND16 hwnd16 = lpmpex->Parm16.WndProc.hwnd;
+
+ lpmpex->uParam = (LONG) HWND32(wParam);
+
+ if (fWhoCalled == WOWDDE_POSTMESSAGE) {
+ GETMISCPTR(lParam, lpCDS16);
+ if (lpCDS32 = (PCOPYDATASTRUCT) malloc_w(sizeof(COPYDATASTRUCT))) {
+ lpCDS32->dwData = lpCDS16->dwData;
+ if (lpCDS32->cbData = lpCDS16->cbData) {
+ if (lpMem32 = malloc_w(lpCDS32->cbData)) {
+ GETMISCPTR(lpCDS16->lpData, lpMem16);
+ if (lpMem16) {
+ RtlCopyMemory(lpMem32, lpMem16, lpCDS32->cbData);
+ CopyDataAddNode (hwnd16, wParam, (DWORD) lpMem16, (DWORD) lpMem32, COPYDATA_16);
+ }
+ FREEMISCPTR(lpMem16);
+ }
+ lpCDS32->lpData = lpMem32;
+ }
+ else {
+ lpCDS32->lpData = NULL;
+ }
+ }
+ FREEMISCPTR(lpCDS16);
+
+ CopyDataAddNode (hwnd16, wParam, (DWORD) lParam, (DWORD) lpCDS32, COPYDATA_16);
+ }
+ else {
+ pTemp = CopyDataFindData32 (hwnd16, wParam, lParam);
+ lpCDS32 = (PCOPYDATASTRUCT) pTemp->Mem32;
+ WOW32ASSERTMSGF(lpCDS32, ("WOW::WM_COPYDATA:Can't locate lpCDS32\n"));
+ }
+
+ *plParamNew = (LONG)lpCDS32;
+ }
+ break;
+
+
+ // Win 3.1 messages
+
+ case WM_DROPFILES:
+ lpmpex->uParam = (UINT)HDROP32(wParam);
+ WOW32ASSERT(lpmpex->uParam != 0);
+ break;
+
+ case WM_DROPOBJECT:
+ case WM_QUERYDROPOBJECT:
+ case WM_DRAGLOOP:
+ case WM_DRAGSELECT:
+ case WM_DRAGMOVE:
+ {
+ register LPDROPSTRUCT lpds;
+ register PDROPSTRUCT16 lpds16;
+
+ if (lParam) {
+
+ lpds = (LPDROPSTRUCT) lpmpex->MsgBuffer;
+
+ GETVDMPTR(lParam, sizeof(DROPSTRUCT16), lpds16);
+
+ lpds->hwndSource = HWND32(lpds16->hwndSource);
+ lpds->hwndSink = HWND32(lpds16->hwndSink);
+ lpds->wFmt = lpds16->wFmt;
+ lpds->ptDrop.y = (LONG)lpds16->ptDrop.y;
+ lpds->ptDrop.x = (LONG)lpds16->ptDrop.x;
+ lpds->dwControlData = lpds16->dwControlData;
+
+ *plParamNew = (LONG) lpds;
+
+ FREEVDMPTR(lpds16);
+ }
+ }
+ break;
+
+ case WM_NEXTMENU: // Thunk
+ *plParamNew = (LONG)lpmpex->MsgBuffer;
+ ((PMDINEXTMENU)(*plParamNew))->hmenuIn = HMENU32(LOWORD(lParam));
+ break;
+
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED:
+ if (lParam) {
+ lpmpex->lParam = (LONG) lpmpex->MsgBuffer;
+ getwindowpos16( (VPWINDOWPOS16)lParam, (LPWINDOWPOS)lpmpex->lParam );
+ }
+ break;
+
+ case WM_TIMER:
+ {
+ HAND16 htask16;
+ PTMR ptmr;
+ WORD wIDEvent;
+
+ htask16 = CURRENTPTD()->htask16;
+ wIDEvent = wParam;
+
+ ptmr = FindTimer16( lpmpex->Parm16.WndProc.hwnd, htask16, wIDEvent );
+
+ if ( !ptmr ) {
+ if ( lParam == 0L ) {
+ /*
+ ** Edit controls have timers which can be sent straight
+ ** through without thunking... (wParam=1, lParam=0)
+ */
+ lpmpex->uParam = (UINT)wIDEvent;
+ *plParamNew = 0L;
+ } else {
+ LOGDEBUG(6,(" ThunkWMMSG16 WARNING: cannot find timer %04x\n", wIDEvent));
+ }
+ } else {
+ lpmpex->uParam = (UINT)wIDEvent;
+ *plParamNew = ptmr->dwTimerProc32; // 32-bit proc or NULL
+ }
+
+ }
+ break;
+
+ }
+ return TRUE;
+}
+
+//
+// the WM_CREATE message has already been thunked, but this WM_CREATE
+// is coming from an MDI client window so lParam->lpCreateParams needs
+// special attention
+//
+
+BOOL FinishThunkingWMCreateMDI16(LONG lParamNew, LPCLIENTCREATESTRUCT lpCCS)
+{
+ PCLIENTCREATESTRUCT16 pCCS16;
+
+ GETVDMPTR(((LPCREATESTRUCT)lParamNew)->lpCreateParams,
+ sizeof(CLIENTCREATESTRUCT16), pCCS16);
+
+ lpCCS->hWindowMenu = HMENU32(FETCHWORD(pCCS16->hWindowMenu));
+ lpCCS->idFirstChild = WORD32(FETCHWORD(pCCS16->idFirstChild));
+
+ ((LPCREATESTRUCT)lParamNew)->lpCreateParams = (LPVOID)lpCCS;
+
+ FREEVDMPTR(pCCS16);
+
+ return TRUE;
+}
+
+//
+// the WM_CREATE message has already been thunked, but this WM_CREATE
+// is coming from an MDI child window so lParam->lpCreateParams needs
+// special attention
+//
+
+BOOL FinishThunkingWMCreateMDIChild16(LONG lParamNew, LPMDICREATESTRUCT lpMCS)
+{
+ PMDICREATESTRUCT16 pMCS16;
+
+ GETVDMPTR(((LPCREATESTRUCT)lParamNew)->lpCreateParams,
+ sizeof(MDICREATESTRUCT16), pMCS16);
+
+ GETPSZIDPTR(pMCS16->vpszClass, lpMCS->szClass);
+ GETPSZPTR(pMCS16->vpszTitle, lpMCS->szTitle);
+ lpMCS->hOwner = HMODINST32(FETCHWORD(pMCS16->hOwner));
+ lpMCS->x = (int)FETCHWORD(pMCS16->x);
+ lpMCS->y = (int)FETCHWORD(pMCS16->y);
+ lpMCS->cx = (int)FETCHWORD(pMCS16->cx);
+ lpMCS->cy = (int)FETCHWORD(pMCS16->cy);
+ lpMCS->style = FETCHDWORD(pMCS16->style);
+ lpMCS->lParam = FETCHDWORD(pMCS16->lParam);
+
+ ((LPCREATESTRUCT)lParamNew)->lpCreateParams = (LPVOID)lpMCS;
+
+ FREEVDMPTR(pMCS16);
+
+ return TRUE;
+}
+
+
+VOID FASTCALL UnThunkWMMsg16(LPMSGPARAMEX lpmpex)
+{
+ switch(lpmpex->Parm16.WndProc.wMsg) {
+
+ case WM_SETTEXT: // 00Ch, <SLPre,SLPost >
+ case WM_WININICHANGE: // 01Ah, <SLPre, LS>
+ case WM_DEVMODECHANGE: // 01Bh, <SLPre, LS>
+ {
+ BOOL fFreePtr;
+ DeleteParamMap(lpmpex->lParam, PARAM_32, &fFreePtr);
+ if (fFreePtr) {
+ FREEPSZPTR((LPSZ)lpmpex->lParam);
+ }
+ }
+ break;
+
+ case WM_GETTEXT: // 00Dh, <SLPre,SLPost,LS>
+ if ((WORD)lpmpex->lReturn > 0) {
+ FLUSHVDMPTR(lpmpex->Parm16.WndProc.lParam, lpmpex->Parm16.WndProc.wParam, (LPSZ)lpmpex->lParam);
+ FREEPSZPTR((LPSZ)lpmpex->lParam);
+ }
+ break;
+
+ case WM_GETMINMAXINFO: // 024h, <SLPre,SLPost,LS>,MINMAXINFOSTRUCT
+ UnThunkWMGetMinMaxInfo16(lpmpex->Parm16.WndProc.lParam, (LPPOINT)lpmpex->lParam);
+ break;
+
+ case WM_DRAWITEM: // 02Bh notused, DRAWITEMSTRUCT
+ if (lpmpex->lParam) {
+ putdrawitem16((VPDRAWITEMSTRUCT16)lpmpex->Parm16.WndProc.lParam, (PDRAWITEMSTRUCT)lpmpex->lParam);
+ }
+ break;
+
+ case WM_MEASUREITEM: // 02Ch notused, MEASUREITEMSTRUCT
+ if (lpmpex->lParam) {
+ putmeasureitem16((VPMEASUREITEMSTRUCT16)lpmpex->Parm16.WndProc.lParam, (PMEASUREITEMSTRUCT)lpmpex->lParam);
+ }
+ break;
+
+ case WM_DELETEITEM: // 02Dh notused, DELETEITEMSTRUCT
+ if (lpmpex->lParam) {
+ putdeleteitem16((VPDELETEITEMSTRUCT16)lpmpex->Parm16.WndProc.lParam, (PDELETEITEMSTRUCT)lpmpex->lParam);
+ }
+ break;
+
+ case WM_GETFONT: // 031h
+ lpmpex->lReturn = GETHFONT16(lpmpex->lReturn);
+ break;
+
+ case WM_COMPAREITEM: // 039h
+ if (lpmpex->lParam) {
+ putcompareitem16((VPCOMPAREITEMSTRUCT16)lpmpex->Parm16.WndProc.lParam, (PCOMPAREITEMSTRUCT)lpmpex->lParam);
+ }
+ break;
+
+ case WM_WINHELP:
+ if (lpmpex->lParam && lpmpex->lParam != (LONG)lpmpex->MsgBuffer) {
+ free_w((PVOID)lpmpex->lParam);
+ }
+ break;
+
+ case WM_NCCALCSIZE: // 083h, <SLPre,SLPost,LS>,RECT
+ if (lpmpex->lParam) {
+ putrect16((VPRECT16)lpmpex->Parm16.WndProc.lParam, (LPRECT)lpmpex->lParam);
+ if (lpmpex->Parm16.WndProc.wParam) {
+ PNCCALCSIZE_PARAMS16 pnc16;
+ PNCCALCSIZE_PARAMS16 lpnc16;
+ LPNCCALCSIZE_PARAMS lpnc;
+
+ lpnc = (LPNCCALCSIZE_PARAMS)lpmpex->lParam;
+ pnc16 = (PNCCALCSIZE_PARAMS16)lpmpex->Parm16.WndProc.lParam;
+
+ putrect16((VPRECT16)(&pnc16->rgrc[1]), &lpnc->rgrc[1]);
+ putrect16((VPRECT16)(&pnc16->rgrc[2]), &lpnc->rgrc[2]);
+
+ GETVDMPTR( pnc16, sizeof(NCCALCSIZE_PARAMS16), lpnc16 );
+
+ putwindowpos16( (VPWINDOWPOS16)lpnc16->lppos, lpnc->lppos );
+
+ FREEVDMPTR( lpnc16 );
+
+ }
+ }
+ break;
+
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED:
+ if (lpmpex->lParam) {
+ putwindowpos16( (VPWINDOWPOS16)lpmpex->Parm16.WndProc.lParam, (LPWINDOWPOS)lpmpex->lParam);
+ }
+ break;
+
+ case WM_CTLCOLOR:
+ // see thunking of wm_ctlcolor.
+
+ if ((ULONG)lpmpex->lReturn > COLOR_ENDCOLORS) {
+ lpmpex->lReturn = GETHBRUSH16(lpmpex->lReturn);
+ }
+ break;
+
+ case WM_MDICREATE: // 220h, <SLPre,SLPost,LS>,MDICREATESTRUCT
+ UnThunkWMMDICreate16(lpmpex->Parm16.WndProc.lParam, (LPMDICREATESTRUCT)lpmpex->lParam);
+ lpmpex->lReturn = GETHWND16(lpmpex->lReturn);
+ break;
+
+ case WM_MDIGETACTIVE:
+ //
+ // LOWORD(lReturn) == hwndMDIActive
+ // HIWORD(lReturn) == fMaximized
+ //
+
+ LOW(lpmpex->lReturn) = GETHWND16((HWND)(lpmpex->lReturn));
+ if (lpmpex->lParam != 0) {
+ HIW(lpmpex->lReturn) = (WORD)(*((LPBOOL)lpmpex->lParam) != 0);
+ }
+ break;
+
+ case WM_MDISETMENU:
+ lpmpex->lReturn = GETHMENU16(lpmpex->lReturn);
+ break;
+
+ case WM_PAINTCLIPBOARD:
+ case WM_SIZECLIPBOARD:
+ if (lpmpex->lParam) {
+ GlobalFree((HANDLE)lpmpex->lParam);
+ }
+ break;
+
+ case WM_ASKCBFORMATNAME:
+ /* BUGBUGBUG -- neither thunk or unthunk should be necessary,
+ since the system does not process this message in DefWindowProc
+ FritzS */
+ if (lpmpex->lParam) {
+ putstr16((VPSZ)lpmpex->Parm16.WndProc.lParam, (LPSZ)lpmpex->lParam, lpmpex->Parm16.WndProc.wParam);
+ free_w((PBYTE)lpmpex->lParam);
+ }
+ break;
+
+ case WM_DDE_INITIATE:
+ WI32DDEDeleteInitiator((HAND16) lpmpex->Parm16.WndProc.wParam);
+ break;
+
+ case WM_NEXTMENU:
+ {
+ PMDINEXTMENU pT = (PMDINEXTMENU)lpmpex->lParam;
+ LOW(lpmpex->lReturn) = GETHMENU16(pT->hmenuNext);
+ HIW(lpmpex->lReturn) = GETHWND16(pT->hwndNext);
+ }
+ break;
+
+ case WM_COPYDATA:
+ if (fWhoCalled == WOWDDE_POSTMESSAGE) {
+ HWND16 hwnd16 = lpmpex->Parm16.WndProc.hwnd;
+ WORD wParam = lpmpex->Parm16.WndProc.wParam;
+ LONG lParamNew = lpmpex->lParam;
+
+ if (((PCOPYDATASTRUCT)lParamNew)->lpData) {
+ free_w (((PCOPYDATASTRUCT)lParamNew)->lpData);
+ CopyDataDeleteNode (hwnd16, wParam, (DWORD) ((PCOPYDATASTRUCT)lParamNew)->lpData);
+ }
+
+ if (lParamNew) {
+ free_w ((PVOID)lParamNew);
+ CopyDataDeleteNode (hwnd16, wParam, lParamNew);
+ }
+ else {
+ LOGDEBUG (LOG_ALWAYS, ("WOW::WM_COPYDATA16:Unthunking - lpCDS32 is NULL\n"));
+ }
+ }
+ break;
+
+ case WM_QUERYDRAGICON:
+ lpmpex->lReturn = (LONG)GETHICON16(lpmpex->lReturn);
+ break;
+
+ case WM_QUERYDROPOBJECT:
+
+ //
+ // Return value is either TRUE, FALSE,
+ // or a cursor!
+ //
+ if (lpmpex->lReturn && lpmpex->lReturn != (LONG)TRUE) {
+ lpmpex->lReturn = (LONG)GETHCURSOR16(lpmpex->lReturn);
+ }
+ break;
+ }
+}
+
+
+BOOL ThunkWMGetMinMaxInfo16(VPVOID lParam, LPPOINT *plParamNew)
+{
+ register LPPOINT lppt;
+ register PPOINT16 ppt16;
+
+ if (lParam) {
+
+ lppt = *plParamNew;
+
+ GETVDMPTR(lParam, sizeof(POINT16)*5, ppt16);
+
+ lppt[0].x = ppt16[0].x;
+ lppt[0].y = ppt16[0].y;
+ lppt[1].x = ppt16[1].x;
+ lppt[1].y = ppt16[1].y;
+ lppt[2].x = ppt16[2].x;
+ lppt[2].y = ppt16[2].y;
+ lppt[3].x = ppt16[3].x;
+ lppt[3].y = ppt16[3].y;
+ lppt[4].x = ppt16[4].x;
+ lppt[4].y = ppt16[4].y;
+
+ FREEVDMPTR(ppt16);
+ }
+ RETURN(TRUE);
+}
+
+
+VOID UnThunkWMGetMinMaxInfo16(VPVOID lParam, register LPPOINT lParamNew)
+{
+ register PPOINT16 ppt16;
+
+ if (lParamNew) {
+
+ GETVDMPTR(lParam, sizeof(POINT16)*5, ppt16);
+
+ ppt16[0].x = (SHORT)lParamNew[0].x;
+ ppt16[0].y = (SHORT)lParamNew[0].y;
+ ppt16[1].x = (SHORT)lParamNew[1].x;
+ ppt16[1].y = (SHORT)lParamNew[1].y;
+ ppt16[2].x = (SHORT)lParamNew[2].x;
+ ppt16[2].y = (SHORT)lParamNew[2].y;
+ ppt16[3].x = (SHORT)lParamNew[3].x;
+ ppt16[3].y = (SHORT)lParamNew[3].y;
+ ppt16[4].x = (SHORT)lParamNew[4].x;
+ ppt16[4].y = (SHORT)lParamNew[4].y;
+
+ FLUSHVDMPTR(lParam, sizeof(POINT16)*5, ppt16);
+ FREEVDMPTR(ppt16);
+
+ }
+ RETURN(NOTHING);
+}
+
+BOOL ThunkWMMDICreate16(VPVOID lParam, LPMDICREATESTRUCT *plParamNew)
+{
+ register LPMDICREATESTRUCT lpmdicreate;
+ register PMDICREATESTRUCT16 pmdicreate16;
+
+ if (lParam) {
+
+ lpmdicreate = *plParamNew;
+
+ GETVDMPTR(lParam, sizeof(MDICREATESTRUCT16), pmdicreate16);
+
+ GETPSZIDPTR( pmdicreate16->vpszClass, lpmdicreate->szClass );
+ GETPSZPTR( pmdicreate16->vpszTitle, lpmdicreate->szTitle );
+
+ lpmdicreate->hOwner = HMODINST32( pmdicreate16->hOwner );
+ lpmdicreate->x = INT32DEFAULT(pmdicreate16->x);
+ lpmdicreate->y = INT32DEFAULT(pmdicreate16->y);
+ lpmdicreate->cx = INT32DEFAULT(pmdicreate16->cx);
+ lpmdicreate->cy = INT32DEFAULT(pmdicreate16->cy);
+ lpmdicreate->style = pmdicreate16->style;
+ lpmdicreate->lParam = pmdicreate16->lParam;
+
+
+ FREEVDMPTR(pmdicreate16);
+ }
+ RETURN(TRUE);
+}
+
+
+VOID UnThunkWMMDICreate16(VPVOID lParam, register LPMDICREATESTRUCT lParamNew)
+{
+ register PMDICREATESTRUCT16 pmdicreate16;
+
+ if (lParamNew) {
+
+ GETVDMPTR(lParam, sizeof(MDICREATESTRUCT16), pmdicreate16);
+
+ pmdicreate16->hOwner = GETHINST16(lParamNew->hOwner);
+ pmdicreate16->x = (SHORT)lParamNew->x;
+ pmdicreate16->y = (SHORT)lParamNew->y;
+ pmdicreate16->cx = (SHORT)lParamNew->cx;
+ pmdicreate16->cy = (SHORT)lParamNew->cy;
+ pmdicreate16->style = lParamNew->style;
+ pmdicreate16->lParam = lParamNew->lParam;
+
+ FLUSHVDMPTR(lParam, sizeof(MDICREATESTRUCT16), pmdicreate16);
+ FREEVDMPTR(pmdicreate16);
+
+ }
+ RETURN(NOTHING);
+}
+
+
+
+BOOL FASTCALL ThunkSTMsg16(LPMSGPARAMEX lpmpex)
+{
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ LOGDEBUG(9,(" Thunking 16-bit STM window message %s(%04x)\n", (LPSZ)GetWMMsgName(wMsg), wMsg));
+
+ switch(wMsg) {
+
+ case WIN30_STM_SETICON:
+ lpmpex->uMsg = STM_SETICON;
+ lpmpex->uParam = (UINT) HICON32(lpmpex->Parm16.WndProc.wParam);
+ break;
+
+ case WIN30_STM_GETICON:
+ lpmpex->uMsg = STM_GETICON;
+ break;
+ }
+ return (TRUE);
+}
+
+
+VOID FASTCALL UnThunkSTMsg16(LPMSGPARAMEX lpmpex)
+{
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ LOGDEBUG(9,(" UnThunking 16-bit STM window message %s(%04x)\n", (LPSZ)GetWMMsgName(wMsg), wMsg));
+
+ switch(wMsg) {
+
+ case WIN30_STM_GETICON:
+ case WIN30_STM_SETICON:
+ lpmpex->lReturn = GETHICON16(lpmpex->lReturn);
+ break;
+ }
+}
+
+
+BOOL FASTCALL ThunkMNMsg16(LPMSGPARAMEX lpmpex)
+{
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ LOGDEBUG(9,(" Thunking 16-bit MN_ window message %s(%04x)\n", (LPSZ)GetWMMsgName(wMsg), wMsg));
+
+ switch(wMsg) {
+
+ case WIN30_MN_GETHMENU:
+ lpmpex->uMsg = MN_GETHMENU;
+ break;
+
+ case WIN30_MN_FINDMENUWINDOWFROMPOINT:
+ lpmpex->uMsg = MN_FINDMENUWINDOWFROMPOINT;
+ lpmpex->uParam = (UINT)lpmpex->MsgBuffer; // enough room for UINT
+ *(PUINT)lpmpex->uParam = 0;
+ break;
+
+ }
+ return (TRUE);
+}
+
+
+VOID FASTCALL UnThunkMNMsg16(LPMSGPARAMEX lpmpex)
+{
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ LOGDEBUG(9,(" UnThunking 16-bit MN_ window message %s(%04x)\n", (LPSZ)GetWMMsgName(wMsg), wMsg));
+
+ switch(wMsg) {
+
+ case WIN30_MN_FINDMENUWINDOWFROMPOINT:
+ if (lpmpex->uParam) {
+ lpmpex->lReturn = MAKELONG((HWND16)lpmpex->lReturn,
+ LOWORD(*(PUINT)lpmpex->uParam));
+ }
+ break;
+ }
+}
diff --git a/private/mvdm/wow32/wmsg16.h b/private/mvdm/wow32/wmsg16.h
new file mode 100644
index 000000000..acdadc352
--- /dev/null
+++ b/private/mvdm/wow32/wmsg16.h
@@ -0,0 +1,55 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSG16.H
+ * WOW32 16-bit message thunks
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+ * Changed 12-May-1992 by Mike Tricker (miketri) Added MultiMedia prototypes
+--*/
+
+
+#define WIN30_MN_MSGMAX WM_USER+200
+#define WIN30_MN_FINDMENUWINDOWFROMPOINT WIN30_MN_MSGMAX+2 // 0x602
+
+#define WIN30_MN_GETHMENU WM_USER+2
+
+
+/* Message number/name association (for debug output only)
+ */
+#ifdef DEBUG
+typedef struct _MSGINFO { /* mi */
+ UINT uMsg; // 0x0001 in the high word means "undocumented"
+ PSZ pszMsgName; // 0x0002 in the high word means "win32-specific"
+} MSGINFO, *PMSGINFO;
+#endif
+
+
+/* Function prototypes
+ */
+#ifdef DEBUG
+PSZ GetWMMsgName(UINT uMsg);
+#endif
+
+HWND FASTCALL ThunkMsg16(LPMSGPARAMEX lpmpex);
+VOID FASTCALL UnThunkMsg16(LPMSGPARAMEX lpmpex);
+BOOL FASTCALL ThunkWMMsg16(LPMSGPARAMEX lpmpex);
+VOID FASTCALL UnThunkWMMsg16(LPMSGPARAMEX lpmpex);
+BOOL FASTCALL ThunkSTMsg16(LPMSGPARAMEX lpmpex);
+VOID FASTCALL UnThunkSTMsg16(LPMSGPARAMEX lpmpex);
+BOOL FASTCALL ThunkMNMsg16(LPMSGPARAMEX lpmpex);
+VOID FASTCALL UnThunkMNMsg16(LPMSGPARAMEX lpmpex);
+
+
+BOOL ThunkWMGetMinMaxInfo16(VPVOID lParam, LPPOINT *plParamNew);
+VOID UnThunkWMGetMinMaxInfo16(VPVOID lParam, LPPOINT lParamNew);
+BOOL ThunkWMMDICreate16(VPVOID lParam, LPMDICREATESTRUCT *plParamNew );
+VOID UnThunkWMMDICreate16(VPVOID lParam, LPMDICREATESTRUCT lParamNew );
+BOOL FinishThunkingWMCreateMDI16(LONG lParamNew, LPCLIENTCREATESTRUCT lpCCS);
+BOOL FinishThunkingWMCreateMDIChild16(LONG lParamNew, LPMDICREATESTRUCT lpMCS);
+#define StartUnThunkingWMCreateMDI16(lParamNew)
+
diff --git a/private/mvdm/wow32/wmsgbm.c b/private/mvdm/wow32/wmsgbm.c
new file mode 100644
index 000000000..49af3f04e
--- /dev/null
+++ b/private/mvdm/wow32/wmsgbm.c
@@ -0,0 +1,97 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSGBM.C
+ * WOW32 16-bit message thunks
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wmsgbm.c);
+
+
+#ifdef DEBUG
+
+MSGINFO amiBM[] = {
+ {OLDBM_GETCHECK, "BM_GETCHECK"}, // 0x0400
+ {OLDBM_SETCHECK, "BM_SETCHECK"}, // 0x0401
+ {OLDBM_GETSTATE, "BM_GETSTATE"}, // 0x0402
+ {OLDBM_SETSTATE, "BM_SETSTATE"}, // 0x0403
+ {OLDBM_SETSTYLE, "BM_SETSTYLE"}, // 0x0404
+};
+
+PSZ GetBMMsgName(WORD wMsg)
+{
+ INT i;
+ register PMSGINFO pmi;
+
+ for (pmi=amiBM,i=NUMEL(amiBM); i>0; i--,pmi++)
+ if ((WORD)pmi->uMsg == wMsg)
+ return pmi->pszMsgName;
+ return GetWMMsgName(wMsg);
+}
+
+#endif
+
+
+BOOL FASTCALL ThunkBMMsg16(LPMSGPARAMEX lpmpex)
+{
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+ LOGDEBUG(7,(" Thunking 16-bit button message %s(%04x)\n", (LPSZ)GetBMMsgName(wMsg), wMsg));
+
+ //
+ // special case BM_CLICK
+ //
+
+ if (wMsg == WIN31_BM_CLICK) {
+ lpmpex->uMsg = BM_CLICK;
+ }
+ else {
+ wMsg -= WM_USER;
+
+ //
+ // For app defined (control) messages that are out of range
+ // return TRUE.
+ //
+ // ChandanC Sept-15-1992
+ //
+
+ if (wMsg < (BM_SETSTYLE - BM_GETCHECK + 1)) {
+ lpmpex->uMsg = wMsg + BM_GETCHECK;
+
+ // The following messages should not require thunking, because
+ // they contain no pointers, handles, or rearranged message parameters,
+ // so consequently they are not documented in great detail here:
+ //
+ // BM_GETCHECK
+ // BM_GETSTATE
+ // BM_SETCHECK
+ // BM_SETSTATE
+ // BM_SETSTYLE
+ //
+ // And these I haven't seen documentation for yet (new for Win32???)
+ //
+ // BM_GETIMAGE
+ // BM_SETIMAGE
+
+ // switch(lpmpex->uMsg) {
+ // NO BM_ message needs thunking
+ // }
+
+ }
+ }
+ return TRUE;
+}
+
+
+VOID FASTCALL UnThunkBMMsg16(LPMSGPARAMEX lpmpex)
+{
+}
diff --git a/private/mvdm/wow32/wmsgbm.h b/private/mvdm/wow32/wmsgbm.h
new file mode 100644
index 000000000..5c1649c1f
--- /dev/null
+++ b/private/mvdm/wow32/wmsgbm.h
@@ -0,0 +1,27 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSGBM.H
+ * WOW32 16-bit message thunks
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* Function prototypes
+ */
+PSZ GetBMMsgName(WORD wMsg);
+
+BOOL FASTCALL ThunkBMMsg16(LPMSGPARAMEX lpmpex);
+VOID FASTCALL UnThunkBMMsg16(LPMSGPARAMEX lpmpex);
+
+#define WIN31_BM_CLICK (WM_USER + 99)
+
+#ifndef BM_CLICK
+#define BM_CLICK 0x00F5 // user\server\usersrv.h
+#endif
diff --git a/private/mvdm/wow32/wmsgcb.c b/private/mvdm/wow32/wmsgcb.c
new file mode 100644
index 000000000..ad57f9591
--- /dev/null
+++ b/private/mvdm/wow32/wmsgcb.c
@@ -0,0 +1,198 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSGCB.C
+ * WOW32 16-bit message thunks
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wmsgcb.c);
+
+
+#ifdef DEBUG
+
+MSGINFO amiCB[] = {
+ {OLDCB_GETEDITSEL, "CB_GETEDITSEL"}, // 0x0400
+ {OLDCB_LIMITTEXT, "CB_LIMITTEXT"}, // 0x0401
+ {OLDCB_SETEDITSEL, "CB_SETEDITSEL"}, // 0x0402
+ {OLDCB_ADDSTRING, "CB_ADDSTRING"}, // 0x0403
+ {OLDCB_DELETESTRING, "CB_DELETESTRING"}, // 0x0404
+ {OLDCB_DIR, "CB_DIR"}, // 0x0405
+ {OLDCB_GETCOUNT, "CB_GETCOUNT"}, // 0x0406
+ {OLDCB_GETCURSEL, "CB_GETCURSEL"}, // 0x0407
+ {OLDCB_GETLBTEXT, "CB_GETLBTEXT"}, // 0x0408
+ {OLDCB_GETLBTEXTLEN, "CB_GETLBTEXTLEN"}, // 0x0409
+ {OLDCB_INSERTSTRING, "CB_INSERTSTRING"}, // 0x040A
+ {OLDCB_RESETCONTENT, "CB_RESETCONTENT"}, // 0x040B
+ {OLDCB_FINDSTRING, "CB_FINDSTRING"}, // 0x040C
+ {OLDCB_SELECTSTRING, "CB_SELECTSTRING"}, // 0x040D
+ {OLDCB_SETCURSEL, "CB_SETCURSEL"}, // 0x040E
+ {OLDCB_SHOWDROPDOWN, "CB_SHOWDROPDOWN"}, // 0x040F
+ {OLDCB_GETITEMDATA, "CB_GETITEMDATA"}, // 0x0410
+ {OLDCB_SETITEMDATA, "CB_SETITEMDATA"}, // 0x0411
+ {OLDCB_GETDROPPEDCONTROLRECT,"CB_GETDROPPEDCONTROLRECT"}, // 0x0412
+ {OLDCB_SETITEMHEIGHT, "CB_SETITEMHEIGHT"}, // 0x0413
+ {OLDCB_GETITEMHEIGHT, "CB_GETITEMHEIGHT"}, // 0x0414
+ {OLDCB_SETEXTENDEDUI, "CB_SETEXTENDEDUI"}, // 0x0415
+ {OLDCB_GETEXTENDEDUI, "CB_GETEXTENDEDUI"}, // 0x0416
+ {OLDCB_GETDROPPEDSTATE, "CB_GETDROPPEDSTATE"}, // 0x0417
+ {OLDCB_FINDSTRINGEXACT, "CB_FINDSTRINGEXACT"}, // 0x0418
+};
+
+PSZ GetCBMsgName(WORD wMsg)
+{
+ INT i;
+ register PMSGINFO pmi;
+
+ for (pmi=amiCB,i=NUMEL(amiCB); i>0; i--,pmi++)
+ if ((WORD)pmi->uMsg == wMsg)
+ return pmi->pszMsgName;
+ return GetWMMsgName(wMsg);
+}
+
+#endif
+
+
+
+BOOL FASTCALL ThunkCBMsg16(LPMSGPARAMEX lpmpex)
+{
+ register PWW pww;
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ LOGDEBUG(7,(" Thunking 16-bit combo box message %s(%04x)\n", (LPSZ)GetCBMsgName(wMsg), wMsg));
+
+ // Sudeepb - 04-Mar-1996
+ // Fix the broken thunking for CBEC_SETCOMBOFOCUS and CBEC_KILLCOMBOFOCUS.
+ // It was broken when NT user merged with Win95 where CB_MAX has changed.
+ // the following code is written in such a manner that the only dependency
+ // we have is that CBEC_SETCOMBOFOCUS precedes CBEC_KILLCOMBOFOCUS which
+ // will always be true.
+
+
+ if (wMsg == OLDCBEC_SETCOMBOFOCUS || wMsg == OLDCBEC_KILLCOMBOFOCUS) {
+ lpmpex->uMsg = (WORD)(wMsg - OLDCBEC_SETCOMBOFOCUS + CBEC_SETCOMBOFOCUS);
+ return TRUE;
+ }
+
+ wMsg -= WM_USER;
+
+ //
+ // For app defined (control) messages that are out of range
+ // return TRUE.
+ //
+ // ChandanC Sept-15-1992
+ //
+
+ if (wMsg < (CB_FINDSTRINGEXACT - CB_GETEDITSEL + 4)) {
+
+ switch(lpmpex->uMsg = wMsg + CB_GETEDITSEL) {
+ case CB_SELECTSTRING:
+ case CB_FINDSTRINGEXACT:
+ case CB_FINDSTRING:
+ case CB_INSERTSTRING:
+ case CB_ADDSTRING:
+ if (!(pww = lpmpex->pww))
+ return FALSE;
+
+ if (!(pww->dwStyle & (CBS_OWNERDRAWFIXED|CBS_OWNERDRAWVARIABLE)) ||
+ (pww->dwStyle & (CBS_HASSTRINGS))) {
+ GETPSZPTR(lpmpex->Parm16.WndProc.lParam, (LPSZ)lpmpex->lParam);
+ }
+ break;
+
+
+ case CB_GETLBTEXT:
+ if (NULL != (pww = lpmpex->pww)) {
+ register PTHUNKTEXTDWORD pthkdword = (PTHUNKTEXTDWORD)lpmpex->MsgBuffer;
+
+ // see comments in the file wmsglb.c
+ //
+
+ pthkdword->fDWORD = (pww->dwStyle & (CBS_OWNERDRAWFIXED|CBS_OWNERDRAWVARIABLE)) &&
+ !(pww->dwStyle & (CBS_HASSTRINGS));
+
+ if (pthkdword->fDWORD) {
+ lpmpex->lParam = (LPARAM)(LPVOID)&pthkdword->dwDataItem;
+ break;
+ }
+ }
+ else {
+ register PTHUNKTEXTDWORD pthkdword = (PTHUNKTEXTDWORD)lpmpex->MsgBuffer;
+ pthkdword->fDWORD = FALSE;
+ }
+
+ GETPSZPTR(lpmpex->Parm16.WndProc.lParam, (LPSZ)lpmpex->lParam);
+ break;
+
+ case CB_DIR:
+ GETPSZPTR(lpmpex->Parm16.WndProc.lParam, (LPSZ)lpmpex->lParam);
+
+ if (W32CheckThunkParamFlag()) {
+ AddParamMap(lpmpex->lParam, lpmpex->Parm16.WndProc.lParam);
+ }
+ break;
+
+ case CB_GETDROPPEDCONTROLRECT:
+ lpmpex->lParam = (LONG)lpmpex->MsgBuffer;
+ break;
+ }
+ }
+ return TRUE;
+}
+
+
+VOID FASTCALL UnThunkCBMsg16(LPMSGPARAMEX lpmpex)
+{
+ switch(lpmpex->uMsg) {
+
+ case CB_GETLBTEXT:
+ {
+ register PTHUNKTEXTDWORD pthkdword = (PTHUNKTEXTDWORD)lpmpex->MsgBuffer;
+
+ if (pthkdword->fDWORD) {
+ // this is a dword, not a string
+ // assign the dword as unaligned
+ UNALIGNED DWORD *lpdwDataItem;
+
+ GETVDMPTR((lpmpex->Parm16.WndProc.lParam), sizeof(DWORD), lpdwDataItem);
+ *lpdwDataItem = pthkdword->dwDataItem;
+ FREEVDMPTR(lpdwDataItem);
+ break;
+ }
+
+ }
+
+ // fall through to the common code
+
+ case CB_ADDSTRING:
+ case CB_FINDSTRING:
+ case CB_FINDSTRINGEXACT:
+ case CB_INSERTSTRING:
+ case CB_SELECTSTRING:
+ FREEPSZPTR((LPSZ)lpmpex->lParam);
+ break;
+
+ case CB_DIR:
+ if (W32CheckThunkParamFlag()) {
+ DeleteParamMap(lpmpex->lParam, PARAM_32, NULL);
+ }
+
+ FREEPSZPTR((LPSZ)lpmpex->lParam);
+ break;
+
+ case CB_GETDROPPEDCONTROLRECT:
+ if (lpmpex->lParam) {
+ putrect16((VPRECT16)lpmpex->Parm16.WndProc.lParam, (LPRECT)lpmpex->lParam);
+ }
+ break;
+ }
+}
diff --git a/private/mvdm/wow32/wmsgcb.h b/private/mvdm/wow32/wmsgcb.h
new file mode 100644
index 000000000..3ba01b50f
--- /dev/null
+++ b/private/mvdm/wow32/wmsgcb.h
@@ -0,0 +1,21 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSGCB.H
+ * WOW32 16-bit message thunks
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* Function prototypes
+ */
+PSZ GetCBMsgName(WORD wMsg);
+
+BOOL FASTCALL ThunkCBMsg16(LPMSGPARAMEX lpmpex);
+VOID FASTCALL UnThunkCBMsg16(LPMSGPARAMEX lpmpex);
diff --git a/private/mvdm/wow32/wmsgem.c b/private/mvdm/wow32/wmsgem.c
new file mode 100644
index 000000000..6744fb42b
--- /dev/null
+++ b/private/mvdm/wow32/wmsgem.c
@@ -0,0 +1,288 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSGEM.C
+ * WOW32 16-bit message thunks
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wmsgem.c);
+
+VPVOID WordBreakProc16 = 0;
+
+extern WBP W32WordBreakProc;
+
+#ifdef DEBUG
+
+MSGINFO amiEM[] = {
+ {OLDEM_GETSEL, "EM_GETSEL"}, // 0x0400
+ {OLDEM_SETSEL, "EM_SETSEL"}, // 0x0401
+ {OLDEM_GETRECT, "EM_GETRECT"}, // 0x0402
+ {OLDEM_SETRECT, "EM_SETRECT"}, // 0x0403
+ {OLDEM_SETRECTNP, "EM_SETRECTNP"}, // 0x0404
+ {OLDEM_SCROLL, "EM_SCROLL"}, // 0x0405
+ {OLDEM_LINESCROLL, "EM_LINESCROLL"}, // 0x0406
+ {OLDEM_GETMODIFY, "EM_GETMODIFY"}, // 0x0408
+ {OLDEM_SETMODIFY, "EM_SETMODIFY"}, // 0x0409
+ {OLDEM_GETLINECOUNT, "EM_GETLINECOUNT"}, // 0x040A
+ {OLDEM_LINEINDEX, "EM_LINEINDEX"}, // 0x040B
+ {OLDEM_SETHANDLE, "EM_SETHANDLE"}, // 0x040C
+ {OLDEM_GETHANDLE, "EM_GETHANDLE"}, // 0x040D
+ {OLDEM_GETTHUMB, "EM_GETTHUMB"}, // 0x040E
+ {OLDEM_LINELENGTH, "EM_LINELENGTH"}, // 0x0411
+ {OLDEM_REPLACESEL, "EM_REPLACESEL"}, // 0x0412
+ {OLDEM_SETFONT, "EM_SETFONT"}, // 0x0413
+ {OLDEM_GETLINE, "EM_GETLINE"}, // 0x0414
+ {OLDEM_LIMITTEXT, "EM_LIMITTEXT"}, // 0x0415
+ {OLDEM_CANUNDO, "EM_CANUNDO"}, // 0x0416
+ {OLDEM_UNDO, "EM_UNDO"}, // 0x0417
+ {OLDEM_FMTLINES, "EM_FMTLINES"}, // 0x0418
+ {OLDEM_LINEFROMCHAR, "EM_LINEFROMCHAR"}, // 0x0419
+ {OLDEM_SETWORDBREAK, "EM_SETWORDBREAK"}, // 0x041A
+ {OLDEM_SETTABSTOPS, "EM_SETTABSTOPS"}, // 0x041B
+ {OLDEM_SETPASSWORDCHAR, "EM_SETPASSWORDCHAR"}, // 0x041C
+ {OLDEM_EMPTYUNDOBUFFER, "EM_EMPTYUNDOBUFFER"}, // 0x041D
+ {OLDEM_GETFIRSTVISIBLELINE, "EM_GETFIRSTVISIBLELINE"}, // 0x041E
+ {OLDEM_SETREADONLY, "EM_SETREADONLY"}, // 0x041F
+ {OLDEM_SETWORDBREAKPROC, "EM_SETWORDBREAKPROC"}, // 0x0420
+ {OLDEM_GETWORDBREAKPROC, "EM_GETWORDBREAKPROC"}, // 0x0421
+ {OLDEM_GETPASSWORDCHAR, "EM_GETPASSWORDCHAR"} // 0x0422
+};
+
+PSZ GetEMMsgName(WORD wMsg)
+{
+ INT i;
+ register PMSGINFO pmi;
+
+ for (pmi=amiEM,i=NUMEL(amiEM); i>0; i--,pmi++) {
+ if ((WORD)pmi->uMsg == wMsg)
+ return pmi->pszMsgName;
+ }
+ return GetWMMsgName(wMsg);
+}
+
+#endif
+
+
+BOOL FASTCALL ThunkEMMsg16(LPMSGPARAMEX lpmpex)
+{
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ LOGDEBUG(7,(" Thunking 16-bit edit control message %s(%04x)\n", (LPSZ)GetEMMsgName(wMsg), wMsg));
+
+ wMsg -= WM_USER;
+
+ //
+ // For app defined (control) messages that are out of range
+ // return TRUE.
+ //
+ // ChandanC Sept-15-1992
+ //
+
+ if (wMsg < (EM_GETPASSWORDCHAR - EM_GETSEL + 1)) {
+ switch(lpmpex->uMsg = wMsg + EM_GETSEL) {
+
+ case EM_GETSEL:
+ // 16 bit apps cannot pass non-zero values in wParam or lParam for this
+ // message to NT since they will be considered long pointers.
+ // This is a hack for ReportWin - MarkRi
+
+ // NOTE: There is a case possible where the app is trying to pass
+ // thru a GETSEL msg that NT has sent it in which case things get more
+ // complicated but we haven't found an app YET that has this problem.
+ lpmpex->uParam = 0 ;
+ lpmpex->lParam = 0 ;
+ break ;
+
+
+ case EM_SETSEL:
+ lpmpex->uParam = LOWORD(lpmpex->Parm16.WndProc.lParam);
+ lpmpex->lParam = HIWORD(lpmpex->Parm16.WndProc.lParam);
+ break;
+
+ case EM_GETLINE:
+ GETMISCPTR(lpmpex->Parm16.WndProc.lParam, (LPSZ)lpmpex->lParam);
+ break;
+
+ case EM_GETRECT:
+ lpmpex->lParam = (LONG)lpmpex->MsgBuffer;
+ break;
+
+ case EM_LINESCROLL:
+ lpmpex->uParam = INT32(HIWORD(lpmpex->Parm16.WndProc.lParam));
+ lpmpex->lParam = INT32(LOWORD(lpmpex->Parm16.WndProc.lParam));
+ break;
+
+ case EM_SETHANDLE:
+ lpmpex->uParam = (UINT)MAKELONG(lpmpex->Parm16.WndProc.wParam,
+ LOWORD((DWORD)lpmpex->pww->hInstance) | 1);
+ break;
+
+ case EM_REPLACESEL:
+ { PSZ psz;
+ int i;
+ GETPSZPTR(lpmpex->Parm16.WndProc.lParam, psz);
+
+ if (psz) {
+ i = strlen(psz)+1;
+ lpmpex->lParam = (LONG) LocalAlloc (LMEM_FIXED, i);
+ RtlCopyMemory ((PSZ)lpmpex->lParam, psz, i);
+ }
+ FREEPSZPTR(psz);
+ }
+ break;
+
+ case EM_SETRECT:
+ case EM_SETRECTNP:
+ if (lpmpex->Parm16.WndProc.lParam) {
+ lpmpex->lParam = (LONG)lpmpex->MsgBuffer;
+ getrect16((VPRECT16)lpmpex->Parm16.WndProc.lParam, (LPRECT)lpmpex->lParam);
+ }
+ break;
+
+ case EM_SETTABSTOPS:
+ {
+ INT cItems = INT32(lpmpex->Parm16.WndProc.wParam);
+ if (cItems > 0) {
+ (PVOID)lpmpex->lParam = STACKORHEAPALLOC(cItems * sizeof(INT),
+ sizeof(lpmpex->MsgBuffer), lpmpex->MsgBuffer);
+ getintarray16((VPINT16)lpmpex->Parm16.WndProc.lParam, cItems, (LPINT)lpmpex->lParam);
+ }
+ }
+ break;
+
+ case EM_SETWORDBREAKPROC:
+ if (lpmpex->Parm16.WndProc.lParam) {
+
+ LONG l;
+
+ l = lpmpex->Parm16.WndProc.lParam;
+
+ //
+ // FEATURE-O-RAMA
+ //
+ // if the selector already has the high bit on then turn off bit 2
+ // of the selector (the LDT bit, which should always be on). we
+ // need a way to not blindly strip off the high bit in our wndproc.
+ //
+
+ if (l & WNDPROC_WOW) {
+ WOW32ASSERT(l & WOWCLASS_VIRTUAL_NOT_BIT31);
+ l &= ~WOWCLASS_VIRTUAL_NOT_BIT31;
+ }
+
+ lpmpex->lParam = l | WNDPROC_WOW;
+ LOGDEBUG (0, ("WOW::WMSGEM.C: EM_SETWORDBREAKPROC: lpmpex->Parm16.WndProc.lParam = %08lx, new lpmpex->Parm16.WndProc.lParam = %08lx\n", lpmpex->Parm16.WndProc.lParam, lpmpex->lParam));
+
+ }
+ break;
+
+ case EM_GETSEL + 0x07:
+ case EM_GETSEL + 0x0F:
+ case EM_GETSEL + 0x10:
+ lpmpex->uMsg = 0;
+ break;
+ } // switch
+ }
+ return TRUE;
+}
+
+
+VOID FASTCALL UnThunkEMMsg16(LPMSGPARAMEX lpmpex)
+{
+
+ LPARAM lParam = lpmpex->Parm16.WndProc.lParam;
+ LPARAM lParamNew = lpmpex->lParam;
+
+ switch(lpmpex->uMsg) {
+
+ case EM_SETSEL:
+
+ // EM_SETSEL no longer positions the caret on NT as Win3.1 did. The new
+ // procedure is to post or send an EM_SETSEL message and then if you
+ // want the caret to be scrolled into view you send an EM_SCROLLCARET
+ // message. This code will do this to emulate the Win 3.1 EM_SETSEL
+ // correctly on NT.
+
+ if (!lpmpex->Parm16.WndProc.wParam) {
+ DWORD dwT;
+
+ if (POSTMSG(dwT))
+ PostMessage(lpmpex->hwnd, EM_SCROLLCARET, 0, 0 );
+ else
+ SendMessage(lpmpex->hwnd, EM_SCROLLCARET, 0, 0 );
+ }
+ break;
+
+ case EM_GETHANDLE:
+ lpmpex->lReturn = GETHMEM16(lpmpex->lReturn);
+ break;
+
+ case EM_GETRECT:
+ if (lParamNew) {
+ putrect16((VPRECT16)lParam, (LPRECT)lParamNew);
+ }
+ break;
+
+ case EM_REPLACESEL:
+ if (lParamNew) {
+ LocalFree ((HLOCAL)lParamNew);
+ }
+ break;
+
+ case EM_SETTABSTOPS:
+ if (lpmpex->Parm16.WndProc.wParam > 0) {
+ STACKORHEAPFREE((LPINT)lParamNew, lpmpex->MsgBuffer);
+ }
+
+ case EM_GETWORDBREAKPROC:
+ if (lpmpex->lReturn) {
+ if (lpmpex->lReturn & WNDPROC_WOW) {
+
+ LOGDEBUG (0, ("WOW::WMSGEM.C: EM_GETWORDBREAKPROC: lReturn = %08lx ", lpmpex->lReturn));
+ lpmpex->lReturn = lpmpex->lReturn & (~WNDPROC_WOW);
+
+ //
+ // if the actual selector had the high bit on then we turned off
+ // bit 2 of the selector (the LDT bit, which will always be on)
+ //
+
+ if (!(lpmpex->lReturn & WOWCLASS_VIRTUAL_NOT_BIT31)) {
+ lpmpex->lReturn |= (WNDPROC_WOW | WOWCLASS_VIRTUAL_NOT_BIT31);
+ }
+
+ LOGDEBUG (0, (" and new lReturn = %08lx\n", lpmpex->lReturn));
+ }
+ else {
+ PARM16 Parm16;
+ LONG lReturn;
+
+ if (!WordBreakProc16) {
+
+ W32WordBreakProc = (WBP)(lpmpex->lReturn);
+
+ Parm16.SubClassProc.iOrdinal = FUN_WOWWORDBREAKPROC;
+
+ if (!CallBack16(RET_SUBCLASSPROC, &Parm16, (VPPROC)NULL,
+ (PVPVOID)&lReturn)) {
+ WOW32ASSERT(FALSE);
+ WordBreakProc16 = lpmpex->lReturn;
+ }
+ }
+ else {
+ lpmpex->lReturn = WordBreakProc16;
+ }
+ }
+ }
+ break;
+ }
+}
diff --git a/private/mvdm/wow32/wmsgem.h b/private/mvdm/wow32/wmsgem.h
new file mode 100644
index 000000000..6a6040475
--- /dev/null
+++ b/private/mvdm/wow32/wmsgem.h
@@ -0,0 +1,21 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSGEM.H
+ * WOW32 16-bit message thunks
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* Function prototypes
+ */
+PSZ GetEMMsgName(WORD wMsg);
+
+BOOL FASTCALL ThunkEMMsg16(LPMSGPARAMEX lpmpex);
+VOID FASTCALL UnThunkEMMsg16(LPMSGPARAMEX lpmpex);
diff --git a/private/mvdm/wow32/wmsglb.c b/private/mvdm/wow32/wmsglb.c
new file mode 100644
index 000000000..2dd8ffbc8
--- /dev/null
+++ b/private/mvdm/wow32/wmsglb.c
@@ -0,0 +1,243 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSGLB.C
+ * WOW32 16-bit message thunks
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wmsglb.c);
+
+
+#ifdef DEBUG
+
+MSGINFO amiLB[] = {
+ {OLDLB_ADDSTRING, "LB_ADDSTRING"}, // 0x0401
+ {OLDLB_INSERTSTRING, "LB_INSERTSTRING"}, // 0x0402
+ {OLDLB_DELETESTRING, "LB_DELETESTRING"}, // 0x0403
+ {OLDLB_RESETCONTENT, "LB_RESETCONTENT"}, // 0x0405
+ {OLDLB_SETSEL, "LB_SETSEL"}, // 0x0406
+ {OLDLB_SETCURSEL, "LB_SETCURSEL"}, // 0x0407
+ {OLDLB_GETSEL, "LB_GETSEL"}, // 0x0408
+ {OLDLB_GETCURSEL, "LB_GETCURSEL"}, // 0x0409
+ {OLDLB_GETTEXT, "LB_GETTEXT"}, // 0x040A
+ {OLDLB_GETTEXTLEN, "LB_GETTEXTLEN"}, // 0x040B
+ {OLDLB_GETCOUNT, "LB_GETCOUNT"}, // 0x040C
+ {OLDLB_SELECTSTRING, "LB_SELECTSTRING"}, // 0x040D
+ {OLDLB_DIR, "LB_DIR"}, // 0x040E
+ {OLDLB_GETTOPINDEX, "LB_GETTOPINDEX"}, // 0x040F
+ {OLDLB_FINDSTRING, "LB_FINDSTRING"}, // 0x0410
+ {OLDLB_GETSELCOUNT, "LB_GETSELCOUNT"}, // 0x0411
+ {OLDLB_GETSELITEMS, "LB_GETSELITEMS"}, // 0x0412
+ {OLDLB_SETTABSTOPS, "LB_SETTABSTOPS"}, // 0x0413
+ {OLDLB_GETHORIZONTALEXTENT, "LB_GETHORIZONTALEXTENT"}, // 0x0414
+ {OLDLB_SETHORIZONTALEXTENT, "LB_SETHORIZONTALEXTENT"}, // 0x0415
+ {OLDLB_SETCOLUMNWIDTH, "LB_SETCOLUMNWIDTH"}, // 0x0416
+ {OLDLB_ADDFILE, "LB_ADDFILE"}, // 0x0417
+ {OLDLB_SETTOPINDEX, "LB_SETTOPINDEX"}, // 0x0418
+ {OLDLB_GETITEMRECT, "LB_GETITEMRECT"}, // 0x0419
+ {OLDLB_GETITEMDATA, "LB_GETITEMDATA"}, // 0x041A
+ {OLDLB_SETITEMDATA, "LB_SETITEMDATA"}, // 0x041B
+ {OLDLB_SELITEMRANGE, "LB_SELITEMRANGE"}, // 0x041C
+ {OLDLB_SETANCHORINDEX, "LB_SETANCHORINDEX"}, // 0x041D
+ {OLDLB_GETANCHORINDEX, "LB_GETANCHORINDEX"}, // 0x041E
+ {OLDLB_SETCARETINDEX, "LB_SETCARETINDEX"}, // 0x041F
+ {OLDLB_GETCARETINDEX, "LB_GETCARETINDEX"}, // 0x0420
+ {OLDLB_SETITEMHEIGHT, "LB_SETITEMHEIGHT"}, // 0x0421
+ {OLDLB_GETITEMHEIGHT, "LB_GETITEMHEIGHT"}, // 0x0422
+ {OLDLB_FINDSTRINGEXACT, "LB_FINDSTRINGEXACT"}, // 0x0423
+ {OLDLBCB_CARETON, "LBCB_CARETON"}, // 0x0424
+ {OLDLBCB_CARETOFF, "LBCB_CARETOFF"}, // 0x0425
+};
+
+PSZ GetLBMsgName(WORD wMsg)
+{
+ INT i;
+ register PMSGINFO pmi;
+
+ for (pmi=amiLB,i=NUMEL(amiLB); i>0; i--,pmi++)
+ if ((WORD)pmi->uMsg == wMsg)
+ return pmi->pszMsgName;
+ return GetWMMsgName(wMsg);
+}
+
+#endif
+
+
+BOOL FASTCALL ThunkLBMsg16(LPMSGPARAMEX lpmpex)
+{
+ register PWW pww;
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+
+ LOGDEBUG(7,(" Thunking 16-bit list box message %s(%04x)\n", (LPSZ)GetLBMsgName(wMsg), wMsg));
+
+ wMsg -= WM_USER + 1;
+
+ //
+ // For app defined (control) messages that are out of range
+ // return TRUE.
+ //
+ // ChandanC Sept-15-1992
+ //
+
+ if (wMsg < (LBCB_CARETOFF - LB_ADDSTRING + 1)) {
+
+ switch(lpmpex->uMsg = wMsg + LB_ADDSTRING) {
+
+ case LB_SELECTSTRING:
+ case LB_FINDSTRING:
+ case LB_FINDSTRINGEXACT:
+ case LB_INSERTSTRING:
+ case LB_ADDSTRING:
+ if (!(pww = lpmpex->pww))
+ return FALSE;
+
+ if (!(pww->dwStyle & (LBS_OWNERDRAWFIXED|LBS_OWNERDRAWVARIABLE)) ||
+ (pww->dwStyle & (LBS_HASSTRINGS))) {
+ GETPSZPTR(lpmpex->Parm16.WndProc.lParam, (LPSZ)lpmpex->lParam);
+ }
+ break;
+
+ case LB_DIR:
+ GETPSZPTR(lpmpex->Parm16.WndProc.lParam, (LPSZ)lpmpex->lParam);
+ break;
+
+ case LB_GETTEXT:
+ if (NULL != (pww = lpmpex->pww)) {
+ register PTHUNKTEXTDWORD pthkdword = (PTHUNKTEXTDWORD)lpmpex->MsgBuffer;
+
+ // we set this as a flag to indicate that we retrieve a dword
+ // instead of a string there. In case when hooks are installed
+ // this code prevents RISC platforms from malfunctioning in
+ // kernel (they have code like this:
+ // try {
+ // <assign to original ptr here>
+ // }
+ // except(1) {
+ // <put error message in debug>
+ // }
+ // which causes this message not to return the proper value)
+ // See walias.h for definition of THUNKTEXTDWORD structure as
+ // well as MSGPARAMEX structure
+ // this code is complemented in UnThunkLBMsg16
+ //
+ // Application: PeachTree Accounting v3.5
+
+ pthkdword->fDWORD = (pww->dwStyle & (LBS_OWNERDRAWFIXED|LBS_OWNERDRAWVARIABLE)) &&
+ !(pww->dwStyle & (LBS_HASSTRINGS));
+
+ if (pthkdword->fDWORD) {
+ lpmpex->lParam = (LPARAM)(LPVOID)&pthkdword->dwDataItem;
+ break;
+ }
+ }
+ else {
+ register PTHUNKTEXTDWORD pthkdword = (PTHUNKTEXTDWORD)lpmpex->MsgBuffer;
+ pthkdword->fDWORD = FALSE;
+ }
+
+ GETPSZPTR(lpmpex->Parm16.WndProc.lParam, (LPSZ)lpmpex->lParam);
+ break;
+
+ case LB_GETITEMRECT:
+ lpmpex->lParam = (LONG)lpmpex->MsgBuffer;
+ break;
+
+ case LB_GETSELITEMS:
+ (PVOID)lpmpex->lParam = STACKORHEAPALLOC(lpmpex->Parm16.WndProc.wParam * sizeof(INT),
+ sizeof(lpmpex->MsgBuffer), lpmpex->MsgBuffer);
+ break;
+
+ case LB_SETSEL:
+ // sign extend
+ {
+ LPARAM lParam = lpmpex->Parm16.WndProc.lParam;
+ lpmpex->lParam = (LOWORD(lParam) == 0xffff) ?
+ INT32(LOWORD(lParam)) : (LONG)lParam;
+ }
+ break;
+
+ case LB_SETTABSTOPS:
+ // apparently lParam is a pointer even if wParam == 1. Recorder passes
+ // the data so. - nandurir
+
+ {
+ INT cItems = INT32(lpmpex->Parm16.WndProc.wParam);
+ if (cItems > 0) {
+ (PVOID)lpmpex->lParam = STACKORHEAPALLOC(cItems * sizeof(INT),
+ sizeof(lpmpex->MsgBuffer), lpmpex->MsgBuffer);
+ getintarray16((VPINT16)lpmpex->Parm16.WndProc.lParam, cItems, (LPINT)lpmpex->lParam);
+ }
+ }
+ break;
+
+ case LB_ADDSTRING + 3:
+ lpmpex->uMsg = 0;
+ break;
+
+ }
+ }
+ return TRUE;
+}
+
+
+VOID FASTCALL UnThunkLBMsg16(LPMSGPARAMEX lpmpex)
+{
+ switch(lpmpex->uMsg) {
+
+ case LB_GETTEXT:
+ {
+ register PTHUNKTEXTDWORD pthkdword = (PTHUNKTEXTDWORD)lpmpex->MsgBuffer;
+
+ if (pthkdword->fDWORD) {
+ // this is a dword, not a string
+ // assign the dword as unaligned
+ UNALIGNED DWORD *lpdwDataItem;
+
+ GETVDMPTR((lpmpex->Parm16.WndProc.lParam), sizeof(DWORD), lpdwDataItem);
+ *lpdwDataItem = pthkdword->dwDataItem;
+ FREEVDMPTR(lpdwDataItem);
+ break;
+ }
+
+ }
+
+ // fall through to the common code
+
+
+ case LB_ADDSTRING: // BUGBUG 3-Jul-1991 JeffPar: for owner-draw list boxes, this can just be a 32-bit number
+ case LB_DIR:
+ case LB_FINDSTRING: // BUGBUG 3-Jul-1991 JeffPar: for owner-draw list boxes, this can just be a 32-bit number
+ case LB_FINDSTRINGEXACT:
+ case LB_INSERTSTRING:
+ case LB_SELECTSTRING:
+ FREEPSZPTR((LPSZ)lpmpex->lParam);
+ break;
+
+ case LB_GETITEMRECT:
+ if ((lpmpex->lParam) && (lpmpex->lReturn != -1L)) {
+ putrect16((VPRECT16)lpmpex->Parm16.WndProc.lParam, (LPRECT)lpmpex->lParam);
+ }
+ break;
+
+ case LB_GETSELITEMS:
+ PUTINTARRAY16V((VPINT16)lpmpex->Parm16.WndProc.lParam, (INT)(lpmpex->lReturn), (LPINT)lpmpex->lParam);
+ STACKORHEAPFREE((LPINT)lpmpex->lParam, lpmpex->MsgBuffer);
+ break;
+
+ case LB_SETTABSTOPS:
+ if (lpmpex->Parm16.WndProc.wParam > 0) {
+ STACKORHEAPFREE((LPINT)lpmpex->lParam, lpmpex->MsgBuffer);
+ }
+ break;
+ }
+}
diff --git a/private/mvdm/wow32/wmsglb.h b/private/mvdm/wow32/wmsglb.h
new file mode 100644
index 000000000..ec770f616
--- /dev/null
+++ b/private/mvdm/wow32/wmsglb.h
@@ -0,0 +1,21 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSGLB.H
+ * WOW32 16-bit message thunks
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* Function prototypes
+ */
+PSZ GetLBMsgName(WORD wMsg);
+
+BOOL FASTCALL ThunkLBMsg16(LPMSGPARAMEX lpmpex);
+VOID FASTCALL UnThunkLBMsg16(LPMSGPARAMEX lpmpex);
diff --git a/private/mvdm/wow32/wmsgsbm.c b/private/mvdm/wow32/wmsgsbm.c
new file mode 100644
index 000000000..009e35244
--- /dev/null
+++ b/private/mvdm/wow32/wmsgsbm.c
@@ -0,0 +1,136 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSGSBM.C
+ * WOW32 16-bit message thunks for SCROLLBARs
+ *
+ * History:
+ * Created 10-Jun-1992 by Bob Day (bobday)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wmsgbm.c);
+
+
+#ifdef DEBUG
+
+MSGINFO amiSBM[] = {
+ {OLDSBM_SETPOS, "SBM_SETPOS"}, // 0x0400
+ {OLDSBM_GETPOS, "SBM_GETPOS"}, // 0x0401
+ {OLDSBM_SETRANGE, "SBM_SETRANGE"}, // 0x0402
+ {OLDSBM_GETRANGE, "SBM_GETRANGE"}, // 0x0403
+ {OLDSBM_ENABLEARROWS,"SBM_ENABLE_ARROWS"}, // 0x0404
+};
+
+PSZ GetSBMMsgName(WORD wMsg)
+{
+ INT i;
+ register PMSGINFO pmi;
+
+ for (pmi=amiSBM,i=NUMEL(amiSBM); i>0; i--,pmi++)
+ if ((WORD)pmi->uMsg == wMsg)
+ return pmi->pszMsgName;
+ return GetWMMsgName(wMsg);
+}
+
+#endif
+
+
+BOOL FASTCALL ThunkSBMMsg16(LPMSGPARAMEX lpmpex)
+{
+ WORD wMsg = lpmpex->Parm16.WndProc.wMsg;
+ LOGDEBUG(7,(" Thunking 16-bit scrollbar message %s(%04x)\n", (LPSZ)GetSBMMsgName(wMsg), wMsg));
+
+ wMsg -= WM_USER;
+
+ //
+ // For app defined (control) messages that are out of range
+ // return TRUE.
+ //
+ // ChandanC Sept-15-1992
+ //
+
+
+ if (wMsg < (SBM_ENABLE_ARROWS - SBM_SETPOS + 1)) {
+ switch(lpmpex->uMsg = wMsg + SBM_SETPOS) {
+
+ // The following messages should not require thunking, because
+ // they contain no pointers, handles, or rearranged message parameters,
+ // so consequently they are not documented in great detail here:
+ //
+ // SBM_SETPOS (requires minimal thunking)
+ // SBM_GETPOS
+ // SBM_ENABLE_ARROWS
+ //
+
+ case SBM_GETRANGE:
+
+ //
+ // Changed semantics for this message to support 32-bit
+ // scroll bar ranges (vs. 16-bit).
+ //
+ // Win16:
+ // posMin = LOWORD(SendMessage(hwnd, SBM_GETRANGE, 0, 0));
+ // posMax = HIWORD(SendMessage(hwnd, SBM_GETRANGE, 0, 0));
+ //
+ // Win32:
+ // SendMessage(hwnd, SBM_GETRANGE,
+ // (WPARAM) &posMin, (LPARAM) &posMax);
+ //
+
+ // Allocate buffers for 32-bit scrollbar proc to put
+ // posMin and posMax in.
+
+ lpmpex->uParam = (UINT)lpmpex->MsgBuffer;
+ lpmpex->lParam = (LONG)((UINT *)lpmpex->uParam + 1);
+ break;
+
+ case SBM_SETRANGE:
+
+ //
+ // Changed semantics to support 32-bit scroll bar range:
+ //
+ // Win16:
+ // SendMessage(hwnd, SBM_SETRANGE, fRedraw, MAKELONG(posMin, posMax);
+ //
+ // Win32:
+ // SendMessage(hwnd, fRedraw ? SBM_SETRANGE : SBM_SETRANGEREDRAW,
+ // posMin, posMax);
+ //
+
+ if (lpmpex->Parm16.WndProc.wParam)
+ lpmpex->uMsg = SBM_SETRANGEREDRAW;
+
+ lpmpex->uParam = INT32(LOWORD(lpmpex->Parm16.WndProc.lParam));
+ lpmpex->lParam = INT32(HIWORD(lpmpex->Parm16.WndProc.lParam));
+ break;
+
+ case SBM_SETPOS:
+ lpmpex->uParam = INT32(lpmpex->Parm16.WndProc.wParam); // sign-extend the position
+ break;
+ }
+ }
+ return TRUE;
+}
+
+
+VOID FASTCALL UnThunkSBMMsg16(LPMSGPARAMEX lpmpex)
+{
+ switch (lpmpex->uMsg) {
+
+ case SBM_GETRANGE:
+
+ if (lpmpex->uParam && lpmpex->lParam) {
+ lpmpex->lReturn = MAKELONG(*(UINT *)lpmpex->uParam,
+ *(UINT *)lpmpex->lParam);
+ }
+ break;
+ }
+
+}
diff --git a/private/mvdm/wow32/wmsgsbm.h b/private/mvdm/wow32/wmsgsbm.h
new file mode 100644
index 000000000..8ef91b046
--- /dev/null
+++ b/private/mvdm/wow32/wmsgsbm.h
@@ -0,0 +1,21 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSGSBM.H
+ * WOW32 16-bit message thunks for SCROLLBARs
+ *
+ * History:
+ * Created 10-Jun-1992 by Bob Day (bobday)
+--*/
+
+
+
+/* Function prototypes
+ */
+PSZ GetSBMMsgName(WORD wMsg);
+
+BOOL FASTCALL ThunkSBMMsg16(LPMSGPARAMEX lpmpex);
+VOID FASTCALL UnThunkSBMMsg16(LPMSGPARAMEX lpmpex);
diff --git a/private/mvdm/wow32/wmtbl32.c b/private/mvdm/wow32/wmtbl32.c
new file mode 100644
index 000000000..39920374c
--- /dev/null
+++ b/private/mvdm/wow32/wmtbl32.c
@@ -0,0 +1,1324 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMTBL32.C
+ * WOW32 32-bit message thunk tables
+ *
+ * History:
+ * Created 19-Feb-1992 by Chandan Chauhan (ChandanC)
+ * Changed 12-May-1992 by Mike Tricker (MikeTri) Added MultiMedia calls - 3A0 to 3CF
+ * Changed 30-Apr-1995 by Dave Hart updated with new/changed messages, removed
+ * message numbers from name text, replaced "EMPTY!0x02A7" with
+ * NULL and changed lookup code to display message number when
+ * NULL.
+--*/
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wmtbl32.c);
+
+//
+// Note: If any of the message thunks is changed from a 'validthunk' to
+// WM32NoThunking make sure that 16->32 messages are not affected
+// (see thunkwmmsg16/unthunkwmmsg16 in msg16.c). If a 16->32 thunk
+// does exist for the message in question you must use W32Thunk16To32
+// instead of WM32NoThunking.
+// - nanduri
+
+//
+// The message names present in the checked build of this table are used by
+// GetWMMsgName, which is called in lots of places on checked builds.
+//
+// - davehart
+//
+
+M32 aw32Msg[] = {
+ {W32MSGFUN(WM32NoThunking, "WM_NULL")},
+ {W32MSGFUN(WM32Create, "WM_CREATE")},
+ {W32MSGFUN(WM32Destroy, "WM_DESTROY")},
+ {W32MSGFUN(WM32NoThunking, "WM_MOVE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_SIZEWAIT")},
+ {W32MSGFUN(WM32NoThunking, "WM_SIZE")},
+ {W32MSGFUN(WM32Activate, "WM_ACTIVATE")},
+ {W32MSGFUN(WM32SetFocus, "WM_SETFOCUS")},
+
+ // 0x8
+ {W32MSGFUN(WM32SetFocus, "WM_KILLFOCUS")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_SETVISIBLE")},
+ {W32MSGFUN(WM32NoThunking, "WM_ENABLE")},
+ {W32MSGFUN(WM32Thunk16To32, "WM_SETREDRAW")},
+ {W32MSGFUN(WM32SetText, "WM_SETTEXT")},
+ {W32MSGFUN(WM32GetText, "WM_GETTEXT")},
+ {W32MSGFUN(WM32NoThunking, "WM_GETTEXTLENGTH")},
+ {W32MSGFUN(WM32NCPaint, "WM_PAINT")},
+
+ // 0x10
+ {W32MSGFUN(WM32NoThunking, "WM_CLOSE")},
+ {W32MSGFUN(WM32NoThunking, "WM_QUERYENDSESSION")},
+ {W32MSGFUN(WM32NoThunking, "WM_QUIT")},
+ {W32MSGFUN(WM32NoThunking, "WM_QUERYOPEN")},
+ {W32MSGFUN(WM32EraseBkGnd, "WM_ERASEBKGND")},
+ {W32MSGFUN(WM32NoThunking, "WM_SYSCOLORCHANGE")},
+ {W32MSGFUN(WM32NoThunking, "WM_ENDSESSION")},
+ {W32MSGFUN(WM32NoThunking, "WM_SYSTEMERROR")},
+
+ // 0x18
+ {W32MSGFUN(WM32NoThunking, "WM_SHOWWINDOW")},
+ {W32MSGFUN(WM32CtlColor, "WM_CTLCOLOR")},
+ {W32MSGFUN(WM32SetText, "WM_WININICHANGE")},
+ {W32MSGFUN(WM32SetText, "WM_DEVMODECHANGE")},
+ {W32MSGFUN(WM32ActivateApp, "WM_ACTIVATEAPP")},
+ {W32MSGFUN(WM32NoThunking, "WM_FONTCHANGE")},
+ {W32MSGFUN(WM32NoThunking, "WM_TIMECHANGE")},
+ {W32MSGFUN(WM32NoThunking, "WM_CANCELMODE")},
+
+ // 0x20
+ {W32MSGFUN(WM32SetFocus, "WM_SETCURSOR")},
+ {W32MSGFUN(WM32SetFocus, "WM_MOUSEACTIVATE")},
+ {W32MSGFUN(WM32NoThunking, "WM_CHILDACTIVATE")},
+ {W32MSGFUN(WM32NoThunking, "WM_QUEUESYNC")},
+ {W32MSGFUN(WM32GetMinMaxInfo, "WM_GETMINMAXINFO")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_LOGOFF")},
+ {W32MSGFUN(WM32NoThunking, "WM_PAINTICON")},
+ {W32MSGFUN(WM32EraseBkGnd, "WM_ICONERASEBKGND")},
+
+ // 0x28
+ {W32MSGFUN(WM32NextDlgCtl, "WM_NEXTDLGCTL")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_ALTTABACTIVE")},
+ {W32MSGFUN(WM32NoThunking, "WM_SPOOLERSTATUS")},
+ {W32MSGFUN(WM32DrawItem, "WM_DRAWITEM")},
+ {W32MSGFUN(WM32MeasureItem, "WM_MEASUREITEM")},
+ {W32MSGFUN(WM32DeleteItem, "WM_DELETEITEM")},
+ {W32MSGFUN(WM32VKeyToItem, "WM_VKEYTOITEM")},
+ {W32MSGFUN(WM32VKeyToItem, "WM_CHARTOITEM")},
+
+ // 0x30
+ {W32MSGFUN(WM32SetFont, "WM_SETFONT")},
+ {W32MSGFUN(WM32GetFont, "WM_GETFONT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_SETHOTKEY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_GETHOTKEY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_FILESYSCHANGE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_ISACTIVEICON")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_QUERYPARKICON")},
+ {W32MSGFUN(WM32QueryDragIcon, "WM_QUERYDRAGICON")},
+
+ // 0x38
+ {W32MSGFUN(WM32WinHelp, "WM_WINHELP")},
+ {W32MSGFUN(WM32CompareItem, "WM_COMPAREITEM")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_FULLSCREEN")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_CLIENTSHUTDOWN")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_DDEMLEVENT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32MMCalcScroll, "MM_CALCSCROLL")},
+
+ // 0x40
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_TESTING")},
+ {W32MSGFUN(WM32NoThunking, "WM_COMPACTING")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_OTHERWINDOWCREATED")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_OTHERWINDOWDESTROYED")},
+ {W32MSGFUN(WM32NoThunking, "WM_COMMNOTIFY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_HOTKEYEVENT")},
+ {W32MSGFUN(WM32WindowPosChanging, "WM_WINDOWPOSCHANGING")},
+ {W32MSGFUN(WM32WindowPosChanging, "WM_WINDOWPOSCHANGED")},
+
+ // 0x48
+ {W32MSGFUN(WM32NoThunking, "WM_POWER")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_COPYGLOBALDATA")},
+ {W32MSGFUN(WM32CopyData, "WM_COPYDATA")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_CANCELJOURNAL")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_LOGONNOTIFY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_KEYF1")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_NOTIFY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_ACCESS_WINDOW")},
+
+ // 0x50
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_INPUTLANGCHANGEREQUEST")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_INPUTLANGCHANGE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_TCARD")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_HELP")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_USERCHANGED")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_NOTIFYFORMAT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x58
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x60
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x68
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x70
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_FINALDESTROY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_MEASUREITEM_CLIENTDATA")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x78
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_CONTEXTMENU")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_STYLECHANGING")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_STYLECHANGED")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_DISPLAYCHANGE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_GETICON")},
+
+ // 0x80
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_SETICON")},
+ {W32MSGFUN(WM32Create, "WM_NCCREATE")},
+ {W32MSGFUN(WM32NoThunking, "WM_NCDESTROY")},
+ {W32MSGFUN(WM32NCCalcSize, "WM_NCCALCSIZE")},
+ {W32MSGFUN(WM32NoThunking, "WM_NCHITTEST")},
+ {W32MSGFUN(WM32NCPaint, "WM_NCPAINT")},
+ {W32MSGFUN(WM32Activate, "WM_NCACTIVATE")},
+ {W32MSGFUN(WM32GetDlgCode, "WM_GETDLGCODE")},
+
+ // 0x88
+ {W32MSGFUN(WM32NoThunking, "WM_SYNCPAINT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_SYNCTASK")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_KLUDGEMINRECT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x90
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x98
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0xA0
+ {W32MSGFUN(WM32NoThunking, "WM_NCMOUSEMOVE")},
+ {W32MSGFUN(WM32NoThunking, "WM_NCLBUTTONDOWN")},
+ {W32MSGFUN(WM32NoThunking, "WM_NCLBUTTONUP")},
+ {W32MSGFUN(WM32NoThunking, "WM_NCLBUTTONDBLCLK")},
+ {W32MSGFUN(WM32NoThunking, "WM_NCRBUTTONDOWN")},
+ {W32MSGFUN(WM32NoThunking, "WM_NCRBUTTONUP")},
+ {W32MSGFUN(WM32NoThunking, "WM_NCRBUTTONDBLCLK")},
+ {W32MSGFUN(WM32NoThunking, "WM_NCMBUTTONDOWN")},
+
+ // 0xA8
+ {W32MSGFUN(WM32NoThunking, "WM_NCMBUTTONUP")},
+ {W32MSGFUN(WM32NoThunking, "WM_NCMBUTTONDBLCLK")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0xB0
+ {W32MSGFUN(WM32EMControl, "EM_GETSEL")},
+ {W32MSGFUN(WM32EMSetSel, "EM_SETSEL")},
+ {W32MSGFUN(WM32EMGetRect, "EM_GETRECT")},
+ {W32MSGFUN(WM32EMSetRect, "EM_SETRECT")},
+ {W32MSGFUN(WM32EMSetRect, "EM_SETRECTNP")},
+ {W32MSGFUN(WM32EMControl, "EM_SCROLL")},
+ {W32MSGFUN(WM32EMLineScroll, "EM_LINESCROLL")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "EM_SCROLLCARET")},
+
+ // 0xB8
+ {W32MSGFUN(WM32EMControl, "EM_GETMODIFY")},
+ {W32MSGFUN(WM32EMControl, "EM_SETMODIFY")},
+ {W32MSGFUN(WM32EMControl, "EM_GETLINECOUNT")},
+ {W32MSGFUN(WM32EMControl, "EM_LINEINDEX")},
+ {W32MSGFUN(WM32EMControl, "EM_SETHANDLE")},
+ {W32MSGFUN(WM32EMControl, "EM_GETHANDLE")},
+ {W32MSGFUN(WM32EMControl, "EM_GETTHUMB")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0xC0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32EMControl, "EM_LINELENGTH")},
+ {W32MSGFUN(WM32EMReplaceSel, "EM_REPLACESEL")},
+ {W32MSGFUN(WM32SetFont, "EM_SETFONT")},
+ {W32MSGFUN(WM32EMGetLine, "EM_GETLINE")},
+ {W32MSGFUN(WM32EMControl, "EM_LIMITTEXT")},
+ {W32MSGFUN(WM32EMControl, "EM_CANUNDO")},
+ {W32MSGFUN(WM32EMControl, "EM_UNDO")},
+
+ // 0xC8
+ {W32MSGFUN(WM32EMControl, "EM_FMTLINES")},
+ {W32MSGFUN(WM32EMControl, "EM_LINEFROMCHAR")},
+ {W32MSGFUN(WM32EMControl, "EM_SETWORDBREAK")},
+ {W32MSGFUN(WM32EMSetTabStops, "EM_SETTABSTOPS")},
+ {W32MSGFUN(WM32EMControl, "EM_SETPASSWORDCHAR")},
+ {W32MSGFUN(WM32EMControl, "EM_EMPTYUNDOBUFFER")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "EM_GETFIRSTVISIBLELINE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "EM_SETREADONLY")},
+
+ // 0xD0
+ {W32MSGFUN(WM32EMSetWordBreakProc,"EM_SETWORDBREAKPROC")},
+ {W32MSGFUN(WM32EMGetWordBreakProc,"EM_GETWORDBREAKPROC")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "EM_GETPASSWORDCHAR")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "EM_SETMARGINS")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "EM_GETMARGINS")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "EM_GETLIMITTEXT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "EM_POSFROMCHAR")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "EM_CHARFROMPOS")},
+
+ // 0xD8
+ {W32MSGFUN(WM32UNDOCUMENTED, "EM_MSGMAX")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0xE0
+ {W32MSGFUN(WM32SBMControl, "SBM_SETPOS")},
+ {W32MSGFUN(WM32SBMControl, "SBM_GETPOS")},
+ {W32MSGFUN(WM32SBMSetRange, "SBM_SETRANGE")},
+ {W32MSGFUN(WM32SBMGetRange, "SBM_GETRANGE")},
+ {W32MSGFUN(WM32SBMControl, "SBM_ENABLE_ARROWS")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32SBMSetRange, "SBM_SETRANGEREDRAW")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0xE8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "SBM_SETSCROLLINFO")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "SBM_GETSCROLLINFO")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0xF0
+ {W32MSGFUN(WM32BMControl, "BM_GETCHECK")},
+ {W32MSGFUN(WM32BMControl, "BM_SETCHECK")},
+ {W32MSGFUN(WM32BMControl, "BM_GETSTATE")},
+ {W32MSGFUN(WM32BMControl, "BM_SETSTATE")},
+ {W32MSGFUN(WM32BMControl, "BM_SETSTYLE")},
+ {W32MSGFUN(WM32BMClick, "BM_CLICK")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "BM_GETIMAGE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "BM_SETIMAGE")},
+
+ // 0xF8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x100
+ {W32MSGFUN(WM32NoThunking, "WM_KEYDOWN")},
+ {W32MSGFUN(WM32NoThunking, "WM_KEYUP")},
+ {W32MSGFUN(WM32NoThunking, "WM_CHAR")},
+ {W32MSGFUN(WM32NoThunking, "WM_DEADCHAR")},
+ {W32MSGFUN(WM32NoThunking, "WM_SYSKEYDOWN")},
+ {W32MSGFUN(WM32NoThunking, "WM_SYSKEYUP")},
+ {W32MSGFUN(WM32NoThunking, "WM_SYSCHAR")},
+ {W32MSGFUN(WM32NoThunking, "WM_SYSDEADCHAR")},
+
+ // 0x108
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_YOMICHAR/WM_CONVERTREQUESTEX")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_CONVERTREQUEST")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_CONVERTRESULT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_INTERIM")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_STARTCOMPOSITION")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_ENDCOMPOSITION")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_COMPOSITION")},
+
+ // 0x110
+ {W32MSGFUN(WM32SetFocus , "WM_INITDIALOG")},
+ {W32MSGFUN(WM32Command, "WM_COMMAND")},
+ {W32MSGFUN(WM32Thunk16To32, "WM_SYSCOMMAND")},
+ {W32MSGFUN(WM32Timer, "WM_TIMER")},
+ {W32MSGFUN(WM32HScroll, "WM_HSCROLL")},
+ {W32MSGFUN(WM32HScroll, "WM_VSCROLL")},
+ {W32MSGFUN(WM32InitMenu, "WM_INITMENU")},
+ {W32MSGFUN(WM32InitMenu, "WM_INITMENUPOPUP")},
+
+ // 0x118
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_SYSTIMER")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32MenuSelect, "WM_MENUSELECT")},
+
+ // 0x120
+ {W32MSGFUN(WM32MenuChar, "WM_MENUCHAR")},
+ {W32MSGFUN(WM32EnterIdle, "WM_ENTERIDLE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x128
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x130
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_LBTRACKPOINT")},
+ {W32MSGFUN(WM32CtlColor, "WM_CTLCOLORMSGBOX")},
+ {W32MSGFUN(WM32CtlColor, "WM_CTLCOLOREDIT")},
+ {W32MSGFUN(WM32CtlColor, "WM_CTLCOLORLISTBOX")},
+ {W32MSGFUN(WM32CtlColor, "WM_CTLCOLORBTN")},
+ {W32MSGFUN(WM32CtlColor, "WM_CTLCOLORDLG")},
+ {W32MSGFUN(WM32CtlColor, "WM_CTLCOLORSCROLLBAR")},
+
+ // 0x138
+ {W32MSGFUN(WM32CtlColor, "WM_CTLCOLORSTATIC")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x140
+ {W32MSGFUN(WM32CBControl, "CB_GETEDITSEL")},
+ {W32MSGFUN(WM32CBControl, "CB_LIMITTEXT")},
+ {W32MSGFUN(WM32CBControl, "CB_SETEDITSEL")},
+ {W32MSGFUN(WM32CBAddString, "CB_ADDSTRING")},
+ {W32MSGFUN(WM32CBControl, "CB_DELETESTRING")},
+ {W32MSGFUN(WM32CBDir, "CB_DIR")},
+ {W32MSGFUN(WM32CBControl, "CB_GETCOUNT")},
+ {W32MSGFUN(WM32CBControl, "CB_GETCURSEL")},
+
+ // 0x148
+ {W32MSGFUN(WM32CBGetLBText, "CB_GETLBTEXT")},
+ {W32MSGFUN(WM32CBControl, "CB_GETLBTEXTLEN")},
+ {W32MSGFUN(WM32CBAddString, "CB_INSERTSTRING")},
+ {W32MSGFUN(WM32CBControl, "CB_RESETCONTENT")},
+ {W32MSGFUN(WM32CBAddString, "CB_FINDSTRING")},
+ {W32MSGFUN(WM32CBAddString, "CB_SELECTSTRING")},
+ {W32MSGFUN(WM32CBControl, "CB_SETCURSEL")},
+ {W32MSGFUN(WM32CBControl, "CB_SHOWDROPDOWN")},
+
+ // 0x150
+ {W32MSGFUN(WM32CBControl, "CB_GETITEMDATA")},
+ {W32MSGFUN(WM32CBControl, "CB_SETITEMDATA")},
+ {W32MSGFUN(WM32CBGetDropDownControlRect,"CB_GETDROPDOWNCONTROLRECT")},
+ {W32MSGFUN(WM32CBControl, "CB_SETITEMHEIGHT")},
+ {W32MSGFUN(WM32CBControl, "CB_GETITEMHEIGHT")},
+ {W32MSGFUN(WM32CBControl, "CB_SETEXTENDEDUI")},
+ {W32MSGFUN(WM32CBControl, "CB_GETEXTENDEDUI")},
+ {W32MSGFUN(WM32CBControl, "CB_GETDROPPEDSTATE")},
+
+ // 0x158
+ {W32MSGFUN(WM32CBAddString, "CB_FINDSTRINGEXACT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "CB_SETLOCALE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "CB_GETLOCALE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "CB_GETTOPINDEX")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "CB_SETTOPINDEX")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "CB_GETHORIZONTALEXTENT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "CB_SETHORIZONTALEXTENT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "CB_GETDROPPEDWIDTH")},
+
+ // 0x160
+ {W32MSGFUN(WM32UNDOCUMENTED, "CB_SETDROPPEDWIDTH")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "CB_INITSTORAGE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "CB_MSGMAX")},
+ {W32MSGFUN(WM32CBComboFocus, "CBEC_SETCOMBOFOCUS")},
+ {W32MSGFUN(WM32CBComboFocus, "CBEC_KILLCOMBOFOCUS")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x168
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x170
+ {W32MSGFUN(WM32STMControl, "STM_SETICON")},
+ {W32MSGFUN(WM32STMControl, "STM_GETICON")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "STM_SETIMAGE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "STM_GETIMAGE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "STM_MSGMAX")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x178
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x180
+ {W32MSGFUN(WM32LBAddString, "LB_ADDSTRING")},
+ {W32MSGFUN(WM32LBAddString, "LB_INSERTSTRING")},
+ {W32MSGFUN(WM32LBControl, "LB_DELETESTRING")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_SELITEMRANGEEX")},
+ {W32MSGFUN(WM32LBControl, "LB_RESETCONTENT")},
+ {W32MSGFUN(WM32LBSetSel, "LB_SETSEL")},
+ {W32MSGFUN(WM32LBControl, "LB_SETCURSEL")},
+ {W32MSGFUN(WM32LBControl, "LB_GETSEL")},
+
+ // 0x188
+ {W32MSGFUN(WM32LBControl, "LB_GETCURSEL")},
+ {W32MSGFUN(WM32LBGetText, "LB_GETTEXT")},
+ {W32MSGFUN(WM32LBGetTextLen, "LB_GETTEXTLEN")},
+ {W32MSGFUN(WM32LBControl, "LB_GETCOUNT")},
+ {W32MSGFUN(WM32LBAddString, "LB_SELECTSTRING")},
+ {W32MSGFUN(WM32LBDir, "LB_DIR")},
+ {W32MSGFUN(WM32LBControl, "LB_GETTOPINDEX")},
+ {W32MSGFUN(WM32LBAddString, "LB_FINDSTRING")},
+
+ // 0x190
+ {W32MSGFUN(WM32LBControl, "LB_GETSELCOUNT")},
+ {W32MSGFUN(WM32LBGetSelItems, "LB_GETSELITEMS")},
+ {W32MSGFUN(WM32LBSetTabStops, "LB_SETTABSTOPS")},
+ {W32MSGFUN(WM32LBControl, "LB_GETHORIZONTALEXTENT")},
+ {W32MSGFUN(WM32LBControl, "LB_SETHORIZONTALEXTENT")},
+ {W32MSGFUN(WM32LBControl, "LB_SETCOLUMNWIDTH")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_ADDFILE")},
+ {W32MSGFUN(WM32LBControl, "LB_SETTOPINDEX")},
+
+ // 0x198
+ {W32MSGFUN(WM32LBGetItemRect, "LB_GETITEMRECT")},
+ {W32MSGFUN(WM32LBControl, "LB_GETITEMDATA")},
+ {W32MSGFUN(WM32LBControl, "LB_SETITEMDATA")},
+ {W32MSGFUN(WM32LBControl, "LB_SELITEMRANGE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_SETANCHORINDEX")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_GETANCHORINDEX")},
+ {W32MSGFUN(WM32LBControl, "LB_SETCARETINDEX")},
+ {W32MSGFUN(WM32LBControl, "LB_GETCARETINDEX")},
+
+ // 0x1A0
+ {W32MSGFUN(WM32LBControl, "LB_SETITEMHEIGHT")},
+ {W32MSGFUN(WM32LBControl, "LB_GETITEMHEIGHT")},
+ {W32MSGFUN(WM32LBAddString, "LB_FINDSTRINGEXACT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LBCB_CARETON")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LBCB_CARETOFF")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_SETLOCALE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_GETLOCALE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_SETCOUNT")},
+
+ // 0x1A8
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_INITSTORAGE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_ITEMFROMPOINT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_INSERTSTRINGUPPER")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_INSERTSTRINGLOWER")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_ADDSTRINGUPPER")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_ADDSTRINGLOWER")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LBCB_STARTTRACK")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "LBCB_ENDTRACK")},
+
+ // 0x1B0
+ {W32MSGFUN(WM32UNDOCUMENTED, "LB_MSGMAX")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x1B8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x1C0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x1C8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x1D0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x1D8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x1E0
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_SETHMENU")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_GETHMENU")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_SIZEWINDOW")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_OPENHIERARCHY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_CLOSEHIERARCHY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_SELECTITEM")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_CANCELMENUS")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_SELECTFIRSTVALIDITEM")},
+
+ // 0x1E8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_GETPPOPUPMENU")},
+ {W32MSGFUN(WM32MNFindMenuWindow, "MN_FINDMENUWINDOWFROMPOINT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_SHOWPOPUPWINDOW")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_BUTTONDOWN")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_MOUSEMOVE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_BUTTONUP")},
+
+ // 0x1F0
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_SETTIMERTOOPENHIERARCHY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MN_DBLCLK")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x1F8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x200
+ {W32MSGFUN(WM32NoThunking, "WM_MOUSEMOVE")},
+ {W32MSGFUN(WM32NoThunking, "WM_LBUTTONDOWN")},
+ {W32MSGFUN(WM32NoThunking, "WM_LBUTTONUP")},
+ {W32MSGFUN(WM32NoThunking, "WM_LBUTTONDBLCLK")},
+ {W32MSGFUN(WM32NoThunking, "WM_RBUTTONDOWN")},
+ {W32MSGFUN(WM32NoThunking, "WM_RBUTTONUP")},
+ {W32MSGFUN(WM32NoThunking, "WM_RBUTTONDBLCLK")},
+ {W32MSGFUN(WM32NoThunking, "WM_MBUTTONDOWN")},
+
+ // 0x208
+ {W32MSGFUN(WM32NoThunking, "WM_MBUTTONUP")},
+ {W32MSGFUN(WM32NoThunking, "WM_MBUTTONDBLCLK")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x210
+ {W32MSGFUN(WM32ParentNotify, "WM_PARENTNOTIFY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_ENTERMENULOOP")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_EXITMENULOOP")},
+ {W32MSGFUN(WM32NextMenu, "WM_NEXTMENU")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_SIZING")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_CAPTURECHANGED")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_MOVING")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x218
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_POWERBROADCAST")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_DEVICECHANGE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x220
+ {W32MSGFUN(WM32MDICreate, "WM_MDICREATE")},
+ {W32MSGFUN(WM32SetFocus, "WM_MDIDESTROY")},
+ {W32MSGFUN(WM32MDIActivate, "WM_MDIACTIVATE")},
+ {W32MSGFUN(WM32SetFocus, "WM_MDIRESTORE")},
+ {W32MSGFUN(WM32SetFocus, "WM_MDINEXT")},
+ {W32MSGFUN(WM32SetFocus, "WM_MDIMAXIMIZE")},
+ {W32MSGFUN(WM32Thunk16To32, "WM_MDITILE")},
+ {W32MSGFUN(WM32Thunk16To32, "WM_MDICASCADE")},
+
+ // 0x228
+ {W32MSGFUN(WM32NoThunking, "WM_MDIICONARRANGE")},
+ {W32MSGFUN(WM32MDIGetActive, "WM_MDIGETACTIVE")},
+ {W32MSGFUN(WM32DropObject, "WM_DROPOBJECT")},
+ {W32MSGFUN(WM32DropObject, "WM_QUERYDROPOBJECT")},
+ {W32MSGFUN(WM32Thunk16To32, "WM_BEGINDRAG")},
+ {W32MSGFUN(WM32DropObject, "WM_DRAGLOOP")},
+ {W32MSGFUN(WM32DropObject, "WM_DRAGSELECT")},
+ {W32MSGFUN(WM32DropObject, "WM_DRAGMOVE")},
+
+ // 0x230
+ {W32MSGFUN(WM32MDISetMenu, "WM_MDISETMENU")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_ENTERSIZEMOVE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_EXITSIZEMOVE")},
+ {W32MSGFUN(WM32DropFiles, "WM_DROPFILES")},
+ {W32MSGFUN(WM32MDISetMenu, "WM_MDIREFRESHMENU")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x238
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x240
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x248
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x250
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x258
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x260
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x268
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x270
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x278
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x280
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_KANJIFIRST")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_SETCONTEXT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_NOTIFY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_CONTROL")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_COMPOSITIONFULL")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_SELECT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_CHAR")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_SYSTEM")},
+
+ // 0x288
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x290
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_KEYDOWN")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_IME_KEYUP")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x298
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_KANJILAST")},
+
+ // 0x2A0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2A8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2B0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2B8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2C0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2C8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2D0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2D8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2E0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2E8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2F0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x2F8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x300
+ {W32MSGFUN(WM32NoThunking, "WM_CUT")},
+ {W32MSGFUN(WM32NoThunking, "WM_COPY")},
+ {W32MSGFUN(WM32NoThunking, "WM_PASTE")},
+ {W32MSGFUN(WM32NoThunking, "WM_CLEAR")},
+ {W32MSGFUN(WM32NoThunking, "WM_UNDO")},
+ {W32MSGFUN(WM32NoThunking, "WM_RENDERFORMAT")},
+ {W32MSGFUN(WM32NoThunking, "WM_RENDERALLFORMATS")},
+ {W32MSGFUN(WM32NoThunking, "WM_DESTROYCLIPBOARD")},
+
+ // 0x308
+ {W32MSGFUN(WM32NoThunking, "WM_DRAWCLIPBOARD")},
+ {W32MSGFUN(WM32SizeClipBoard, "WM_PAINTCLIPBOARD")},
+ {W32MSGFUN(WM32SetFocus, "WM_VSCROLLCLIPBOARD")},
+ {W32MSGFUN(WM32SizeClipBoard, "WM_SIZECLIPBOARD")},
+ {W32MSGFUN(WM32AskCBFormatName, "WM_ASKCBFORMATNAME")},
+ {W32MSGFUN(WM32ChangeCBChain, "WM_CHANGECBCHAIN")},
+ {W32MSGFUN(WM32SetFocus, "WM_HSCROLLCLIPBOARD")},
+ {W32MSGFUN(WM32NoThunking, "WM_QUERYNEWPALETTE")},
+
+ // 0x310
+ {W32MSGFUN(WM32SetFocus, "WM_PALETTEISCHANGING")},
+ {W32MSGFUN(WM32SetFocus, "WM_PALETTECHANGED")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_HOTKEY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_SYSMENU")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_HOOKMSG")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_EXITPROCESS")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_WAKETHREAD")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_PRINT")},
+
+ // 0x318
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_PRINTCLIENT")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x320
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x328
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x330
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x338
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x340
+ {W32MSGFUN(WM32NotifyWow, "WM_NOTIFYWOW")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x348
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x350
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x358
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_HANDHELDFIRST")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_HANDHELDLAST")},
+
+ // 0x360
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_AFXFIRST")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x368
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x370
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x378
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_AFXLAST")},
+
+ // 0x380
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_PENWINFIRST")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x388
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_PENWINLAST")},
+
+ // 0x390
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_COALESCE_FIRST")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x398
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_COALESCE_LAST")},
+
+ // 0x3A0
+ {W32MSGFUN(WM32NoThunking, "MM_JOY1MOVE")},
+ {W32MSGFUN(WM32NoThunking, "MM_JOY2MOVE")},
+ {W32MSGFUN(WM32NoThunking, "MM_JOY1ZMOVE")},
+ {W32MSGFUN(WM32NoThunking, "MM_JOY2ZMOVE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x3A8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x3B0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32NoThunking, "MM_JOY1BUTTONDOWN")},
+ {W32MSGFUN(WM32NoThunking, "MM_JOY2BUTTONDOWN")},
+ {W32MSGFUN(WM32NoThunking, "MM_JOY1BUTTONUP")},
+
+ // 0x3B8
+ {W32MSGFUN(WM32NoThunking, "MM_JOY2BUTTONUP")},
+ {W32MSGFUN(WM32NoThunking, "MM_MCINOTIFY")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32NoThunking, "MM_WOM_OPEN")},
+ {W32MSGFUN(WM32NoThunking, "MM_WOM_CLOSE")},
+ {W32MSGFUN(WM32NoThunking, "MM_WOM_DONE")},
+ {W32MSGFUN(WM32NoThunking, "MM_WIM_OPEN")},
+ {W32MSGFUN(WM32NoThunking, "MM_WIM_CLOSE")},
+
+ // 0x3C0
+ {W32MSGFUN(WM32NoThunking, "MM_WIM_DATA")},
+ {W32MSGFUN(WM32NoThunking, "MM_MIM_OPEN")},
+ {W32MSGFUN(WM32NoThunking, "MM_MIM_CLOSE")},
+ {W32MSGFUN(WM32NoThunking, "MM_MIM_DATA")},
+ {W32MSGFUN(WM32NoThunking, "MM_MIM_LONGDATA")},
+ {W32MSGFUN(WM32NoThunking, "MM_MIM_ERROR")},
+ {W32MSGFUN(WM32NoThunking, "MM_MIM_LONGERROR")},
+ {W32MSGFUN(WM32NoThunking, "MM_MOM_OPEN")},
+
+ // 0x3C8
+ {W32MSGFUN(WM32NoThunking, "MM_MOM_CLOSE")},
+ {W32MSGFUN(WM32NoThunking, "MM_MOM_DONE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, "MM_MCISYSTEM_STRING")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x3D0
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x3D8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x3E0
+ {W32MSGFUN(WM32DDEInitiate, "WM_DDE_INITIATE")},
+ {W32MSGFUN(WM32DDERequest, "WM_DDE_TERMINATE")},
+ {W32MSGFUN(WM32DDEAdvise, "WM_DDE_ADVISE")},
+ {W32MSGFUN(WM32DDERequest, "WM_DDE_UNADVISE")},
+ {W32MSGFUN(WM32DDEAck, "WM_DDE_ACK")},
+ {W32MSGFUN(WM32DDEData, "WM_DDE_DATA")},
+ {W32MSGFUN(WM32DDERequest, "WM_DDE_REQUEST")},
+ {W32MSGFUN(WM32DDEPoke, "WM_DDE_POKE")},
+
+ // 0x3E8
+ {W32MSGFUN(WM32DDEExecute, "WM_DDE_EXECUTE")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x3F0
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_CBT_RESERVED_FIRST")},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+
+ // 0x3F8
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, NULL)},
+ {W32MSGFUN(WM32UNDOCUMENTED, "WM_CBT_RESERVED_LAST")},
+};
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+INT iMsgMax = NUMEL(aw32Msg);
+PM32 paw32Msg = aw32Msg;
+#endif
+
diff --git a/private/mvdm/wow32/wmtbl32.h b/private/mvdm/wow32/wmtbl32.h
new file mode 100644
index 000000000..281b27d80
--- /dev/null
+++ b/private/mvdm/wow32/wmtbl32.h
@@ -0,0 +1,34 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMTBL32.H
+ * WOW32 32-bit Message Thunkers
+ *
+ * History:
+ * Created 23-Feb-1992 by Chandan Chauhan (ChandanC)
+--*/
+
+
+#define THUNKMSG 1
+#define UNTHUNKMSG 0
+
+
+/* Message dispatch table
+ */
+
+extern M32 aw32Msg[];
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iMsgMax;
+#endif
+
+
+#ifdef DEBUG
+#define WM32UNDOCUMENTED WM32Undocumented
+#else
+#define WM32UNDOCUMENTED WM32NoThunking
+#endif
diff --git a/private/mvdm/wow32/wole2.c b/private/mvdm/wow32/wole2.c
new file mode 100644
index 000000000..23b7e2748
--- /dev/null
+++ b/private/mvdm/wow32/wole2.c
@@ -0,0 +1,371 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1994, Microsoft Corporation
+ *
+ * WOLE2.C
+ * WOW32 Support for OLE2 stuff
+ *
+ * History:
+ * Created 03-May-1994 by Bob Day (bobday)
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wole.c);
+
+/*
+** Under OLE 2.0, the IMessageFilter interface passes HTASKs/THREADIDs. It
+** passes HTASKs in the 16-bit world, and THREADIDs in the 32-bit world. The
+** OLE 2.0 16 <-> 32 interoperability DLLs need a way of converting the
+** HTASK into an appropriate THREADID and back.
+**
+** Really the only place the 16-bit code uses the HTASK is in ole2's BUSY.C
+** module, wherein they take the HTASK and use TOOLHELP's TaskFindHandle
+** to determine a HINST. Then they take the HINST and try and find its
+** module name, and a top-level window handle. Using this, they bring up
+** a nice dialog describing the task.
+**
+** In the case when a 32-bit process's THREADID needs to be given into the
+** 16-bit world as an htask, we create an htask alias (a GDT selector).
+** We check for it in TaskFindHandle and return an HINST of exactly the
+** same value (same GDT selector). We also check for this value in
+** GetModuleFileName. Then, later, we make sure that any window operated on
+** with GetWindowWord( GWW_HINST, ...) maps to exactly the same value if it
+** is from a 32-bit process AND from the process which we created an alias
+** for.
+**
+** I've tried to make these routines general, so that later we might be able
+** to really maintain HTASK aliases whenever we see a 32-bit THREADID, but
+** it is too late before shipping to be able to test a general fix.
+**
+** -BobDay
+**
+*/
+
+#define MAP_SLOT_HTASK(slot) ((HTASK16)((WORD)0xffe0 - (8 * (slot))))
+#define MAP_HTASK_SLOT(htask) ((UINT)(((WORD)0xffe0 - (htask16))/8))
+
+typedef struct tagHTASKALIAS {
+ DWORD dwThreadID32;
+ DWORD dwProcessID32;
+ FILETIME ftCreationTime;
+} HTASKALIAS;
+
+#define MAX_HTASKALIAS_SIZE 32 // 32 should be plenty
+
+HTASKALIAS *lphtaskalias = NULL;
+UINT cHtaskAliasCount = 0;
+
+BOOL GetThreadIDHTASKALIAS(
+ DWORD dwThreadID32,
+ HTASKALIAS *ha
+) {
+ OBJECT_ATTRIBUTES obja;
+ THREAD_BASIC_INFORMATION ThreadInfo;
+ HANDLE hThread;
+ NTSTATUS Status;
+ FILETIME ftDummy;
+ CLIENT_ID cid;
+
+ InitializeObjectAttributes(
+ &obja,
+ NULL,
+ 0,
+ NULL,
+ 0 );
+
+ cid.UniqueProcess = 0; // Don't know it, 0 means any process
+ cid.UniqueThread = (HANDLE)dwThreadID32;
+
+ Status = NtOpenThread(
+ &hThread,
+ THREAD_QUERY_INFORMATION,
+ &obja,
+ &cid );
+
+ if ( !NT_SUCCESS(Status) ) {
+#if DBG
+ DbgPrint("WOW32: Could not get open thread handle\n");
+#endif
+ return( FALSE );
+ }
+
+ Status = NtQueryInformationThread(
+ hThread,
+ ThreadBasicInformation,
+ (PVOID)&ThreadInfo,
+ sizeof(THREAD_BASIC_INFORMATION),
+ NULL
+ );
+
+ ha->dwProcessID32 = (DWORD)ThreadInfo.ClientId.UniqueProcess;
+ ha->dwThreadID32 = dwThreadID32;
+
+ GetThreadTimes( hThread,
+ &ha->ftCreationTime,
+ &ftDummy,
+ &ftDummy,
+ &ftDummy );
+
+ Status = NtClose( hThread );
+ if ( !NT_SUCCESS(Status) ) {
+#if DBG
+ DbgPrint("WOW32: Could not close thread handle\n");
+ DbgBreakPoint();
+#endif
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+HTASK16 AddHtaskAlias(
+ DWORD ThreadID32
+) {
+ UINT iSlot;
+ UINT iUsable;
+ HTASKALIAS ha;
+ FILETIME ftOldest;
+
+ if ( !GetThreadIDHTASKALIAS( ThreadID32, &ha ) ) {
+ return( 0 );
+ }
+
+ //
+ // Need to allocate the alias table?
+ //
+ if ( lphtaskalias == NULL ) {
+ lphtaskalias = (HTASKALIAS *) malloc_w( MAX_HTASKALIAS_SIZE * sizeof(HTASKALIAS) );
+ if ( lphtaskalias == NULL ) {
+ LOGDEBUG(LOG_ALWAYS,("WOW::AddHtaskAlias : Failed to allocate memory\n"));
+ WOW32ASSERT(FALSE);
+ return( 0 );
+ }
+ // Zero them out initially
+ memset( lphtaskalias, 0, MAX_HTASKALIAS_SIZE * sizeof(HTASKALIAS) );
+ }
+
+ //
+ // Now iterate through the alias table, either finding an available slot,
+ // or finding the oldest one there to overwrite.
+ //
+ iSlot = 0;
+ iUsable = 0;
+ ftOldest.dwLowDateTime = 0xffffffff;
+ ftOldest.dwHighDateTime = 0xffffffff;
+
+ while ( iSlot < MAX_HTASKALIAS_SIZE ) {
+
+ //
+ // Did we find an available slot?
+ //
+ if ( lphtaskalias[iSlot].dwThreadID32 == 0 ) {
+ cHtaskAliasCount++; // Using an available slot
+ iUsable = iSlot;
+ break;
+ }
+
+ //
+ // Remember the oldest guy
+ //
+ if ( lphtaskalias[iSlot].ftCreationTime.dwHighDateTime < ftOldest.dwHighDateTime ||
+ (lphtaskalias[iSlot].ftCreationTime.dwHighDateTime == ftOldest.dwHighDateTime &&
+ lphtaskalias[iSlot].ftCreationTime.dwLowDateTime < ftOldest.dwLowDateTime) ) {
+ ftOldest = lphtaskalias[iSlot].ftCreationTime;
+ iUsable = iSlot;
+ }
+
+ iSlot++;
+ }
+
+ //
+ // If the above loop is exitted due to not enough space, then
+ // iUsable will be the oldest one. If it was exitted because we found
+ // an empty slot, then iUsable will be the slot.
+ //
+
+ lphtaskalias[iUsable] = ha;
+
+ return( MAP_SLOT_HTASK(iUsable) );
+}
+
+HTASK16 FindHtaskAlias(
+ DWORD ThreadID32
+) {
+ UINT iSlot;
+
+ if ( lphtaskalias == NULL || ThreadID32 == 0 ) {
+ return( 0 );
+ }
+
+ iSlot = MAX_HTASKALIAS_SIZE;
+
+ while ( iSlot > 0 ) {
+ --iSlot;
+
+ //
+ // Did we find the appropriate guy?
+ //
+ if ( lphtaskalias[iSlot].dwThreadID32 == ThreadID32 ) {
+
+ return( MAP_SLOT_HTASK(iSlot) );
+ }
+ }
+ return( 0 );
+}
+
+void RemoveHtaskAlias(
+ HTASK16 htask16
+) {
+ UINT iSlot;
+
+ //
+ // Get out early if we haven't any aliases
+ //
+ if ( lphtaskalias == NULL || (!htask16)) {
+ return;
+ }
+ iSlot = MAP_HTASK_SLOT(htask16);
+
+ if (iSlot >= MAX_HTASKALIAS_SIZE) {
+ LOGDEBUG(LOG_ALWAYS, ("WOW::RemoveHtaskAlias : iSlot >= MAX_TASK_ALIAS_SIZE\n"));
+ WOW32ASSERT(FALSE);
+ return;
+ }
+
+ //
+ // Zap the entry from the list
+ //
+
+ if (lphtaskalias[iSlot].dwThreadID32) {
+
+ lphtaskalias[iSlot].dwThreadID32 = 0;
+ lphtaskalias[iSlot].dwProcessID32 = 0;
+ lphtaskalias[iSlot].ftCreationTime.dwHighDateTime = 0;
+ lphtaskalias[iSlot].ftCreationTime.dwLowDateTime = 0;
+
+ --cHtaskAliasCount;
+ }
+}
+
+DWORD GetHtaskAlias(
+ HTASK16 htask16,
+ LPDWORD lpProcessID32
+) {
+ UINT iSlot;
+ DWORD ThreadID32;
+ HTASKALIAS ha;
+ BOOL fBad;
+
+ if ( !ISTASKALIAS(htask16) ) {
+ return( 0 );
+ }
+ iSlot = MAP_HTASK_SLOT(htask16);
+
+
+ if (iSlot >= MAX_HTASKALIAS_SIZE) {
+ LOGDEBUG(LOG_ALWAYS, ("WOW::GetHtaskAlias : iSlot >= MAX_TASK_ALIAS_SIZE\n"));
+ WOW32ASSERT(FALSE);
+ return (0);
+ }
+
+ ThreadID32 = lphtaskalias[iSlot].dwThreadID32;
+
+ //
+ // Make sure the thread still exists in the system
+ //
+ fBad = TRUE;
+
+ if ( GetThreadIDHTASKALIAS( ThreadID32, &ha ) ) {
+ if ( ha.ftCreationTime.dwHighDateTime == lphtaskalias[iSlot].ftCreationTime.dwHighDateTime &&
+ ha.ftCreationTime.dwLowDateTime == lphtaskalias[iSlot].ftCreationTime.dwLowDateTime &&
+ ha.dwProcessID32 == lphtaskalias[iSlot].dwProcessID32 ) {
+ fBad = FALSE;
+ }
+ }
+
+ if ( fBad ) {
+ RemoveHtaskAlias( htask16 );
+ return( 0 );
+ }
+
+ if ( lpProcessID32 != NULL ) {
+ *lpProcessID32 = ha.dwProcessID32;
+ }
+
+ return( ThreadID32 );
+}
+
+UINT GetHtaskAliasProcessName(
+ HTASK16 htask16,
+ LPSTR lpNameBuffer,
+ UINT cNameBufferSize
+) {
+ DWORD dwThreadID32;
+ DWORD dwProcessID32;
+ PSYSTEM_PROCESS_INFORMATION ProcessInfo;
+ UCHAR LargeBuffer1[16*1024]; // 16K should be plenty
+ NTSTATUS status;
+ ANSI_STRING pname;
+ ULONG TotalOffset;
+
+ dwThreadID32 = GetHtaskAlias(htask16, &dwProcessID32);
+ if ( dwThreadID32 == 0 ) {
+ return( 0 );
+ }
+
+ if ( cNameBufferSize == 0 || lpNameBuffer == NULL ) {
+ return( 0 );
+ }
+
+ status = NtQuerySystemInformation(
+ SystemProcessInformation,
+ LargeBuffer1,
+ sizeof(LargeBuffer1),
+ &TotalOffset
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ return( 0 );
+ }
+
+ //
+ // Iterate through the returned list of process information structures,
+ // trying to find the one with the right process id.
+ //
+ TotalOffset = 0;
+ ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)LargeBuffer1;
+
+ while (TRUE) {
+ if ( (DWORD)ProcessInfo->UniqueProcessId == dwProcessID32 ) {
+ pname.Buffer = NULL;
+ if ( ProcessInfo->ImageName.Buffer ) {
+ RtlUnicodeStringToAnsiString(&pname,(PUNICODE_STRING)&ProcessInfo->ImageName,TRUE);
+
+ //
+ // Truncate the name to make it fit
+ //
+ pname.Buffer[cNameBufferSize-1] = '\0';
+
+ strcpy( lpNameBuffer, pname.Buffer );
+
+ RtlFreeAnsiString( &pname );
+
+ return( strlen(lpNameBuffer) );
+ } else {
+ //
+ // Don't let them get the name of a system process
+ //
+ return( 0 );
+ }
+ }
+ if (ProcessInfo->NextEntryOffset == 0) {
+ break;
+ }
+ TotalOffset += ProcessInfo->NextEntryOffset;
+ ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&LargeBuffer1[TotalOffset];
+ }
+ return( 0 );
+}
diff --git a/private/mvdm/wow32/wole2.h b/private/mvdm/wow32/wole2.h
new file mode 100644
index 000000000..2725c0f7c
--- /dev/null
+++ b/private/mvdm/wow32/wole2.h
@@ -0,0 +1,24 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WOLE2.H
+ * WOW32 16-bit OLE2 special stuff
+ *
+ * History:
+ * Created 04-May-1994 by Bob Day (bobday)
+--*/
+
+#define ISTASKALIAS(htask16) (((htask16) & 0x4) == 0 && (htask16 <= 0xffe0) && (htask16))
+
+/* Function prototypes
+ */
+HTASK16 AddHtaskAlias( DWORD ThreadID32 );
+HTASK16 FindHtaskAlias( DWORD ThreadID32 );
+void RemoveHtaskAlias( HTASK16 htask16 );
+DWORD GetHtaskAlias( HTASK16 htask16, LPDWORD lpdwProcessID32 );
+UINT GetHtaskAliasProcessName( HTASK16 htask16, LPSTR lpNameBuffer, UINT cNameBufferSize );
+
+extern UINT cHtaskAliasCount;
diff --git a/private/mvdm/wow32/wow32.c b/private/mvdm/wow32/wow32.c
new file mode 100644
index 000000000..269a998ac
--- /dev/null
+++ b/private/mvdm/wow32/wow32.c
@@ -0,0 +1,2376 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WOW32.C
+ * WOW32 16-bit API support
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * Multi-Tasking 23-May-1991 Matt Felton [mattfe]
+ * WOW as DLL 06-Dec-1991 Sudeep Bharati (sudeepb)
+ * Cleanup and rework multi tasking feb 6 (mattfe)
+ * added notification thread for task creation mar-11 (mattfe)
+ * added basic exception handling for retail build apr-3 92 mattfe
+ * use host_ExitThread apr-17 92 daveh
+ * Hung App Support june-22 82 mattfe
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wktbl.h"
+#include "wutbl.h"
+#include "wgtbl.h"
+#include "wstbl.h"
+#include "wkbtbl.h"
+#include "wshltbl.h"
+#include "wmmtbl.h"
+#include "wsocktbl.h"
+#include "wthtbl.h"
+#include <stdarg.h>
+#include <ntcsrdll.h>
+#define SHAREWOW_MAIN
+#include <sharewow.h>
+
+
+/* Function Prototypes */
+DWORD W32SysErrorBoxThread2(PTDB pTDB);
+VOID StartDebuggerForWow(VOID);
+BOOLEAN LoadCriticalStringResources(void);
+
+
+extern DECLSPEC_IMPORT ULONG *ExpLdt;
+#define LDT_DESC_PRESENT 0x8000
+#define STD_SELECTOR_BITS 0x7
+
+MODNAME(wow32.c);
+
+#define REGISTRY_BUFFER_SIZE 512
+
+// for logging iloglevel to a file
+#ifdef DEBUG
+CHAR szLogFile[128];
+int fLog = 0;
+HANDLE hfLog = NULL;
+UCHAR gszAssert[256];
+#endif
+
+/* iloglevel = 16 MAX the world (all 16 bit kernel internal calls
+ * iloglevel = 14 All internal WOW kernel Calls
+ * ilogeveel = 12 All USER GDI call + return Codes
+ * iloglevel = 5 Returns From Calls
+ * iloglevel = 3 Calling Parameters
+ */
+INT flOptions = 0; // command line optin
+#ifdef DEBUG
+INT iLogLevel = 0; // logging level; 0 implies none
+INT fDebugWait = 0 ; // Single Step, 0 = No single step
+#endif
+
+HANDLE hmodWOW32;
+HANDLE hHostInstance = 0;
+#ifdef DEBUG
+INT fLogFilter = -1; // Logging Code Fiters
+WORD fLogTaskFilter = (WORD)-1; // Filter Logging for Specific TaskID
+#endif
+#ifdef i386
+PX86CONTEXT pIntelRegisters = 0; // x86 Only - Pointer to Intel Register Block
+#endif
+
+#ifdef DEBUG
+BOOL fSkipLog = 0; // TRUE to temporarily skip certain logging
+INT iReqLogLevel = 0; // Current Output LogLevel
+INT iCircBuffer = CIRC_BUFFERS-1; // Current Buffer
+CHAR achTmp[CIRC_BUFFERS][TMP_LINE_LEN] = {" "}; // Circular Buffer
+CHAR *pachTmp = &achTmp[0][0];
+WORD awfLogFunctionFilter[FILTER_FUNCTION_MAX] = {0xffff,0,0,0,0,0,0,0,0,0}; // Specific Filter API Array
+PWORD pawfLogFunctionFilter = awfLogFunctionFilter;
+INT iLogFuncFiltIndex = 0; // Index Into Specific Array for Debugger Extensions
+#endif
+
+UINT iW32ExecTaskId = (UINT)-1; // Base Task ID of Task Being Exec'd
+WORD iWOWTaskCur = 0; // pTDB of currently running task ID
+UINT nWOWTasks = 0 ; // # of WOW tasks running
+BOOL fBoot = TRUE; // TRUE During the Boot Process
+HANDLE ghevWaitCreatorThread = (HANDLE)-1; // Used to Syncronize creation of a new thread
+
+
+BOOL fWowMode = FALSE; // Flag used to determine wow mode.
+ // currently defaults to FALSE (real mode wow)
+ // This is used by the memory access macros
+ // to properly form linear addresses.
+ // When running on an x86 box, it will be
+ // initialized to the mode the first wow
+ // bop call is made in. This flag can go
+ // away when we no longer want to run real
+ // mode wow. (Daveh 7/25/91)
+
+HANDLE hSharedTaskMemory;
+DWORD dwSharedProcessOffset;
+HANDLE hWOWHeap;
+HANDLE ghProcess; // WOW Process Handle
+PFNWOWHANDLERSOUT pfnOut;
+PTD * pptdWOA = NULL;
+PTD gptdShell = NULL;
+DWORD fThunkStrRtns; // used as a BOOL
+BOOL gfDebugExceptions = FALSE; // set to 1 in debugger to
+ // enable debugging of W32Exception
+BOOL gfIgnoreInputAssertGiven = FALSE;
+
+#ifndef _X86_
+PUCHAR IntelMemoryBase; // Start of emulated CPU's memory
+#endif
+
+
+DWORD gpsi = 0;
+
+#define TOOLONGLIMIT _MAX_PATH
+#define WARNINGMSGLENGTH 255
+
+PSZ aszCriticalStrings[CRITICAL_STRING_COUNT];
+
+char szEmbedding[] = "embedding";
+char szDevices[] = "devices";
+char szBoot[] = "boot";
+char szShell[] = "shell";
+char szServerKey[] = "protocol\\StdFileEditing\\server";
+char szPicture[] = "picture";
+char szPostscript[] = "postscript";
+char szZapfDingbats[] = "ZAPFDINGBATS";
+char szZapf_Dingbats[] = "ZAPF DINGBATS";
+char szSymbol[] = "SYMBOL";
+char szTmsRmn[] = "TMS RMN";
+char szHelv[] = "HELV";
+char szMavisCourier[]= "MAVIS BEACON COURIER FP";
+char szWinDotIni[] = "win.ini";
+char szSystemDotIni[] = "system.ini";
+char szExplorerDotExe[] = "Explorer.exe";
+char szDrWtsn32[] = "drwtsn32";
+PSTR pszWinIniFullPath;
+PSTR pszWindowsDirectory;
+PSTR pszSystemDirectory;
+
+extern BOOL GdiReserveHandles(VOID);
+extern CRITICAL_SECTION VdmLoadCritSec;
+extern LIST_ENTRY TimerList;
+
+extern PVOID GdiQueryTable();
+extern PVOID gpGdiHandleInfo;
+
+#if defined (_X86_)
+
+extern PVOID WowpLockPrefixTable;
+
+IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used = {
+ 0, // Reserved
+ 0, // Reserved
+ 0, // Reserved
+ 0, // Reserved
+ 0, // GlobalFlagsClear
+ 0, // GlobalFlagsSet
+ 0, // CriticalSectionTimeout (milliseconds)
+ 0, // DeCommitFreeBlockThreshold
+ 0, // DeCommitTotalFreeThreshold
+ &WowpLockPrefixTable, // LockPrefixTable, defined in FASTWOW.ASM
+ 0, 0, 0, 0, 0, 0, 0 // Reserved
+};
+
+#endif
+
+BOOLEAN
+W32DllInitialize(
+ IN PVOID DllHandle,
+ IN ULONG Reason,
+ IN PCONTEXT Context OPTIONAL
+ )
+
+/*++
+
+Routine Description: DllMain function called during ntvdm's
+ LoadLibrary("wow32")
+
+Arguments:
+
+ DllHandle - set global hmodWOW32
+
+ Reason - Attach or Detach
+
+ Context - Not Used
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(Context);
+
+ hmodWOW32 = DllHandle;
+
+ switch ( Reason ) {
+
+ case DLL_PROCESS_ATTACH:
+
+ if (!CreateSmallHeap()) {
+ return FALSE;
+ }
+
+ if ((hWOWHeap = HeapCreate (0,
+ INITIAL_WOW_HEAP_SIZE,
+ GROW_HEAP_AS_NEEDED)) == NULL)
+ return FALSE;
+
+ // initialize hook stubs data.
+
+ W32InitHookState(hmodWOW32);
+
+ // initialize the thunk table offsets. do it here so the debug process
+ // gets them.
+
+ InitThunkTableOffsets();
+
+ //
+ // initialization for named pipe handling in file thunks
+ //
+
+ InitializeCriticalSection(&VdmLoadCritSec);
+
+ //
+ // Load Critical Error Strings
+ //
+
+ if (!LoadCriticalStringResources()) {
+ MessageBox(NULL, "The Win16 subsystem could not load critical string resources from wow32.dll, terminating.",
+ "Win16 subsystem load failure", MB_ICONEXCLAMATION | MB_OK);
+ }
+
+ //
+ // setup the GDI table for handle conversion
+ //
+
+ gpGdiHandleInfo = GdiQueryTable();
+
+ W32EWExecer();
+
+ InitializeListHead(&TimerList);
+ break;
+
+ case DLL_THREAD_ATTACH:
+ IsDebuggerAttached(); // Yes, this routine has side-effects.
+ break;
+
+ case DLL_THREAD_DETACH:
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /*
+ * Tell base he can nolonger callback to us.
+ */
+ RegisterWowBaseHandlers(NULL);
+
+ HeapDestroy (hWOWHeap);
+ break;
+
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+LoadCriticalStringResources(
+ void
+ )
+
+/*++
+
+Routine Description: Loads strings we want around even if we can't allocate
+ memory. Called during wow32 DLL load.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ TRUE if all strings loaded and aszCriticalStrings initialized.
+
+--*/
+
+{
+ int n;
+ PSZ psz, pszStringBuffer;
+ DWORD cbTotal;
+ DWORD cbUsed;
+ DWORD cbStrLen;
+
+ //
+ // Allocate too much memory for strings (maximum possible) at first,
+ // reallocate to the real size when we're done loading strings.
+ //
+
+ cbTotal = CRITICAL_STRING_COUNT * CCH_MAX_STRING_RESOURCE;
+
+ psz = pszStringBuffer = malloc_w(cbTotal);
+
+ if ( ! psz ) {
+ return FALSE;
+ }
+
+ cbUsed = 0;
+
+ for ( n = 0; n < CRITICAL_STRING_COUNT; n++ ) {
+
+ //
+ // LoadString return value doesn't count null terminator.
+ //
+
+ cbStrLen = LoadString(hmodWOW32, n, psz, CCH_MAX_STRING_RESOURCE);
+
+ if ( ! cbStrLen ) {
+ return FALSE;
+ }
+
+ aszCriticalStrings[n] = psz;
+
+ psz += cbStrLen + 1;
+ cbUsed += cbStrLen + 1;
+
+ }
+
+ realloc_w(pszStringBuffer, cbUsed, HEAP_REALLOC_IN_PLACE_ONLY);
+
+ return TRUE;
+}
+
+
+//***************************************************************************
+// Continues ExitWindowsExec api call after logoff and subsequent logon
+// Uses Events to synchronize across all wow vdms
+//
+//***************************************************************************
+
+BOOL W32EWExecer(VOID)
+{
+ STARTUPINFO StartupInfo;
+ PROCESS_INFORMATION ProcessInformation;
+ BOOL CreateProcessStatus;
+ BYTE abT[REGISTRY_BUFFER_SIZE];
+
+ if (W32EWExecData(EWEXEC_QUERY, (LPSTR)abT, sizeof(abT))) {
+ HANDLE hevT;
+ if (hevT = CreateEvent(NULL, TRUE, FALSE, WOWSZ_EWEXECEVENT)) {
+ if (GetLastError() == 0) {
+ W32EWExecData(EWEXEC_DEL, (LPSTR)NULL, 0);
+
+ LOGDEBUG(0, ("WOW:Execing dos app - %s\r\n", abT));
+ RtlZeroMemory((PVOID)&StartupInfo, (DWORD)sizeof(StartupInfo));
+ StartupInfo.cb = sizeof(StartupInfo);
+ StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
+ StartupInfo.wShowWindow = SW_NORMAL;
+
+ CreateProcessStatus = CreateProcess(
+ NULL,
+ abT,
+ NULL, // security
+ NULL, // security
+ FALSE, // inherit handles
+ CREATE_NEW_CONSOLE | CREATE_DEFAULT_ERROR_MODE,
+ NULL, // environment strings
+ NULL, // current directory
+ &StartupInfo,
+ &ProcessInformation
+ );
+
+ if (CreateProcessStatus) {
+ WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
+ CloseHandle( ProcessInformation.hProcess );
+ CloseHandle( ProcessInformation.hThread );
+ }
+
+ SetEvent(hevT);
+ }
+ else {
+ WaitForSingleObject(hevT, INFINITE);
+ }
+
+ CloseHandle(hevT);
+ }
+ }
+ return 0;
+}
+
+//***************************************************************************
+// W32EWExecData -
+// sets/resets the 'commandline', ie input to ExitWindowssExec api in the
+// registry - 'WOW' key 'EWExec' value
+//
+//***************************************************************************
+
+BOOL W32EWExecData(DWORD fnid, LPSTR lpData, DWORD cb)
+{
+ BOOL bRet = FALSE;
+ BYTE abT[REGISTRY_BUFFER_SIZE];
+
+
+ switch (fnid) {
+ case EWEXEC_SET:
+ bRet = WriteProfileString(WOWSZ_EWEXECVALUE,
+ WOWSZ_EWEXECVALUE,
+ lpData);
+ break;
+
+ case EWEXEC_DEL:
+ bRet = WriteProfileString(WOWSZ_EWEXECVALUE,
+ NULL, NULL);
+ break;
+
+ case EWEXEC_QUERY:
+ if (bRet = GetProfileString(WOWSZ_EWEXECVALUE,
+ WOWSZ_EWEXECVALUE,
+ "", abT, sizeof(abT))) {
+ strcpy(lpData, abT);
+ }
+
+ break;
+
+ default:
+ WOW32ASSERT(FALSE);
+ break;
+ }
+ return !!bRet;
+}
+
+
+
+/* W32Init - Initialize WOW support
+ *
+ * ENTRY
+ *
+ * EXIT
+ * TRUE if successful, FALSE if not
+ */
+
+
+BOOL W32Init(VOID)
+{
+ HKEY WowKey;
+#ifdef DEBUG
+ CHAR WOWCmdLine[REGISTRY_BUFFER_SIZE];
+ PCHAR pWOWCmdLine;
+ ULONG WOWCmdLineSize = REGISTRY_BUFFER_SIZE;
+#endif
+ DWORD cb;
+ DWORD dwType;
+ PTD ptd;
+ PFNWOWHANDLERSIN pfnIn;
+ LPVOID lpSharedTaskMemory;
+#ifdef _X86_
+ pIntelRegisters = getIntelRegistersPointer(); // X86 Only, get pointer to Register Context Block
+#endif // UP.
+
+#ifndef _X86_
+ //
+ // This is the one and only call to Sim32GetVDMPointer in WOW32.
+ // All other cases should use WOWGetVDMPointer. This one is necessary
+ // to set up the base memory address used by GetRModeVDMPointerMacro.
+ // (There's also a call in GetPModeVDMPointerAssert, but that's in
+ // the checked build only and only as a fallback mechanism.)
+ //
+
+ IntelMemoryBase = Sim32GetVDMPointer(0,0,0);
+#endif
+
+ fWowMode = ((getMSW() & MSW_PE) ? TRUE : FALSE);
+
+ // Boost the HourGlass
+
+ ShowStartGlass(10000);
+
+ //
+ // Set up a global WindowsDirectory to be used by other WOW functions.
+ //
+
+ {
+ char szBuf[ MAX_PATH ];
+ int cb;
+
+ GetSystemDirectory(szBuf, sizeof szBuf);
+ GetShortPathName(szBuf, szBuf, sizeof szBuf);
+ cb = strlen(szBuf) + 1;
+ pszSystemDirectory = malloc_w_or_die(cb);
+ RtlCopyMemory(pszSystemDirectory, szBuf, cb);
+
+ GetWindowsDirectory(szBuf, sizeof szBuf);
+ GetShortPathName(szBuf, szBuf, sizeof szBuf);
+ cb = strlen(szBuf) + 1;
+ pszWindowsDirectory = malloc_w_or_die(cb);
+ RtlCopyMemory(pszWindowsDirectory, szBuf, cb);
+
+ pszWinIniFullPath = malloc_w_or_die(cb + 8); // "\win.ini"
+ RtlCopyMemory(pszWinIniFullPath, szBuf, cb);
+ pszWinIniFullPath[ cb - 1 ] = '\\';
+ RtlCopyMemory(pszWinIniFullPath + cb, szWinDotIni, 8);
+ }
+
+ // Give USER32 our entry points
+
+ pfnIn.pfnLocalAlloc = W32LocalAlloc;
+ pfnIn.pfnLocalReAlloc = W32LocalReAlloc;
+ pfnIn.pfnLocalLock = W32LocalLock;
+ pfnIn.pfnLocalUnlock = W32LocalUnlock;
+ pfnIn.pfnLocalSize = W32LocalSize;
+ pfnIn.pfnLocalFree = W32LocalFree;
+ pfnIn.pfnGetExpWinVer = W32GetExpWinVer;
+ pfnIn.pfnInitDlgCb = W32InitDlg;
+ pfnIn.pfn16GlobalAlloc = W32GlobalAlloc16;
+ pfnIn.pfn16GlobalFree = W32GlobalFree16;
+ pfnIn.pfnEmptyCB = W32EmptyClipboard;
+ pfnIn.pfnFindResourceEx = W32FindResource;
+ pfnIn.pfnLoadResource = W32LoadResource;
+ pfnIn.pfnFreeResource = W32FreeResource;
+ pfnIn.pfnLockResource = W32LockResource;
+ pfnIn.pfnUnlockResource = W32UnlockResource;
+ pfnIn.pfnSizeofResource = W32SizeofResource;
+ pfnIn.pfnWowWndProcEx = (PFNWOWWNDPROCEX)W32Win16WndProcEx;
+ pfnIn.pfnWowEditNextWord = W32EditNextWord;
+ pfnIn.pfnWowSetFakeDialogClass = SetFakeDialogClass;
+ pfnIn.pfnWowCBStoreHandle = WU32ICBStoreHandle;
+
+ gpsi = UserRegisterWowHandlers(&pfnIn, &pfnOut);
+
+ RegisterWowBaseHandlers(W32DDEFreeGlobalMem32);
+
+ // Prepare us to be in the shared memory process list
+
+ lpSharedTaskMemory = LOCKSHAREWOW();
+
+ WOW32ASSERTMSG(lpSharedTaskMemory, "WOW32: Could not access shared memory object\n");
+
+ if ( lpSharedTaskMemory ) {
+ UNLOCKSHAREWOW();
+ }
+
+ CleanseSharedList();
+ AddProcessSharedList();
+
+ // Allocate a Temporary TD for the first thread
+
+ ptd = CURRENTPTD() = malloc_w_or_die(sizeof(TD));
+
+ RtlZeroMemory(ptd, sizeof(*ptd));
+
+ // Create Global Wait Event - Used During Task Creation To Syncronize with New Thread
+
+ if (!(ghevWaitCreatorThread = CreateEvent(NULL, FALSE, FALSE, NULL))) {
+ LOGDEBUG(0,(" W32INIT ERROR: event creation failure\n"));
+ return FALSE;
+ }
+
+
+ if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\WOW",
+ 0,
+ KEY_QUERY_VALUE,
+ &WowKey
+ ) != 0){
+ LOGDEBUG(0,(" W32INIT ERROR: Registry Opening failed\n"));
+ return FALSE;
+ }
+
+ //
+ // If present (it usually isn't) read ThunkNLS value entry.
+ //
+
+ cb = sizeof(fThunkStrRtns);
+ if (RegQueryValueEx(WowKey,
+ "ThunkNLS",
+ NULL,
+ &dwType,
+ (LPBYTE) &fThunkStrRtns,
+ &cb) || dwType != REG_DWORD) {
+
+ //
+ // Didn't find the registry value or it's the wrong type,
+ // so we use the default behavior which is to thunk outside the
+ // US.
+ //
+
+ fThunkStrRtns = GetSystemDefaultLCID() !=
+ MAKELCID(
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ SORT_DEFAULT
+ );
+ }
+
+#ifdef DEBUG
+
+ if (RegQueryValueEx (WowKey,
+ "wowcmdline",
+ NULL,
+ &dwType,
+ (LPBYTE)&WOWCmdLine,
+ &WOWCmdLineSize) != 0){
+ RegCloseKey (WowKey);
+ LOGDEBUG(0,(" W32INIT ERROR: WOWCMDLINE not found in registry\n"));
+ return FALSE;
+ }
+
+ pWOWCmdLine = (PCHAR)((PBYTE)WOWCmdLine + WOWCmdLineSize + 1);
+
+ WOWCmdLineSize = REGISTRY_BUFFER_SIZE - WOWCmdLineSize -1;
+
+ if (WOWCmdLineSize < (REGISTRY_BUFFER_SIZE / 2)){
+ LOGDEBUG(0,(" W32INIT ERROR: Registry Buffer too small\n"));
+ return FALSE;
+ }
+
+ if (ExpandEnvironmentStrings ((LPCSTR)WOWCmdLine, (LPSTR)pWOWCmdLine, WOWCmdLineSize) >
+ WOWCmdLineSize) {
+ LOGDEBUG(0,(" W32INIT ERROR: Registry Buffer too small\n"));
+ return FALSE;
+ }
+
+ // Find Debug Info
+ while (*pWOWCmdLine) {
+ if (*pWOWCmdLine == '-' || *pWOWCmdLine == '/') {
+ // c = (char)tolower(*++pWOWCmdLine);
+ switch(*++pWOWCmdLine) {
+ case 'd':
+ case 'D':
+ flOptions |= OPT_DEBUG;
+ break;
+ case 'n':
+ case 'N':
+ flOptions |= OPT_BREAKONNEWTASK;
+ break;
+ case 'l':
+ case 'L':
+ iLogLevel = atoi(++pWOWCmdLine);
+ break;
+ default:
+ break;
+ }
+
+ }
+ pWOWCmdLine++;
+ }
+
+ if (iLogLevel > 0) {
+ if (!(flOptions & OPT_DEBUG))
+ if (!(OPENLOG()))
+ iLogLevel = 0;
+ }
+ else
+ iLogLevel = 0;
+
+#endif
+
+ //
+ // Initialize list of known DLLs used by WK32WowIsKnownDLL
+ // from the registry.
+ //
+
+ WK32InitWowIsKnownDLL(WowKey);
+
+ RegCloseKey (WowKey);
+
+ //
+ // Initialize list of app names known to be setup applications
+ //
+ //
+
+ W32InitWOWSetupNames();
+
+ //
+ // Initialize param mapping cache
+ //
+ //
+
+ InitParamMap();
+
+ //
+ // Set our GDI batching limit from win.ini. This is useful for SGA and
+ // other performance measurements which require each API to do its own
+ // work. To set the batching size to 1, which is most common, put the
+ // following in win.ini:
+ //
+ // [WOW]
+ // BatchLimit=1
+ //
+ // or using ini:
+ //
+ // ini WOW.BatchLimit = 1
+ //
+ // Note that this code only changes the batch limit if the above
+ // line is in win.ini, otherwise we use default batching. It's
+ // important that this code be in the free build to be useful.
+ //
+
+ {
+ extern DWORD dwWOWBatchLimit; // declared in wkman.c
+
+ dwWOWBatchLimit = GetProfileInt("WOW", // section
+ "BatchLimit", // key
+ 0 // default if not found
+ );
+ }
+
+ ghProcess = NtCurrentProcess();
+
+#ifdef DEBUG
+
+#ifdef i386
+ if (IsDebuggerAttached()) {
+ if (GetProfileInt("WOWDebug", "debugbreaks", 0))
+ *pNtVDMState |= VDM_BREAK_DEBUGGER;
+
+ if (GetProfileInt("WOWDebug", "exceptions", 0))
+ *pNtVDMState |= VDM_BREAK_EXCEPTIONS;
+ }
+#endif
+
+
+ if (IsDebuggerAttached() && (flOptions & OPT_BREAKONNEWTASK)) {
+ OutputDebugString("\nW32Init - Initialization Complete, Set any Breakpoints Now, type g to continue\n\n");
+ DbgBreakPoint();
+ }
+
+#endif
+
+ // Initialize ClipBoard formats structure.
+
+ InitCBFormats ();
+
+ // This is to initialize the InquireVisRgn for FileMaker Pro 2.0
+ // InquireVisRgn is an undocumented API Win 3.1 API.
+
+ InitVisRgn();
+
+
+ // HUNG APP SUPPORT
+
+ if (!WK32InitializeHungAppSupport()) {
+ LOGDEBUG(LOG_ALWAYS, ("W32INIT Error: InitializeHungAppSupport Failed"));
+ return FALSE;
+ }
+
+ SetPriorityClass(ghProcess, NORMAL_PRIORITY_CLASS);
+
+ return TRUE;
+}
+
+/* Thunk Dispatch Table
+ *
+ * see fastwow.h for instructions on how to create a new thunk table
+ *
+ */
+#ifdef DEBUG_OR_WOWPROFILE
+PA32 awThunkTables[] = {
+ {W32TAB(aw32WOW, "All ", cAPIThunks)}
+};
+#endif
+
+#ifdef DEBUG_OR_WOWPROFILE // define symbols for API profiling only (debugger extension)
+INT iThunkTableMax = NUMEL(awThunkTables);
+PPA32 pawThunkTables = awThunkTables;
+INT iFuncId = 0;
+#endif // WOWPROFILE
+
+
+/* WOW32UnimplementedAPI - Error Thunk is Not Implemented
+ *
+ * Stub thunk table entry for all unimplemented APIs on
+ * the checked build, and on the free build NOPAPI and
+ * LOCALAPI entries point here as well.
+ *
+ * ENTRY
+ *
+ * EXIT
+ *
+ */
+
+ULONG FASTCALL WOW32UnimplementedAPI(PVDMFRAME pFrame)
+{
+#ifdef DEBUG
+ INT iFun;
+
+ iFun = pFrame->wCallID;
+
+ WOW32ASSERTMSGF (FALSE, ("WOW32 Error - %s: Function %i %s not implemented\n",
+ GetModName(iFun),
+ GetOrdinal(iFun),
+ aw32WOW[iFun].lpszW32
+ ));
+
+#else
+ UNREFERENCED_PARAMETER(pFrame);
+#endif
+ return FALSE;
+}
+
+
+#ifdef DEBUG
+
+/* WOW32NopAPI - Thunk to do nothing - checked build only.
+ *
+ * All Function tables point here for APIs which should do nothing.
+ *
+ * ENTRY
+ *
+ * EXIT
+ *
+ */
+
+ULONG FASTCALL WOW32NopAPI(PVDMFRAME pFrame)
+{
+ INT iFun;
+
+ iFun = pFrame->wCallID;
+
+ LOGDEBUG(4,("%s: Function %i %s is NOP'd\n", GetModName(iFun), GetOrdinal(iFun), aw32WOW[iFun].lpszW32));
+
+ return FALSE;
+}
+
+
+/* WOW32LocalAPI - ERROR Should Have Been Handled in 16 BIT
+ * Checked build only
+ *
+ * All Function tables point here for Local API Error Messages
+ *
+ * ENTRY
+ * Module startup registers:
+ *
+ * EXIT
+ *
+ *
+ */
+
+ULONG FASTCALL WOW32LocalAPI(PVDMFRAME pFrame)
+{
+ INT iFun;
+
+ iFun = pFrame->wCallID;
+
+ WOW32ASSERTMSGF (FALSE, ("Error - %s: Function %i %s should be handled by 16-bit code\n",
+ GetModName(iFun),
+ GetOrdinal(iFun),
+ aw32WOW[iFun].lpszW32
+ ));
+
+ return FALSE;
+}
+
+#endif // DEBUG
+
+
+LPFNW32 FASTCALL W32PatchCodeWithLpfnw32(PVDMFRAME pFrame , INT iFun )
+{
+ LPFNW32 lpfnW32;
+ VPVOID vpCode;
+ LPBYTE lpCode;
+
+#ifdef DEBUG_OR_WOWPROFILE
+ //
+ // On checked builds do not patch calls to the three special
+ // thunks above, since many entries will point to each one,
+ // the routines could not easily distinguish which 16-bit
+ // entrypoint was called.
+ //
+
+ if (flOptions & OPT_DONTPATCHCODE ||
+ aw32WOW[iFun].lpfnW32 == WOW32UnimplementedAPI ||
+ aw32WOW[iFun].lpfnW32 == WOW32NopAPI ||
+ aw32WOW[iFun].lpfnW32 == WOW32LocalAPI ) {
+
+ return aw32WOW[iFun].lpfnW32;
+ }
+#endif
+
+ //
+ // just return the thunk function if called in real mode
+ //
+ if (!fWowMode) {
+ return aw32WOW[iFun].lpfnW32;
+ }
+
+ // the thunk looks like so.
+ //
+ // push HI_WCALLID (3bytes) - 0th byte is opcode.
+ // push 0xfnid (3bytes)
+ // call wow16call (5bytes)
+ // ThunksCSIP:
+ //
+
+ // point to the 1st word (the hiword)
+ vpCode = (DWORD)pFrame->wThunkCSIP - (0x5 + 0x3 + 0x2);
+
+ WOW32ASSERT(HI_WCALLID == 0); // we need to revisit wow32.c if this
+ // value is changed to a non-zero value
+
+ WOW32ASSERT(HIWORD(iFun) == HI_WCALLID);
+ GETVDMPTR(vpCode, 0x2 + 0x3, lpCode);
+ WOW32ASSERT(lpCode != NULL);
+
+ WOW32ASSERT(*(PWORD16)(lpCode) == HIWORD(iFun));
+ WOW32ASSERT(*(PWORD16)(lpCode+0x3) == LOWORD(iFun));
+
+ lpfnW32 = aw32WOW[iFun].lpfnW32;
+ iFun = (DWORD)lpfnW32;
+
+ *((PWORD16)lpCode) = HIWORD(iFun);
+ lpCode += 0x3; // seek to the 2nd word (the loword)
+ *((PWORD16)lpCode) = LOWORD(iFun);
+
+ FLUSHVDMCODEPTR(vpCode, 0x2 + 0x3, lpCode);
+ FREEVDMPTR(lpCode);
+
+ return lpfnW32;
+
+}
+
+
+/* W32Dispatch - Recipient of all WOW16 API calls
+ *
+ * This routine dispatches to the relavant WOW thunk routine via
+ * jump tables wktbl.c wutbl.c wgtbl.c based on a function id on the 16 bit
+ * stack.
+ *
+ * In debug versions it also calls routines to log parameters.
+ *
+ * ENTRY
+ * None (x86 registers contain parameters)
+ *
+ * EXIT
+ * None (x86 registers/memory updated appropriately)
+ */
+VOID W32Dispatch()
+{
+ INT iFun;
+ ULONG ulReturn;
+ VPVOID vpCurrentStack;
+ register PTD ptd;
+ register PVDMFRAME pFrame;
+#ifdef DEBUG_OR_WOWPROFILE
+ INT iFunT;
+#endif
+
+#ifdef WOWPROFILE
+ DWORD dwTics;
+#endif
+
+ //
+ // WARNING: DO NOT ADD ANYTHING TO THIS FUNCTION UNLESS YOU ADD THE SAME
+ // STUFF TO i386/FastWOW.asm. i386/FastWOW.ASM is used for speedy
+ // thunk dispatching on retail builds.
+ //
+
+ try {
+
+ //
+ // if we get here then even if we're going to be fastbopping
+ // then the faststack stuff must not be enabled yet. that's why
+ // there's no #if FASTBOPPING for this fetching of the vdmstack
+ //
+
+ vpCurrentStack = VDMSTACK(); // Get 16 bit ss:sp
+
+ // Use WOWGetVDMPointer here since we can get called in RealMode on
+ // Errors
+
+ pFrame = WOWGetVDMPointer(vpCurrentStack, sizeof(VDMFRAME), fWowMode);
+
+ ptd = CURRENTPTD(); // Setup Task Pointer
+ ptd->vpStack = vpCurrentStack; // Save 16 bit ss:sp
+
+ WOW32ASSERT( FIELD_OFFSET(TD,vpStack) == 0 );
+ WOW32ASSERT( FIELD_OFFSET(TEB,WOW32Reserved) == 0xC0 );
+
+ iFun = pFrame->wCallID;
+
+#ifdef DEBUG_OR_WOWPROFILE
+ iFuncId = 0; // initialize 'cause GetFuncId checks for this.
+ iFunT = iFuncId = ISFUNCID(iFun) ? iFun : GetFuncId(iFun) ;
+#endif
+ iWOWTaskCur = pFrame->wTDB; // Record the task's current ID
+
+ if (ISFUNCID(iFun)) {
+#ifdef DEBUG
+ if (cAPIThunks && iFunT >= cAPIThunks) {
+ LOGDEBUG(LOG_ALWAYS,("W32Dispatch: Task %04x thunked to function %d, cAPIThunks = %d.\n",
+ iWOWTaskCur, iFunT, cAPIThunks));
+ WOW32ASSERT(FALSE);
+ }
+#endif
+ iFun = (INT)W32PatchCodeWithLpfnw32(pFrame, iFun);
+ }
+
+
+ LOGARGS(3,pFrame); // Perform Function Logging
+
+#ifdef WOWPROFILE // For API profiling only (debugger extension)
+ dwTics = GetWOWTicDiff(0L);
+#endif // WOWPROFILE
+
+ //
+ // WARNING: DO NOT ADD ANYTHING TO THIS FUNCTION UNLESS YOU ADD THE SAME
+ // STUFF TO i386/FastWOW.asm. i386/FastWOW.ASM is used for speedy
+ // thunk dispatching on retail builds.
+ //
+ ulReturn = (*((LPFNW32)iFun))(pFrame); // Dispatch to Thunk
+
+#ifdef DEBUG_OR_WOWPROFILE
+ iFuncId = iFunT;
+#endif
+
+#ifdef WOWPROFILE // For API profiling only (debugger extension)
+ dwTics = GetWOWTicDiff(dwTics);
+ iFun = iFunT;
+ // add time ellapsed for call to total
+ aw32WOW[iFun].cTics += dwTics;
+ aw32WOW[iFun].cCalls++; // inc # times this API called
+#endif // WOWPROFILE
+
+ FREEVDMPTR(pFrame); // Set the 16-bit return code
+ GETFRAMEPTR(ptd->vpStack, pFrame);
+
+ LOGRETURN(5,pFrame,ulReturn); // Log return Values
+ pFrame->wAX = LOW(ulReturn); // Pass Back Return Value form thunk
+ pFrame->wDX = HIW(ulReturn);
+
+#ifdef DEBUG
+ // If OPT_DEBUGRETURN is set, diddle the RetID as approp.
+
+ if (flOptions & OPT_DEBUGRETURN) {
+ if (pFrame->wRetID == RET_RETURN) {
+ pFrame->wRetID = RET_DEBUGRETURN;
+ flOptions &= ~OPT_DEBUGRETURN;
+ }
+ }
+ // Put the current logging level where 16-bit code can get it
+ // Use ROMBIOS Hard DISK information as a safe address
+ *(PBYTE)GetVDMAddr(0x0040,0x0042) = (BYTE)(iLogLevel/10+'0');
+ *(PBYTE)GetVDMAddr(0x0040,0x0043) = (BYTE)(iLogLevel%10+'0');
+#endif // DEBUG
+
+ FREEVDMPTR(pFrame);
+
+ SETVDMSTACK(ptd->vpStack);
+
+ } except (W32Exception(GetExceptionCode(), GetExceptionInformation())) {
+
+ }
+ //
+ // WARNING: DO NOT ADD ANYTHING TO THIS FUNCTION UNLESS YOU ADD THE SAME
+ // STUFF TO i386/FastWOW.asm. i386/FastWOW.ASM is used for speedy
+ // thunk dispatching on retail builds.
+ //
+}
+
+
+#if NO_W32TRYCALL
+
+INT
+W32FilterException(
+ INT ExceptionCode,
+ PEXCEPTION_POINTERS ExceptionInformation
+ )
+
+/* W32FilterException - Filter WOW32 thread exceptions
+ *
+ * ENTRY
+ *
+ * ExceptionCode - Indicate type of exception
+ *
+ * ExceptionInformation - Supplies a pointer to ExceptionInformation
+ * structure.
+ *
+ * EXIT
+ *
+ * return exception disposition value.
+ */
+
+{
+ extern BOOLEAN IsW32WorkerException(VOID);
+ extern VOID W32SetExceptionContext(PCONTEXT);
+
+ INT Disposition = EXCEPTION_CONTINUE_SEARCH;
+
+ if ((ExceptionCode != EXCEPTION_WOW32_ASSERTION) &&
+ IsW32WorkerException()) {
+
+ Disposition = W32Exception(ExceptionCode, ExceptionInformation);
+ if (Disposition == EXCEPTION_EXECUTE_HANDLER) {
+
+ //
+ // if this is the exception we want to handle, change its
+ // context to the point where we can safely fail the api and
+ // return exception disposition as continue execution.
+ //
+
+ W32SetExceptionContext(ExceptionInformation->ContextRecord);
+ Disposition = EXCEPTION_CONTINUE_EXECUTION;
+ }
+ }
+ return(Disposition);
+}
+
+#else
+
+/* W32TryCall - Called from FASTWOW to do a TryExcept Around API Calls
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+DWORD FASTCALL W32TryCall(PVDMFRAME pFrame , LPFNW32 lpfnW32 )
+{
+ DWORD ulReturn = 0;
+
+ try {
+
+ if (ISFUNCID(lpfnW32)) {
+ lpfnW32 = W32PatchCodeWithLpfnw32(pFrame, (INT)lpfnW32);
+ }
+
+ ulReturn = (*lpfnW32)(pFrame); // Dispatch to Thunk
+
+ } except (W32Exception(GetExceptionCode(), GetExceptionInformation())) {
+ }
+ return (ulReturn);
+}
+
+#endif
+
+/* W32Exception - Handle WOW32 thread exceptions
+ *
+ * ENTRY
+ * None (x86 registers contain parameters)
+ *
+ * EXIT
+ * None (x86 registers/memory updated appropriately)
+ *
+ */
+
+INT W32Exception(DWORD dwException, PEXCEPTION_POINTERS pexi)
+{
+ PTD ptd;
+ PVDMFRAME pFrame;
+
+ DWORD dwButtonPushed;
+ char szTask[9];
+ HMODULE hModule;
+ char szModule[_MAX_PATH + 1];
+ PSZ pszModuleFilePart;
+ PSZ pszErrorFormatString;
+ char szErrorMessage[TOOLONGLIMIT + 4*WARNINGMSGLENGTH];
+ char szDialogText[TOOLONGLIMIT + 4*WARNINGMSGLENGTH];
+ PTDB pTDB;
+ NTSTATUS Status;
+ HANDLE DebugPort;
+ PRTL_CRITICAL_SECTION PebLockPointer;
+ CHAR AeDebuggerCmdLine[256];
+ CHAR AeAutoDebugString[8];
+ BOOL AeAutoDebug;
+ WORD wDebugButton;
+
+
+ if (!gfDebugExceptions) {
+
+ //
+ // If the process is being debugged, just let the exception happen
+ // so that the debugger can see it. This way the debugger can ignore
+ // all first chance exceptions.
+ //
+
+ DebugPort = (HANDLE)NULL;
+ Status = NtQueryInformationProcess(
+ GetCurrentProcess(),
+ ProcessDebugPort,
+ (PVOID)&DebugPort,
+ sizeof(DebugPort),
+ NULL
+ );
+
+ if ( NT_SUCCESS(Status) && DebugPort) {
+
+ //
+ // Process is being debugged.
+ // Return a code that specifies that the exception
+ // processing is to continue
+ //
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+ }
+
+
+ //
+ // NtClose can raise exceptions if NtGlobalFlag is set for it.
+ // We want to ignore these exceptions if we're not being debugged,
+ // since the errors will be returned from the APIs and we generally
+ // don't have control over what handles the app closes. (Well, that's
+ // not true for file I/O, but it is true for RegCloseKey.)
+ //
+
+ if (STATUS_INVALID_HANDLE == dwException ||
+ STATUS_HANDLE_NOT_CLOSABLE == dwException) {
+
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ //
+ // See if a debugger has been programmed in. If so, use the
+ // debugger specified. If not then there is no AE Cancel support
+ // DEVL systems will default the debugger command line. Retail
+ // systems will not.
+ //
+ // The above paragraph was copied from the system exception
+ // popup in base. It is no longer true. On retail systems,
+ // AeDebug.Auto is set to 1 and AeDebug.Debugger is
+ // "drwtsn32 -p %ld -e %ld -g".
+ //
+ // This means if we support AeDebug for stress, customers don't see
+ // our exception popup and misalignment handling -- instead they get
+ // a nearly-useless drwtsn32.log and popup.
+ //
+ // SO, we check for this situation and act as if no debugger was
+ // enabled.
+ //
+
+ wDebugButton = 0;
+ AeAutoDebug = FALSE;
+
+ //
+ // If we are holding the PebLock, then the createprocess will fail
+ // because a new thread will also need this lock. Avoid this by peeking
+ // inside the PebLock and looking to see if we own it. If we do, then just allow
+ // a regular popup.
+ //
+
+ PebLockPointer = NtCurrentPeb()->FastPebLock;
+
+ if ( PebLockPointer->OwningThread != NtCurrentTeb()->ClientId.UniqueThread ) {
+
+ try {
+ if ( GetProfileString(
+ "AeDebug",
+ "Debugger",
+ NULL,
+ AeDebuggerCmdLine,
+ sizeof(AeDebuggerCmdLine)-1
+ ) ) {
+ wDebugButton = SEB_CANCEL;
+
+ if ( GetProfileString(
+ "AeDebug",
+ "Auto",
+ "0",
+ AeAutoDebugString,
+ sizeof(AeAutoDebugString)-1
+ ) ) {
+
+ if ( !strcmp(AeAutoDebugString,"1") ) {
+ AeAutoDebug = TRUE;
+ }
+ }
+ }
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ wDebugButton = 0;
+ AeAutoDebug = FALSE;
+ }
+ }
+
+ //
+ // See comment above about drwtsn32
+ //
+
+ if (AeAutoDebug &&
+ !_strnicmp(AeDebuggerCmdLine, szDrWtsn32, (sizeof szDrWtsn32) - 1)) {
+
+ wDebugButton = 0;
+ AeAutoDebug = FALSE;
+ }
+
+ ptd = CURRENTPTD();
+ GETFRAMEPTR(ptd->vpStack, pFrame);
+
+ pTDB = (PVOID)SEGPTR(ptd->htask16,0);
+
+ //
+ // Get a zero-terminated copy of the Win16 task name.
+ //
+
+ RtlZeroMemory(szTask, sizeof(szTask));
+ RtlCopyMemory(szTask, pTDB->TDB_ModName, sizeof(szTask)-1);
+
+ //
+ // Translate exception address to module name in szModule.
+ //
+
+ strcpy(szModule, CRITSTR(TheWin16Subsystem));
+ RtlPcToFileHeader(pexi->ExceptionRecord->ExceptionAddress, (PVOID *)&hModule);
+ GetModuleFileName(hModule, szModule, sizeof(szModule));
+ pszModuleFilePart = strrchr(szModule, '\\');
+ if (pszModuleFilePart) {
+ pszModuleFilePart++;
+ } else {
+ pszModuleFilePart = szModule;
+ }
+
+
+ //
+ // Format error message into szErrorMessage
+ //
+
+ switch (dwException) {
+
+ case EXCEPTION_ACCESS_VIOLATION:
+ pszErrorFormatString = CRITSTR(CausedAV);
+ break;
+
+ case EXCEPTION_STACK_OVERFLOW:
+ pszErrorFormatString = CRITSTR(CausedStackOverflow);
+ break;
+
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ pszErrorFormatString = CRITSTR(CausedAlignmentFault);
+ break;
+
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ case EXCEPTION_PRIV_INSTRUCTION:
+ pszErrorFormatString = CRITSTR(CausedIllegalInstr);
+ break;
+
+ case EXCEPTION_IN_PAGE_ERROR:
+ pszErrorFormatString = CRITSTR(CausedInPageError);
+ break;
+
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ pszErrorFormatString = CRITSTR(CausedIntDivideZero);
+ break;
+
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ case EXCEPTION_FLT_OVERFLOW:
+ case EXCEPTION_FLT_STACK_CHECK:
+ case EXCEPTION_FLT_UNDERFLOW:
+ pszErrorFormatString = CRITSTR(CausedFloatException);
+
+ default:
+ pszErrorFormatString = CRITSTR(CausedException);
+ }
+
+ wsprintf(szErrorMessage,
+ pszErrorFormatString,
+ szTask,
+ pszModuleFilePart,
+ pexi->ExceptionRecord->ExceptionAddress,
+ dwException
+ );
+
+ LOGDEBUG(LOG_ALWAYS, ("W32Exception:\n%s\n",szErrorMessage));
+
+ //
+ // Format dialog text into szDialogText and display.
+ //
+
+ if (AeAutoDebug) {
+
+ dwButtonPushed = 2;
+
+ } else {
+
+ if (wDebugButton == SEB_CANCEL) {
+
+ wsprintf(szDialogText,
+ "%s\n%s\n%s\n%s\n",
+ szErrorMessage,
+ CRITSTR(ChooseClose),
+ CRITSTR(ChooseCancel),
+ (dwException == EXCEPTION_DATATYPE_MISALIGNMENT)
+ ? CRITSTR(ChooseIgnoreAlignment)
+ : CRITSTR(ChooseIgnore)
+ );
+ } else {
+
+ wsprintf(szDialogText,
+ "%s\n%s\n%s\n",
+ szErrorMessage,
+ CRITSTR(ChooseClose),
+ (dwException == EXCEPTION_DATATYPE_MISALIGNMENT)
+ ? CRITSTR(ChooseIgnoreAlignment)
+ : CRITSTR(ChooseIgnore)
+ );
+
+ }
+
+ dwButtonPushed = WOWSysErrorBox(
+ CRITSTR(ApplicationError),
+ szDialogText,
+ SEB_CLOSE,
+ wDebugButton,
+ SEB_IGNORE | SEB_DEFBUTTON
+ );
+
+ }
+
+ //
+ // If CANCEL is chosen Launch Debugger.
+ //
+
+ if (dwButtonPushed == 2) {
+
+ BOOL b;
+ STARTUPINFO StartupInfo;
+ PROCESS_INFORMATION ProcessInformation;
+ CHAR CmdLine[256];
+ NTSTATUS Status;
+ HANDLE EventHandle;
+ SECURITY_ATTRIBUTES sa;
+
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+ EventHandle = CreateEvent(&sa,TRUE,FALSE,NULL);
+ RtlZeroMemory(&StartupInfo,sizeof(StartupInfo));
+ sprintf(CmdLine,AeDebuggerCmdLine,GetCurrentProcessId(),EventHandle);
+ StartupInfo.cb = sizeof(StartupInfo);
+ StartupInfo.lpDesktop = "Winsta0\\Default";
+ CsrIdentifyAlertableThread();
+ b = CreateProcess(
+ NULL,
+ CmdLine,
+ NULL,
+ NULL,
+ TRUE,
+ 0,
+ NULL,
+ NULL,
+ &StartupInfo,
+ &ProcessInformation
+ );
+
+ if ( b && EventHandle) {
+
+ //
+ // Do an alertable wait on the event
+ //
+
+ Status = NtWaitForSingleObject(
+ EventHandle,
+ TRUE,
+ NULL
+ );
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ } else {
+
+ LOGDEBUG(0, ("W32Exception unable to start debugger.\n"));
+ goto KillTask;
+ }
+ }
+
+ //
+ // If IGNORE is chosen and it's an EXCEPTION_DATATYPE_MISALIGNMENT,
+ // turn on software emulation of misaligned access and restart the
+ // faulting instruction. Otherwise, just fail the API and continue.
+ //
+
+ if (dwButtonPushed == 3) {
+
+ if (dwException == EXCEPTION_DATATYPE_MISALIGNMENT) {
+ SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT);
+ LOGDEBUG(0, ("W32Exception disabling alignment fault exceptions at user's request.\n"));
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ LOGDEBUG(0, ("W32Exception ignoring at user's request via EXCEPTION_EXECUTE_HANDLER\n"));
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+
+ //
+ // If user typed CLOSE or Any of the above fail,
+ // force just the task to die.
+ //
+
+KillTask:
+ LOGDEBUG(0, ("W32Exception killing task via RET_FORCETASKEXIT\n"));
+ GETFRAMEPTR(ptd->vpStack, pFrame);
+ pFrame->wRetID = RET_FORCETASKEXIT;
+ return EXCEPTION_EXECUTE_HANDLER;
+
+}
+
+
+#ifdef DEBUG
+VOID StartDebuggerForWow(VOID)
+/*++
+
+Routine Description:
+
+ This routine checks to see if there's a debugger attached to WOW. If not,
+ it attempts to spawn one with a command to attach to WOW. If the system
+ was booted with /DEBUG in boot.ini (kernel debugger enabled), we'll run
+ "ntsd -d" otherwise we'll run "ntsd".
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ BOOL fKernelDebuggerEnabled, b;
+ NTSTATUS Status;
+ SYSTEM_KERNEL_DEBUGGER_INFORMATION KernelDebuggerInformation;
+ ULONG ulReturnLength;
+ SECURITY_ATTRIBUTES sa;
+ STARTUPINFO StartupInfo;
+ PROCESS_INFORMATION ProcessInformation;
+ CHAR szCmdLine[256];
+ HANDLE hEvent;
+
+ //
+ // Are we being run under a debugger ?
+ //
+
+ if (IsDebuggerAttached()) {
+
+ //
+ // No need to start one.
+ //
+
+ return;
+ }
+
+
+ //
+ // Is the kernel debugger enabled?
+ //
+
+ Status = NtQuerySystemInformation(
+ SystemKernelDebuggerInformation,
+ &KernelDebuggerInformation,
+ sizeof(KernelDebuggerInformation),
+ &ulReturnLength
+ );
+
+ if (NT_SUCCESS(Status) &&
+ (ulReturnLength >= sizeof(KernelDebuggerInformation))) {
+
+ fKernelDebuggerEnabled = KernelDebuggerInformation.KernelDebuggerEnabled;
+
+ } else {
+
+ fKernelDebuggerEnabled = FALSE;
+ LOGDEBUG(0,("StartDebuggerForWow: NtQuerySystemInformation(kdinfo) returns 0x%8.8x, return length 0x%08x.\n",
+ Status, ulReturnLength));
+
+ }
+
+ //
+ // Create an event for NTSD to signal once it has fully connected
+ // and is ready for the exception. We force the handle to be inherited.
+ //
+
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+ hEvent = CreateEvent(&sa, TRUE, FALSE, NULL);
+
+ //
+ // Build debugger command line.
+ //
+
+ wsprintf(szCmdLine, "ntsd %s -p %lu -e %lu -g",
+ fKernelDebuggerEnabled ? "-d" : "",
+ GetCurrentProcessId(),
+ hEvent
+ );
+
+ RtlZeroMemory(&StartupInfo,sizeof(StartupInfo));
+ StartupInfo.cb = sizeof(StartupInfo);
+
+ b = CreateProcess(
+ NULL,
+ szCmdLine,
+ NULL,
+ NULL,
+ TRUE, // fInheritHandles
+ CREATE_DEFAULT_ERROR_MODE,
+ NULL,
+ NULL,
+ &StartupInfo,
+ &ProcessInformation
+ );
+
+ if (b) {
+ CloseHandle(ProcessInformation.hProcess);
+ CloseHandle(ProcessInformation.hThread);
+
+ if (hEvent) {
+
+ //
+ // Wait for debugger to initialize.
+ //
+
+ WaitForSingleObject(hEvent, INFINITE);
+ }
+ }
+
+ CloseHandle(hEvent);
+
+ return;
+}
+#endif // DEBUG
+
+
+BOOL IsDebuggerAttached(VOID)
+/*++
+
+Routine Description:
+
+ Checks to see if there's a debugger attached to WOW. If there is,
+ this routine also turns on a bit in the 16-bit kernel's DS so it
+ can do its part to report debug events.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - no debugger attached or NtQueryInformationProcess fails.
+ TRUE - debugger is definitely attached.
+
+--*/
+
+{
+ NTSTATUS Status;
+ HANDLE MyDebugPort;
+ LPBYTE lpDebugWOW;
+ static BOOL fDebuggerAttached = FALSE;
+ static BOOL fKernel16Notified = FALSE;
+
+ //
+ // Don't bother checking if we already have been told that
+ // there is a debugger attached, since debuggers cannot detach.
+ //
+
+ if (!fDebuggerAttached) {
+
+ //
+ // Query our ProcessDebugPort, if it is nonzero we have
+ // a debugger attached.
+ //
+
+ Status = NtQueryInformationProcess(
+ NtCurrentProcess(),
+ ProcessDebugPort,
+ (PVOID)&MyDebugPort,
+ sizeof(MyDebugPort),
+ NULL
+ );
+
+ fDebuggerAttached = NT_SUCCESS(Status) && MyDebugPort;
+
+ }
+
+ //
+ // If we have a debugger attached share that information
+ // with the 16-bit kernel.
+ //
+
+ if (!fKernel16Notified && fDebuggerAttached && vpDebugWOW != 0) {
+
+ GETVDMPTR(vpDebugWOW, 1, lpDebugWOW);
+ *lpDebugWOW |= 1;
+ FREEVDMPTR(lpDebugWOW);
+
+ DBGNotifyDebugged( TRUE );
+
+ fKernel16Notified = TRUE;
+ }
+
+ return fDebuggerAttached;
+}
+
+
+void *
+WOWGetVDMPointer(
+ VPVOID Address,
+ DWORD Count,
+ BOOL ProtectedMode
+ )
+/*++
+
+Routine Description:
+
+ This routine converts a 16/16 address to a linear address.
+
+ WARNING NOTE - This routine has been optimized so protect mode LDT lookup
+ falls stright through.
+
+Arguments:
+
+ Address -- specifies the address in seg:offset format
+ Size -- specifies the size of the region to be accessed.
+ ProtectedMode -- true if the address is a protected mode address
+
+Return Value:
+
+ The pointer.
+
+--*/
+
+{
+ if (ProtectedMode) {
+ return GetPModeVDMPointer(Address, Count);
+ } else {
+ return GetRModeVDMPointer(Address);
+ }
+}
+
+
+PVOID FASTCALL
+GetPModeVDMPointerAssert(
+ DWORD Address
+#ifdef DEBUG
+ , DWORD Count
+#endif
+ )
+/*++
+
+Routine Description:
+
+ Convert a 16:16 protected mode address to the equivalent flat pointer.
+
+Arguments:
+
+ Address -- specifies the address in selector:offset format
+
+Return Value:
+
+ The pointer.
+
+--*/
+
+{
+#ifdef DEBUG
+ void *vp;
+#endif
+
+ //
+ // Check to see if the descriptor is marked present
+ // We assume here that ExpLdt is DWORD ALIGNED to avoid a slower
+ // unaligned access on risc.
+ //
+
+ if (!((ExpLdt)[(Address >> 18) | 1] & LDT_DESC_PRESENT)) {
+ PARM16 Parm16;
+ ULONG ul;
+
+ if ((HIWORD(Address) & STD_SELECTOR_BITS) == STD_SELECTOR_BITS) {
+ // We've determined that the selector is valid and not
+ // present. So we call over to kernel16 to have it load
+ // the selector into a segment register. This forces a
+ // segment fault, and the segment should be brought in.
+ // Note that CallBack16 also calls this routine, so we could
+ // theoretically get into an infinite recursion loop here.
+ // This could only happen if selectors like the 16-bit stack
+ // were not present, which would mean we are hosed anyway.
+ // Such a loop should terminate with a stack fault eventually.
+
+ Parm16.WndProc.lParam = (LONG) Address;
+ CallBack16(RET_FORCESEGMENTFAULT, &Parm16, 0, &ul);
+ } else {
+
+ // We come here if the address can't be resolved. A null
+ // selector is special-cased to allow for a null 16:16
+ // pointer to be passed.
+ if (HIWORD(Address)) {
+
+ LOGDEBUG(LOG_ALWAYS,("WOW::GetVDMPointer: *** Invalid 16:16 address %04x:%04x\n",
+ HIWORD(Address), LOWORD(Address)));
+ // If we get here, then we are about to return a bogus
+ // flat pointer.
+ // I would prefer to eventually assert this, but it
+ // appears to be overactive for winfax lite.
+ //WOW32ASSERT(FALSE);
+
+ }
+
+ }
+ }
+
+
+#ifdef DEBUG
+ if (vp = GetPModeVDMPointerMacro(Address, Count)) {
+
+#ifdef _X86_
+ //
+ // Check the selector limit on x86 only and return NULL if
+ // the limit is too small.
+ //
+
+ if (SelectorLimit &&
+ (Address & 0xFFFF) + Count > SelectorLimit[Address >> 19] + 1)
+ {
+ WOW32ASSERTMSGF (FALSE, ("WOW32 limit check assertion: %04x:%04x size %x is beyond limit %x.\n",
+ Address >> 16,
+ Address & 0xFFFF,
+ Count,
+ SelectorLimit[Address >> 19]
+ ));
+
+ return vp;
+ }
+#endif
+
+#if 0 // this code is a paranoid check, only useful when debugging GetPModeVDMPointer.
+ if (vp != Sim32GetVDMPointer(Address, Count, TRUE)) {
+ LOGDEBUG(LOG_ALWAYS,
+ ("GetPModeVDMPointer: GetPModeVDMPointerMacro(%x) returns %x, Sim32 returns %x!\n",
+ Address, vp, Sim32GetVDMPointer(Address, Count, TRUE)));
+ vp = Sim32GetVDMPointer(Address, Count, TRUE);
+ }
+#endif
+
+ return vp;
+
+ } else {
+
+ return NULL;
+
+ }
+#else
+ return GetPModeVDMPointerMacro(Address, 0); // No limit check on free build.
+#endif // DEBUG
+}
+
+
+
+
+ULONG FASTCALL W32GetFastAddress( PVDMFRAME pFrame )
+{
+#if FASTBOPPING
+ return (ULONG)WOWBopEntry;
+#else
+ return 0;
+#endif
+}
+
+ULONG FASTCALL W32GetFastCbRetAddress( PVDMFRAME pFrame )
+{
+#if FASTBOPPING
+ return (ULONG)FastWOWCallbackRet;
+#else
+ return( 0L );
+#endif
+}
+
+ULONG FASTCALL W32GetTableOffsets( PVDMFRAME pFrame )
+{
+ PWOWGETTABLEOFFSETS16 parg16;
+ PTABLEOFFSETS pto16;
+
+ GETARGPTR(pFrame, sizeof(PDWORD16), parg16);
+ GETVDMPTR(parg16->vpThunkTableOffsets, sizeof(TABLEOFFSETS), pto16);
+
+ RtlCopyMemory(pto16, &tableoffsets, sizeof(TABLEOFFSETS));
+
+ FLUSHVDMPTR(parg16->vpThunkTableOffsets, sizeof(TABLEOFFSETS), pto16);
+ FREEVDMPTR(pto16);
+
+ FREEARGPTR(parg16);
+
+#if FASTBOPPING
+ fKernelCSIPFixed = TRUE;
+#endif
+
+ return 1;
+}
+
+ULONG FASTCALL W32GetFlatAddressArray( PVDMFRAME pFrame )
+{
+#if FASTBOPPING
+ return (ULONG)FlatAddress;
+#else
+ return 0;
+#endif
+}
+
+
+#ifdef DEBUG
+
+/*
+ * DoAssert - do an assertion. called after the expression has been evaluted
+ *
+ * Input:
+ *
+ *
+ * Note if the requested log level is not what we want we don't output
+ * but we always output to the circular buffer - just in case.
+ *
+ *
+ */
+int DoAssert(PSZ szAssert, PSZ szModule, UINT line, UINT loglevel)
+{
+ INT savefloptions;
+
+ //
+ // Start a debugger for WOW if there isn't already one.
+ //
+ // Until now StartDebuggerForWow was started by
+ // the exception filter, which meant asserts on a
+ // checked build got the debugger but the user didn't see
+ // the assertion text on the debugger screen because
+ // logprintf was called before the debugger attached.
+ // -- DaveHart 31-Jan-95
+ //
+
+ StartDebuggerForWow();
+
+ savefloptions = flOptions;
+ flOptions |= OPT_DEBUG; // *always* print the message
+
+ //
+ // szAssert is NULL for bare-bones WOW32ASSERT()
+ //
+
+ if (szAssert == NULL) {
+ LOGDEBUG(loglevel, ("WOW32 assertion failure: %s line %d\n", szModule, line));
+ } else {
+ LOGDEBUG(loglevel, ("%s", szAssert));
+ }
+
+ flOptions = savefloptions;
+
+ if (IsDebuggerAttached()) {
+
+ DbgBreakPoint();
+
+ } else {
+
+ DWORD dw = SetErrorMode(0);
+
+ RaiseException(EXCEPTION_WOW32_ASSERTION, 0, 0, NULL);
+
+ SetErrorMode(dw);
+
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * sprintf_gszAssert
+ *
+ * Used by WOW32ASSERTMSGF to format the assertion text into
+ * a global buffer, gszAssert. There is probably a better way.
+ *
+ * DaveHart 15-Jun-95.
+ *
+ */
+int _cdecl sprintf_gszAssert(PSZ pszFmt, ...)
+{
+ va_list VarArgs;
+
+ va_start(VarArgs, pszFmt);
+
+ return vsprintf(gszAssert, pszFmt, VarArgs);
+}
+
+
+
+/*
+ * logprintf - format log print routine
+ *
+ * Input:
+ * iReqLogLevel - Requested Logging Level
+ *
+ * Note if the requested log level is not what we want we don't output
+ * but we always output to the circular buffer - just in case.
+ *
+ *
+ */
+VOID logprintf(PSZ pszFmt, ...)
+{
+ DWORD lpBytesWritten;
+ int len;
+ char text[1024];
+ va_list arglist;
+
+ va_start(arglist, pszFmt);
+ len = vsprintf(text, pszFmt, arglist);
+
+ // fLog states (set by !wow32.logfile debugger extension):
+ // 0 -> no logging;
+ // 1 -> log to file
+ // 2 -> create log file
+ // 3 -> close log file
+ if(fLog > 1) {
+ if(fLog == 2) {
+ if((hfLog = CreateFile(szLogFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL)) != INVALID_HANDLE_VALUE) {
+ fLog = 1;
+ }
+ else {
+ hfLog = NULL;
+ fLog = 0;
+ OutputDebugString("Couldn't open log file!\n");
+ }
+ }
+ else {
+ FlushFileBuffers(hfLog);
+ CloseHandle(hfLog);
+ hfLog = NULL;
+ fLog = 0;
+ }
+ }
+
+ if ( len > TMP_LINE_LEN-1 ) {
+ text[TMP_LINE_LEN-2] = '\n';
+ text[TMP_LINE_LEN-1] = '\0'; /* Truncate to 128 */
+ }
+
+ IFLOG(iReqLogLevel) {
+ // write to file?
+ if (fLog) {
+ WriteFile(hfLog, text, len, &lpBytesWritten, NULL);
+ }
+ // write to terminal?
+ else if (flOptions & OPT_DEBUG) {
+ OutputDebugString(text);
+ }
+ }
+
+ strcpy(&achTmp[iCircBuffer][0], text);
+ if (--iCircBuffer < 0 ) {
+ iCircBuffer = CIRC_BUFFERS-1;
+ }
+}
+
+/*
+ * checkloging - Some Functions we don't want to log
+ *
+ * Entry
+ * fLogFilter = Filter for Specific Modules - Kernel, User, GDI etc.
+ * fLogTaskFilter = Filter for specific TaskID
+ *
+ * Exit: TRUE - OK to LOG Event
+ * FALSE - Don't Log Event
+ *
+ */
+BOOL checkloging(register PVDMFRAME pFrame)
+{
+ INT i;
+ BOOL bReturn;
+ INT iFun = GetFuncId(pFrame->wCallID);
+ PTABLEOFFSETS pto = &tableoffsets;
+
+
+ // Filter on Specific Call IDs
+
+ if (awfLogFunctionFilter[0] != 0xffff) {
+ INT nOrdinal;
+
+ nOrdinal = GetOrdinal(iFun);
+
+ bReturn = FALSE;
+ for (i=0; i < FILTER_FUNCTION_MAX ; i++) {
+ if (awfLogFunctionFilter[i] == nOrdinal) {
+ bReturn = TRUE;
+ break;
+ }
+ }
+ } else {
+ bReturn = TRUE;
+ }
+
+ // Do not LOG Internal Kernel Calls below level 20
+ if (iLogLevel < 20 ) {
+ if((iFun == FUN_WOWOUTPUTDEBUGSTRING) ||
+ ((iFun < pto->user) && (iFun >= FUN_WOWINITTASK)))
+
+ bReturn = FALSE;
+ }
+
+ // LOG Only Specific TaskID
+
+ if (fLogTaskFilter != 0xffff) {
+ if (fLogTaskFilter != pFrame->wTDB) {
+ bReturn = FALSE;
+ }
+ }
+
+ // LOG Filter On Modules USER/GDI/Kernel etc.
+
+ switch (ModFromCallID(iFun)) {
+
+ case MOD_KERNEL:
+ if ((fLogFilter & FILTER_KERNEL) == 0 )
+ bReturn = FALSE;
+ break;
+ case MOD_USER:
+ if ((fLogFilter & FILTER_USER) == 0 )
+ bReturn = FALSE;
+ break;
+ case MOD_GDI:
+ if ((fLogFilter & FILTER_GDI) == 0 )
+ bReturn = FALSE;
+ break;
+ case MOD_KEYBOARD:
+ if ((fLogFilter & FILTER_KEYBOARD) == 0 )
+ bReturn = FALSE;
+ break;
+ case MOD_SOUND:
+ if ((fLogFilter & FILTER_SOUND) == 0 )
+ bReturn = FALSE;
+ break;
+ case MOD_MMEDIA:
+ if ((fLogFilter & FILTER_MMEDIA) == 0 )
+ bReturn = FALSE;
+ break;
+ case MOD_WINSOCK:
+ if ((fLogFilter & FILTER_WINSOCK) == 0 )
+ bReturn = FALSE;
+ break;
+ case MOD_COMMDLG:
+ if ((fLogFilter & FILTER_COMMDLG) == 0 ) {
+ bReturn = FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+ return (bReturn);
+}
+
+
+/*
+ * Argument Logging For Tracing API Calls
+ *
+ *
+ */
+VOID logargs(INT iLog, register PVDMFRAME pFrame)
+{
+ register PBYTE pbArgs;
+ INT iFun;
+ INT cbArgs;
+
+ if (checkloging(pFrame)) {
+ iFun = GetFuncId(pFrame->wCallID);
+ cbArgs = aw32WOW[iFun].cbArgs; // Get Number of Parameters
+
+ if ((fLogFilter & FILTER_VERBOSE) == 0 ) {
+ LOGDEBUG(iLog,("%s(", aw32WOW[iFun].lpszW32));
+ } else {
+ LOGDEBUG(iLog,("%04X %08X %04X %s:%s(",pFrame->wTDB, pFrame->vpCSIP,pFrame->wAppDS, GetModName(iFun), aw32WOW[iFun].lpszW32));
+ }
+
+ GETARGPTR(pFrame, cbArgs, pbArgs);
+ pbArgs += cbArgs;
+
+ //
+ // Log the function arguments a word at a time.
+ // The first iteration of the while loop is unrolled so
+ // that the main loop doesn't have to figure out whether
+ // or not to print a comma.
+ //
+
+ if (cbArgs > 0) {
+
+ pbArgs -= sizeof(WORD);
+ cbArgs -= sizeof(WORD);
+ LOGDEBUG(iLog,("%04x", *(PWORD16)pbArgs));
+
+ while (cbArgs > 0) {
+
+ pbArgs -= sizeof(WORD);
+ cbArgs -= sizeof(WORD);
+ LOGDEBUG(iLog,(",%04x", *(PWORD16)pbArgs));
+
+ }
+ }
+
+ FREEARGPTR(pbArgs);
+ LOGDEBUG(iLog,(")\n"));
+
+ if (fDebugWait != 0) {
+ DbgPrint("WOWSingle Step\n");
+ DbgBreakPoint();
+ }
+ }
+}
+
+
+/*
+ * logreturn - Log Return Values From Call
+ *
+ * Entry
+ *
+ * Exit - None
+ */
+VOID logreturn(INT iLog, register PVDMFRAME pFrame, ULONG ulReturn)
+{
+ INT iFun;
+
+ if (checkloging(pFrame)) {
+ iFun = GetFuncId(pFrame->wCallID);
+ if ((fLogFilter & FILTER_VERBOSE) == 0 ) {
+ LOGDEBUG(iLog,("%s: %lx\n", aw32WOW[iFun].lpszW32, ulReturn));
+ } else {
+ LOGDEBUG(iLog,("%04X %08X %04X %s:%s: %lx\n", pFrame->wTDB, pFrame->vpCSIP, pFrame->wAppDS, GetModName(iFun), aw32WOW[iFun].lpszW32, ulReturn));
+ }
+ }
+}
+
+#endif // DEBUG
+
+PVOID FASTCALL malloc_w (ULONG size)
+{
+ PVOID pv;
+
+ pv = HeapAlloc(hWOWHeap, 0, size);
+ WOW32ASSERTMSG(pv, "WOW32: malloc_w failing, returning NULL\n");
+ return pv;
+}
+
+PVOID FASTCALL malloc_w_zero (ULONG size)
+{
+ PVOID pv;
+
+ pv = HeapAlloc(hWOWHeap, HEAP_ZERO_MEMORY, size);
+ WOW32ASSERTMSG(pv, "WOW32: malloc_w_zero failing, returning NULL\n");
+ return pv;
+}
+
+PVOID FASTCALL realloc_w (PVOID p, ULONG size, DWORD dwFlags)
+{
+ PVOID pv;
+
+ pv = HeapReAlloc(hWOWHeap, dwFlags, p, size);
+ WOW32ASSERTMSG(pv, "WOW32: realloc_w failing, returning NULL\n");
+ return pv;
+}
+
+VOID FASTCALL free_w (PVOID p)
+{
+ HeapFree(hWOWHeap, 0, (LPSTR)(p));
+}
+
+//
+// malloc_w_or_die is for use by *initialization* code only, when we
+// can't get WOW going because, for example, we can't allocate a buffer
+// to hold the known DLL list.
+//
+// malloc_w_or_die should not be used by API or message thunks or worker
+// routines called by API or message thunks.
+//
+
+PVOID FASTCALL malloc_w_or_die(ULONG size)
+{
+ PVOID pv;
+ if (!(pv = malloc_w(size))) {
+ WOW32ASSERTMSG(pv, "WOW32: malloc_w_or_die failing, terminating.\n");
+ WOWStartupFailed(); // never returns.
+ }
+ return pv;
+}
+
+//
+// WOWStartupFailed puts up a fatal error box and terminates WOW.
+//
+
+PVOID WOWStartupFailed(VOID)
+{
+ char szCaption[256];
+ char szMsgBoxText[1024];
+
+ LoadString(hmodWOW32, iszStartupFailed, szMsgBoxText, sizeof szMsgBoxText);
+ LoadString(hmodWOW32, iszSystemError, szCaption, sizeof szCaption);
+
+ MessageBox(GetDesktopWindow(),
+ szMsgBoxText,
+ szCaption,
+ MB_SETFOREGROUND | MB_TASKMODAL | MB_ICONSTOP | MB_OK | MB_DEFBUTTON1);
+
+ ExitVDM(WOWVDM, ALL_TASKS); // Tell Win32 All Tasks are gone.
+ ExitProcess(EXIT_FAILURE);
+ return (PVOID)NULL;
+}
+
+
+//****************************************************************************
+#ifdef DEBUG_OR_WOWPROFILE
+DWORD GetWOWTicDiff(DWORD dwPrevCount) {
+/*
+ * Returns difference between a previous Tick count & the current tick count
+ *
+ * NOTE: Tick counts are in unspecified units (PerfFreq is in MHz)
+ */
+ DWORD dwDiff;
+ LARGE_INTEGER PerfCount, PerfFreq;
+
+ NtQueryPerformanceCounter(&PerfCount, &PerfFreq);
+
+ /* if ticks carried into high dword (assuming carry was only one) */
+ if( dwPrevCount > PerfCount.LowPart ) {
+ /* (0xFFFFFFFF - (dwPrevCount - LowPart)) + 1L caused compiler to
+ optimize in an arithmetic overflow, so we do it in two steps
+ to fool Mr. compiler
+ */
+ dwDiff = (dwPrevCount - PerfCount.LowPart) - 1L;
+ dwDiff = ((DWORD)0xFFFFFFFF) - dwDiff;
+ }
+ else {
+ dwDiff = PerfCount.LowPart - dwPrevCount;
+ }
+
+ return(dwDiff);
+
+}
+
+INT GetFuncId(DWORD iFun)
+{
+ INT i;
+
+ if (iFuncId == 0) {
+ if (!ISFUNCID(iFun)) {
+ for (i = 0; i < cAPIThunks; i++) {
+ if (aw32WOW[i].lpfnW32 == (LPFNW32)iFun) {
+ iFun = i;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ iFun = iFuncId;
+ }
+
+ return iFun;
+}
+#endif // DEBUG_OR_WOWPROFILE
diff --git a/private/mvdm/wow32/wow32.def b/private/mvdm/wow32/wow32.def
new file mode 100644
index 000000000..2a18cfb91
--- /dev/null
+++ b/private/mvdm/wow32/wow32.def
@@ -0,0 +1,43 @@
+LIBRARY wow32
+
+DESCRIPTION 'WOW32 DLL for MVDM'
+
+EXPORTS
+
+ W32Init
+ W32Dispatch
+ W32HungAppNotifyThread
+
+ GetCommShadowMSR
+ GetCommHandle
+
+ WOW32DriverCallback
+ WOW32ResolveHandle
+
+ WOW32ResolveMemory
+
+ WOWGetVDMPointer
+ WOWGetVDMPointerFix = WOWGetVDMPointer
+ WOWGetVDMPointerUnfix
+
+ WOWGlobalAlloc16
+ WOWGlobalFree16
+ WOWGlobalLock16
+ WOWGlobalUnlock16
+ WOWGlobalAllocLock16
+ WOWGlobalUnlockFree16
+ WOWGlobalLockSize16
+
+ WOWYield16
+ WOWDirectedYield16
+
+ WOWHandle32
+ WOWHandle16
+
+ WOWFreeMetafile
+
+ WOWCallback16
+ WOWCallback16Ex
+
+ CopyDropFilesFrom32
+ CopyDropFilesFrom16
diff --git a/private/mvdm/wow32/wow32.h b/private/mvdm/wow32/wow32.h
new file mode 100644
index 000000000..0b2ef26b7
--- /dev/null
+++ b/private/mvdm/wow32/wow32.h
@@ -0,0 +1,675 @@
+/*++ BUILD Version: 0003
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WOW32.H
+ * WOW32 16-bit API support
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * Changed 12-May-1992 by Mike Tricker (MikeTri) Added MultiMedia header includes
+ * Changed 30-Jul-1992 by Mike Tricker (MikeTri) Removed all Multimedia includes
+--*/
+#ifndef _DEF_WOW32_ // if this hasn't already been included
+#define _DEF_WOW32_
+
+
+#define HACK32
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#ifdef i386
+ #define PMODE32
+ #define FASTCALL _fastcall
+#else
+ #define FASTCALL
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <process.h>
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+#include <winuserp.h>
+#include <shellapi.h>
+
+#include <wow.h>
+
+#include "walias.h"
+#include "wstruc.h"
+#include "wheap.h"
+#include "wowcmpat.h"
+
+
+//
+// Enable warnings that are turned off by sdk\inc\warning.h but we want on
+//
+#pragma warning(error:4101) // Unreferenced local variable
+
+
+/* Constants
+ */
+#define CIRC_BUFFERS 100 // Number of Saved in Circular Buffer for debug logging only
+#define TMP_LINE_LEN 200 // maxlen of Circular Buffer strings
+#define FILTER_FUNCTION_MAX 10 // Number of Calls you can filter on
+
+#define WOWPRIVATEMSG 0x00010000 // this gets OR'd into certain 16-bit msg's
+ // for handling special message cases
+
+#define CLR_BLACK 0x00000000
+#define CLR_RED 0x007F0000
+#define CLR_GREEN 0x00007F00
+#define CLR_BROWN 0x007F7F00
+#define CLR_BLUE 0x0000007F
+#define CLR_MAGENTA 0x007F007F
+#define CLR_CYAN 0x00007F7F
+#define CLR_LT_GRAY 0x00BFBFBF
+
+#define CLR_DK_GRAY 0x007F7F7F
+#define CLR_BR_RED 0x00FF0000
+#define CLR_BR_GREEN 0x0000FF00
+#define CLR_YELLOW 0x00FFFF00
+#define CLR_BR_BLUE 0x000000FF
+#define CLR_BR_MAGENTA 0x00FF00FF
+#define CLR_BR_CYAN 0x0000FFFF
+#define CLR_WHITE 0x00FFFFFF
+
+#define WM_CTLCOLOR 0x0019
+
+#define WM_WOWDESTROYCLIPBOARD 0x0
+#define WM_WOWSETCBDATA 0x0
+
+#define WOWVDM TRUE
+
+/***** ifdef( DEBUG || WOWPROFILE ) *****/
+#ifdef DEBUG
+#ifndef WOWPROFILE
+#define WOWPROFILE // DEBUG => WOWPROFILE
+#endif // !WOWPROFILE
+#endif // DEBUG
+
+#ifdef WOWPROFILE
+#ifndef DEBUG_OR_WOWPROFILE
+#define DEBUG_OR_WOWPROFILE
+#endif
+#endif // WOWPROFILE
+
+
+/* Types
+ */
+typedef ULONG (FASTCALL *LPFNW32)(PVDMFRAME);
+
+
+/* Dispatch table entry DO NOT CHANGE THE SIZES OF THESE TABLES WITHOUT
+** CHANGING I386\FASTWOW.ASM!
+ */
+typedef struct _W32 { /* w32 */
+ LPFNW32 lpfnW32; // function address
+#ifdef DEBUG_OR_WOWPROFILE
+ LPSZ lpszW32; // function name (DEBUG version only)
+ INT cbArgs; // # of bytes of arguments (DEBUG version only)
+ DWORD cCalls; // # of times this API called
+ DWORD cTics; // sum total # of tics ellapsed for all invocations
+#endif // DEBUG_OR_WOWPROFILE
+} W32, *PW32;
+
+
+/* DO NOT CHANGE THE SIZES OF THESE TABLES WITHOUT
+** CHANGING I386\FASTWOW.ASM!
+*/
+typedef struct _PA32 {
+ PW32 lpfnA32; // Array Address
+#ifdef DEBUG_OR_WOWPROFILE
+ LPSZ lpszW32; // Table Name (DEBUG version only)
+ INT *lpiFunMax; // Pointer # of table entries (DEBUG version only)
+#endif // DEBUG_OR_WOWPROFILE
+} PA32, *PPA32;
+
+
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+#define W32FUN(fn,name,mod,size) fn,name,size,0L,0L
+#define W32MSGFUN(fn,name) fn,name,0L,0L
+#else // non-profile RETAIL
+#define W32FUN(fn,name,mod,size) fn
+#define W32MSGFUN(fn,name) fn
+#endif
+
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+#define W32TAB(fn,name,size) fn,name,&size
+#else // RETAIL ONLY
+#define W32TAB(fn,name,size) fn
+#endif
+
+
+/* Per-thread data
+ */
+#define CURRENTPTD() ((PTD)(NtCurrentTeb()->WOW32Reserved))
+#define PTEBTOPTD(pteb) ((PTD)((pteb)->WOW32Reserved))
+
+
+//
+// Internal flags used in the COMMDLGTD Flags element
+//
+
+#define WOWCD_ISCHOOSEFONT 1
+#define WOWCD_ISOPENFILE 2
+
+//
+// Used for COMMDLG thunk support
+//
+
+typedef struct _COMMDLGTD {
+ HWND16 hdlg;
+ VPVOID vpfnHook;
+ VPVOID vpData;
+ ULONG ExtendedErr;
+ union {
+ VPVOID vpfnSetupHook;
+ PVOID pRes;
+ };
+ HWND16 SetupHwnd;
+ struct _COMMDLGTD *Previous;
+ PVOID pData32;
+ ULONG Flags;
+} COMMDLGTD, *PCOMMDLGTD;
+
+
+//
+// WOAINST
+//
+
+typedef struct _WOAINST {
+ struct _WOAINST *pNext;
+ struct _TD *ptdWOA; // TD of associated WinOldAp task
+ DWORD dwChildProcessID;
+ HANDLE hChildProcess;
+ CHAR szModuleName[1]; // As provided to LoadModule
+} WOAINST, *PWOAINST;
+
+
+//
+// TD.dwFlags bit definitions
+//
+
+#define TDF_INITCALLBACKSTACK 0x00000001
+#define TDF_IGNOREINPUT 0x00000002
+#define TDF_FORCETASKEXIT 0x00000004
+#define TDF_TASKCLEANUPDONE 0x00000008
+#define TDF_SETUPAPPLICATION 0x00000010
+
+typedef struct _TD { /* td */
+ VPVOID vpStack; // 16-bit stack MUST BE FIRST!!!
+ VPVOID vpCBStack; // 16-bit callback frame
+ DWORD FastWowEsp; // offset must match mvdm\inc\vdmtb.inc
+ struct _TD *ptdNext; // Pointer to Next PTD
+ DWORD dwFlags; // TDF_ values above
+ INT VDMInfoiTaskID; // SCS Task ID != 0 if task Exec'd form 32 bit program
+ PCOMMDLGTD CommDlgTd; // COMMDLG support - jvert 5-Jan-1993
+ DWORD dwWOWCompatFlags; // WOW Compatibility flags
+ DWORD dwWOWCompatFlagsEx;// Extended WOW Compatibility flags
+ DWORD dwThreadID; // ID of the thread
+ HANDLE hThread; // Thread Handle
+ HHOOK hIdleHook; // Hook handle for USER idle notification
+ HRGN hrgnClip; // used by GetClipRgn()
+ ULONG ulLastDesktophDC; // remembers last desktop DC for GetDC(0)
+ PWOAINST pWOAList; // One per active winoldap child
+ HAND16 htask16; // 16-bit kernel task handle - unique across VDMs
+ HAND16 hInst16; // 16-bit instance handle for this task
+ HAND16 hMod16; // 16-bit module handle for this task
+} TD, *PTD;
+
+
+/* Options (for flOptions)
+ *
+ * Bits 0-15 are RESERVED for use by x86,
+ * so it must match the x86 definition, if any! -JTP
+ */
+#define OPT_DEBUG 0x00008 // shadow all log output on debug terminal (/d)
+#define OPT_BREAKONNEWTASK 0x00010 // breakpoint on new task start
+#define OPT_DONTPATCHCODE 0x00020 // doesnt patch wcallid with lpfnw32
+#define OPT_DEBUGRETURN 0x10000 // convert next WOW16 return to debug return
+#define OPT_FAKESUCCESS 0x20000 // convert selected failures into successes
+
+/* Logging Filtering Options (fLogFilter)
+ *
+ * To Log all output set fLogFilter = -1
+ */
+
+#define FILTER_KERNEL 0x00000001
+#define FILTER_USER 0x00000002
+#define FILTER_GDI 0x00000004
+#define FILTER_KEYBOARD 0x00000008
+#define FILTER_SOUND 0x00000010
+#define FILTER_KERNEL16 0X00000020
+#define FILTER_MMEDIA 0x00000040
+#define FILTER_WINSOCK 0x00000080
+#define FILTER_VERBOSE 0x00000100
+#define FILTER_COMMDLG 0x00000200
+
+/* Global data
+ */
+#ifdef DEBUG
+extern UCHAR gszAssert[256]; // Buffer for assertion text (could be eliminated with restructuring)
+int _cdecl sprintf_gszAssert(PSZ pszFmt, ...);
+extern HANDLE hfLog; // log file handle, if any
+#endif
+extern INT flOptions; // command-line options (see OPT_*)
+#ifdef DEBUG
+extern INT iLogLevel; // logging level; 0 implies none
+extern INT fDebugWait; // Single Step; 0 = No Single Step
+#endif
+extern HANDLE hHostInstance;
+#ifdef DEBUG
+extern INT fLogFilter; // Filter Catagories of Functions
+extern WORD fLogTaskFilter; // Filter Specific TaskID only
+#endif
+#ifdef i386
+extern PX86CONTEXT pIntelRegisters; // x86 Only - Pointer to Intel Register Block
+#endif
+
+#ifdef DEBUG
+extern INT iReqLogLevel; // Current Output LogLevel
+extern INT iCircBuffer; // Current Buffer
+extern CHAR achTmp[CIRC_BUFFERS][TMP_LINE_LEN]; // Circular Buffer
+extern WORD awfLogFunctionFilter[FILTER_FUNCTION_MAX]; // Specific Filter API Array
+extern INT iLogFuncFiltIndex; // Index Into Specific Array for Debugger Extensions
+#endif
+
+
+/* WOW global data
+ */
+extern UINT iW32ExecTaskId; // Base Task ID of Task Being Exec'd
+extern UINT nWOWTasks; // # of WOW tasks running
+extern BOOL fBoot; // TRUE During Boot Process
+extern HANDLE ghevWaitCreatorThread; // Used to Syncronize creation of a new thread
+extern WORD iWOWTaskCur; // ID of current task running
+extern BOOL fWowMode; // see comment in wow32.c
+extern HANDLE hWOWHeap;
+extern DECLSPEC_IMPORT BOOL fSeparateWow; // imported from ntvdm, FALSE if shared WOW VDM.
+extern HANDLE ghProcess; // WOW Process Handle
+extern PFNWOWHANDLERSOUT pfnOut; // USER secret API pointers
+extern DECLSPEC_IMPORT DWORD FlatAddress[]; // Base address of each selector in LDT
+extern DECLSPEC_IMPORT LPDWORD SelectorLimit; // Limit of each selector in LDT (x86 only)
+extern PTD * pptdWOA;
+extern PTD gptdShell;
+extern char szEmbedding[];
+extern char szServerKey[];
+extern char szPicture[];
+extern char szPostscript[];
+extern char szZapfDingbats[];
+extern char szZapf_Dingbats[];
+extern char szSymbol[];
+extern char szTmsRmn[];
+extern char szHelv[];
+extern char szMavisCourier[];
+extern char szDevices[];
+extern char szBoot[];
+extern char szShell[];
+extern char szWinDotIni[];
+extern char szSystemDotIni[];
+extern char szExplorerDotExe[];
+extern PSTR pszWinIniFullPath;
+extern PSTR pszWindowsDirectory;
+extern PSTR pszSystemDirectory;
+extern BOOL gfIgnoreInputAssertGiven;
+
+
+
+#ifndef _X86_
+extern PUCHAR IntelMemoryBase; // Start of emulated CPU's memory
+#define pNtVDMState ((ULONG *)(IntelMemoryBase+FIXED_NTVDMSTATE_LINEAR))
+#endif
+
+
+/* WOW32 assertion/warning macros
+ *
+ * Take care where you put ASSERTs and where you put VERIFYs; ASSERT
+ * expressions go away in the retail product, VERIFYs don't, so if an essential
+ * calculation or function call is taking place, put it in WOW32VERIFY().
+ *
+ * WOW32ASSERT(exp) - prints module and line number and breakpoints
+ * WOW32VERIFY(exp) - like WOW32ASSERT but expression evaluated on free build
+ * WOW32ASSERTMSG(exp, msg) - print the string and breakpoint
+ * WOW32ASSERTMSGF(exp, (fmt, args...)) - print the formatted string and
+ * breakpoint
+ * WOW32WARNMSG(exp, msg) - print the string but don't breakpoint
+ * WOW32WARNMSGF(exp, (fmt, args, ...)) - print the formatted string but don't
+ * breakpoint
+ * WOW32APIWARN(exp, msg) - specific to API thunks, msg must be API name,
+ * does not breakpoint at all.
+ */
+
+#define EXCEPTION_WOW32_ASSERTION 0x9898
+
+#ifdef DEBUG
+#undef MODNAME
+#define MODNAME(module) static char szModule[] = __FILE__
+
+int DoAssert(PSZ szAssert, PSZ szModule, UINT line, UINT loglevel);
+
+#define WOW32ASSERT(exp) \
+{ \
+ if (!(exp)) \
+ { \
+ DoAssert(NULL, szModule, __LINE__, LOG_ALWAYS); \
+ } \
+}
+
+#define WOW32VERIFY(exp) WOW32ASSERT(exp)
+
+#define WOW32ASSERTMSG(exp,msg) \
+{ \
+ if (!(exp)) { \
+ DoAssert(msg, szModule, __LINE__, LOG_ALWAYS); \
+ } \
+}
+
+#define WOW32ASSERTMSGF(exp, printf_args) \
+( \
+ (!(exp)) ? ( \
+ sprintf_gszAssert printf_args, \
+ DoAssert(gszAssert, szModule, __LINE__, LOG_ALWAYS) \
+ ) : 0 \
+)
+
+#define WOW32WARNMSG(exp,msg) \
+{ \
+ if (!(exp)) { \
+ LOGDEBUG(LOG_ALWAYS, ("%s", (msg))); \
+ } \
+}
+
+#define WOW32WARNMSGF(exp, printf_args) \
+{ \
+ if (!(exp)) { \
+ LOGDEBUG(LOG_ALWAYS, printf_args); \
+ } \
+}
+
+#define WOW32APIWARN(exp,msg) \
+{ \
+ if (!(exp)) { \
+ LOGDEBUG(1,(" WOW32 WARNING: %s failed", (msg))); \
+ if (flOptions & OPT_FAKESUCCESS) { \
+ LOGDEBUG(1,(" (but returning fake success)\n")); \
+ (ULONG)exp = TRUE; \
+ } \
+ else { \
+ LOGDEBUG(1,("\n")); \
+ } \
+ } \
+}
+
+#else
+#ifndef i386
+#undef MODNAME
+#define MODNAME(module) static DWORD no_extra_semicolon_on_mipsfree
+#endif // MIPS
+#define WOW32ASSERT(exp)
+#define WOW32VERIFY(exp) (exp)
+#define WOW32ASSERTMSG(exp,msg)
+#define WOW32ASSERTMSGF(exp,msg)
+#define WOW32WARNMSG(exp,msg)
+#define WOW32WARNMSGF(exp,msg)
+#define WOW32APIWARN(exp,msg)
+#endif
+
+#ifdef DEBUG
+#define LOGARGS(l,v) logargs(l,v)
+#else
+#define LOGARGS(l,v)
+#endif
+
+#ifdef DEBUG
+#define LOGRETURN(l,v,r) logreturn(l,v,r)
+#else
+#define LOGRETURN(l,v,r)
+#endif
+
+//
+// Macros used to eliminate compiler warning generated when formal
+// parameters or local variables are not declared.
+//
+// Use DBG_UNREFERENCED_PARAMETER() when a parameter is not yet
+// referenced but will be once the module is completely developed.
+//
+// Use DBG_UNREFERENCED_LOCAL_VARIABLE() when a local variable is not yet
+// referenced but will be once the module is completely developed.
+//
+// Use UNREFERENCED_PARAMETER() if a parameter will never be referenced.
+//
+// DBG_UNREFERENCED_PARAMETER and DBG_UNREFERENCED_LOCAL_VARIABLE will
+// eventually be made into a null macro to help determine whether there
+// is unfinished work.
+//
+
+#ifndef UNREFERENCED_PARAMETER
+#define UNREFERENCED_PARAMETER(P) (P)
+#define DBG_UNREFERENCED_PARAMETER(P) (P)
+#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (V)
+#endif
+
+#define SIZE_BOGUS 256
+
+#define SIZETO64K(s) (s?(INT)s:(INT)(64*K)) // return 64K if zero
+
+#define CHAR32(b) ((CHAR)(b))
+#define BYTE32(b) ((BYTE)(b))
+#define INT32(i) ((INT)(INT16)(i))
+#define UINT32(i) ((unsigned int)(i))
+#define BOOL32(f) ((BOOL)(f))
+#define WORD32(w) ((WORD)(w))
+#define LONG32(l) FETCHLONG(l)
+#define DWORD32(dw) FETCHDWORD(dw)
+#define VPFN32(fn) FETCHDWORD(fn)
+#define INT32DEFAULT(i) ((WORD)i==(WORD)CW_USEDEFAULT16?(UINT)(WORD)i:INT32(i))
+
+#define GETBYTE16(v) (v)
+#define GETINT16(v) ((INT16)(v))
+#define GETBOOL16(v) ((BOOL16)(v))
+#define GETWORD16(v) (v)
+#define GETLONG16(v) (v)
+#define GETDWORD16(v) (v)
+#define GETUINT16(v) ((WORD)(v))
+
+
+#define ATOM32(a16) (a16) // bogus
+#define PROC32(vpfn16) ((PROC)FETCHDWORD(vpfn16))
+#define NPSTR32(np16) ((NPSTR)(np16)) // bogus
+
+#define GETATOM16(v) (v) // bogus
+#define GETPROC16(v) ((ULONG)(v)) // bogus
+#define GETWNDPROC16(v) ((ULONG)(v)) // bogus
+#define GETNPSTRBOGUS(v) ((ULONG)(INT)(v)) // bogus
+#define GETLPSTRBOGUS(v) ((ULONG)(v)) // bogus
+#define GETLPWORDBOGUS(v) ((ULONG)(v)) // bogus
+
+
+/* Simulator wrapper macros
+ */
+#ifndef _X86_ // emulated CPU
+#define VDMSTACK() (((ULONG)getSS()<<16)|getSP())
+#define SETVDMSTACK(vp) {setSS(HIW(vp)); setSP(LOW(vp));}
+#else // X86
+#define VDMSTACK() ((USHORT)pIntelRegisters->SegSs << 16 | (USHORT)pIntelRegisters->Esp)
+#define SETVDMSTACK(vp) pIntelRegisters->SegSs = HIW(vp); pIntelRegisters->Esp = LOW(vp);
+#endif
+
+// Use FlatAddress array exported by ntvdm instead of Sim32GetVDMPointer.
+
+#ifndef _X86_
+#define INTEL_MEMORY_BASE ((DWORD)IntelMemoryBase)
+#else
+#define INTEL_MEMORY_BASE (0)
+#endif
+
+#define GetPModeVDMPointerMacro(Address, Count) \
+ ( \
+ FlatAddress[(Address) >> 19] \
+ ? (void *)(FlatAddress[(Address) >> 19] + ((Address) & 0xFFFF)) \
+ : NULL \
+ )
+
+#define SetPModeVDMPointerBase(Selector, Base) \
+ { \
+ FlatAddress[Selector >> 3] = Base; \
+ } \
+
+
+#define GetRModeVDMPointer(Address) \
+ (void *)(INTEL_MEMORY_BASE + (((Address) & 0xFFFF0000) >> 12) + \
+ ((Address) & 0xFFFF))
+
+#ifdef DEBUG
+ PVOID FASTCALL GetPModeVDMPointerAssert(DWORD Address, DWORD Count);
+ #define GetPModeVDMPointer(vp, count) GetPModeVDMPointerAssert((vp), (count))
+#else
+ PVOID FASTCALL GetPModeVDMPointerAssert(DWORD Address);
+ #define GetPModeVDMPointer(vp, count) GetPModeVDMPointerAssert((vp))
+#endif
+
+
+#define SEGPTR(seg,off) GetPModeVDMPointer(((ULONG)seg<<16)|off, 0)
+#define FRAMEPTR(vp) ((PVDMFRAME)GetPModeVDMPointer(vp, 0))
+#define CBFRAMEPTR(vp) ((PCBVDMFRAME)GetPModeVDMPointer(vp, 0))
+
+#define GETFRAMEPTR(vp,p) {p=FRAMEPTR(vp); }
+#define GETARGPTR(p,cb,parg) parg=(PVOID)((ULONG)p+OFFSETOF(VDMFRAME,bArgs));
+
+#define VDMPTR(vp,cb) (PVOID)GetPModeVDMPointer(FETCHDWORD(vp),(cb))
+#define GETVDMPTR(vp,cb,p) ((p)=VDMPTR((vp),(cb)))
+#define GETOPTPTR(vp,cb,p) {(p)=NULL; if (FETCHDWORD(vp)) GETVDMPTR(vp,cb,p);}
+#define GETSTRPTR(vp,cb,p) {GETVDMPTR(vp,cb,p); LOGDEBUG(11,(" String @%08lx: \"%.*s\"\n",vp,min((cb),80),(p)));}
+#define GETVARSTRPTR(vp,cb,p) {GETVDMPTR(vp,(((cb)==-1)?1:(cb)),p); LOGDEBUG(11,(" String @%08lx: \"%.*s\"\n",(vp),min(((cb)==-1)?strlen(p):(cb),80),(p)));}
+#define GETPSZPTR(vp,p) {GETOPTPTR(vp,1,p); LOGDEBUG(11,(" String @%08lx: \"%.80s\"\n",(FETCHDWORD(vp)),(p)));}
+#define GETPSZPTRNOLOG(vp,p) GETOPTPTR(vp,1,p)
+#define GETPSZIDPTR(vp,p) {p=(LPSZ)FETCHDWORD(vp); if (HIW16(vp)) GETPSZPTR(vp,p);}
+#define GETMISCPTR(vp,p) GETOPTPTR(vp,1,p) // intended for non-string variable-length pointers
+#define ALLOCVDMPTR(vp,cb,p) GETVDMPTR(vp,cb,p) // intended for output-only pointers
+
+//
+// Macros to "flush" VDM pointers after modifying 16-bit memory.
+// Use FLUSHVDMCODEPTR when the 16-bit memory contains x86 code.
+// Use FLUSHVDMPTR when the 16-bit memory does not contain x86 code.
+//
+// On x86, these macros are NOPs. On RISC, FLUSHVDMPTR is a NOP, while
+// FLUSHVDMCODEPTR actually calls the emulator so it can recompile any
+// code affected.
+//
+
+#define FLUSHVDMCODEPTR(vp,cb,p) Sim32FlushVDMPointer( (vp), (USHORT)(cb), (PBYTE)(p), (fWowMode))
+//#define FLUSHVDMPTR(vp,cb,p) TRUE // BUGBUG! davehart
+#define FLUSHVDMPTR(vp,cb,p) FLUSHVDMCODEPTR(vp,cb,p)
+
+#define LOG_ALWAYS 0x00
+#define LOG_ERROR 0x01
+#define LOG_IMPORTANT LOG_ERROR
+#define LOG_WARNING 0x02
+#define LOG_TRACE 0x04
+#define LOG_PRIVATE 0x08
+#define LOG_API 0x10
+#define LOG_MSG 0x20
+#define LOG_CALLBACK 0x40
+#define LOG_STRING 0x80
+
+
+#ifndef i386
+#ifdef DEBUG
+static CHAR *pszLogNull = "<null>";
+#undef GETPSZPTR
+#define GETPSZPTR(vp,p) {GETOPTPTR(vp,0,p); LOGDEBUG(11,(" String @%08lx: \"%.80s\"\n",(FETCHDWORD(vp)),p ? p : pszLogNull));}
+#endif
+#endif
+
+#ifndef DEBUG
+#define FREEARGPTR(p)
+#define FREEOPTPTR(p)
+#define FREESTRPTR(p)
+#define FREEPSZPTR(p)
+#define FREEPSZIDPTR(p)
+#define FREEMISCPTR(p)
+#define FREEVDMPTR(p)
+#define FREEOPTPTR(p)
+#else
+#define FREEARGPTR(p) p=NULL
+#define FREEOPTPTR(p) p=NULL
+#define FREESTRPTR(p) p=NULL
+#define FREEPSZPTR(p) p=NULL
+#define FREEPSZIDPTR(p) p=NULL
+#define FREEMISCPTR(p) p=NULL
+#define FREEVDMPTR(p) p=NULL
+#define FREEOPTPTR(p) p=NULL
+#endif
+
+#define RETURN(ul) return ul
+
+
+/* Function prototypes
+ */
+BOOL W32Init(VOID);
+VOID W32Dispatch(VOID);
+INT W32Exception(DWORD dwException, PEXCEPTION_POINTERS pexi);
+BOOLEAN W32DllInitialize(PVOID DllHandle,ULONG Reason,PCONTEXT Context);
+BOOL IsDebuggerAttached(VOID);
+
+ULONG FASTCALL W32GetFastAddress( PVDMFRAME pFrame );
+ULONG FASTCALL W32GetFastCbRetAddress( PVDMFRAME pFrame );
+ULONG FASTCALL W32GetTableOffsets( PVDMFRAME pFrame );
+ULONG FASTCALL W32GetFlatAddressArray( PVDMFRAME pFrame );
+PTD ThreadProcID32toPTD(DWORD ThreadID, DWORD dwProcessID);
+PTD Htask16toPTD( HAND16 );
+HTASK16 ThreadID32toHtask16(DWORD ThreadID32);
+PVOID WOWStartupFailed(VOID);
+
+#ifdef DEBUG
+VOID logprintf(PSZ psz, ...);
+VOID logargs(INT iLog, PVDMFRAME pFrame);
+VOID logreturn(INT iLog, PVDMFRAME pFrame, ULONG ulReturn);
+BOOL checkloging(register PVDMFRAME pFrame);
+#endif
+
+#ifdef DEBUG_OR_WOWPROFILE
+DWORD GetWOWTicDiff(DWORD dwPrevCount);
+INT GetFuncId(DWORD iFun);
+#endif
+
+BOOL IsDebuggerAttached(VOID);
+
+//
+// Thunk table stub functions and aliases.
+//
+
+ULONG FASTCALL WOW32UnimplementedAPI(PVDMFRAME pFrame);
+
+#ifdef DEBUG
+ ULONG FASTCALL WOW32NopAPI(PVDMFRAME pFrame);
+ ULONG FASTCALL WOW32LocalAPI(PVDMFRAME pFrame);
+ ULONG FASTCALL WK32WowPartyByNumber(PVDMFRAME pFrame);
+
+ #define LOCALAPI WOW32LocalAPI
+ #define NOPAPI WOW32NopAPI
+ #define UNIMPLEMENTEDAPI WOW32UnimplementedAPI
+ #define WK32WOWPARTYBYNUMBER WK32WowPartyByNumber
+#else
+ #define LOCALAPI WOW32UnimplementedAPI
+ #define NOPAPI WOW32UnimplementedAPI
+ #define UNIMPLEMENTEDAPI WOW32UnimplementedAPI
+ #define WK32WOWPARTYBYNUMBER UNIMPLEMENTEDAPI
+#endif
+
+
+#endif // ifndef _DEF_WOW32_ THIS SHOULD BE THE LAST LINE IN THIS FILE
diff --git a/private/mvdm/wow32/wow32.prf b/private/mvdm/wow32/wow32.prf
new file mode 100644
index 000000000..4ed3fdd8d
--- /dev/null
+++ b/private/mvdm/wow32/wow32.prf
@@ -0,0 +1,409 @@
+FastBopSetVDMStack@4
+BlockWOWIdle@4
+@WK32WowWaitForMsgAndEvent@4
+@GetPModeVDMPointerAssert@4
+CallBack16@16
+W32Win16WndProcEx@24
+@WU32PeekMessage@4
+FastWOWCallbackRet@0
+WOWBopEntry@0
+FastWOWCallbackCall@0
+WowFaxWndProc@16
+@WM32SetFocus@4
+@W32PatchCodeWithLpfnw32@8
+W32DllInitialize@12
+hConvert16to32@4
+@ThunkMsg16@4
+@WU32DefWindowProc@4
+@WU32GetKeyState@4
+@stackalloc16@4
+IsThunkWindowProc@8
+@ThunkWMMsg16@4
+strstr
+ThreadProcID32toPTD@8
+ThreadID32toHtask16@4
+@WG32PatBlt@4
+strchr
+ReleaseCachedDCs@20
+CacheReleasedDC@12
+@UnThunkWMMsg16@4
+DDEFindNode32@4
+GetExePtr16@4
+@WU32GetWindowLong@4
+getrect16@8
+@WU32RealizePalette@4
+FindPWC@4
+strncpy
+putrect16@8
+strrchr
+@WU32SendMessage@4
+_stricmp
+putwindowpos16@8
+strncmp
+memmove
+W32DDEFreeGlobalMem32@4
+@WU32SetScrollPos@4
+@WU32WaitMessage@4
+@WG32SelectObject@4
+getwindowpos16@8
+@WG32GetTextExtent@4
+@WU32DispatchMessage@4
+getmsg16@12
+@WM32WindowPosChanging@4
+GdiCleanCacheDC@4
+RealLockResource16@8
+FindPWW@8
+WOWGetVDMPointer@12
+AllocMapFileCache@0
+@WK32GetDriveType@4
+@WK32LoadLibraryEx32@4
+WOWHandle16@8
+GetCurrentDir@8
+VDDAssociateNtHandle@12
+@WM32ParentNotify@4
+@WK32SetCurrentDirectory@4
+RtlAnsiCharToUnicodeChar@4
+strcpyCDS@8
+@WK32GetProcAddress32@4
+GetCDSFromDrv@4
+RtlUpcaseUnicodeToMultiByteN@20
+WK32ICallProc32MakeCall@12
+FastBopVDMStack@0
+TruncatePath83@8
+SetEnvironmentVariableOem@8
+W32Thread@4
+@WK32FileRead@4
+@WU32GetWindowWord@4
+GetStdClassNumber@4
+toupper
+@WG32SetPixel@4
+WOWCallback16Ex@20
+@WK32FileOpen@4
+ResumeTimerThread@0
+@WG32SetBrushOrg@4
+@WU32SetWindowPos@4
+@WU32SetWindowLong@4
+@WG32SetBkColor@4
+@WG32ExtTextOut@4
+GetStdClassWndProc@4
+W32FreeResource@8
+@WU32GetDC@4
+IsDevice@4
+@WM32Activate@4
+@WG32GetMapMode@4
+W32LockResource@8
+WOWCallback16@8
+CopyBMI16ToBMI32@12
+VDDRetrieveNtHandle@16
+GetFullPathNameOem@16
+@WU32GlobalAddAtom@4
+@WG32CreateCompatibleDC@4
+@WU32LoadBitmap@4
+@WG32CreatePalette@4
+@WG32CreateDIBPatternBrush@4
+GetBMI32Size@8
+putpaletteentry16@12
+@WU32ReleaseDC@4
+StoreDC@12
+@malloc16@4
+@WG32DeleteObject@4
+@WU32DeleteMenu@4
+@WG32SetTextColor@4
+@WK32GetPrivateProfileInt@4
+W32DdeFreeHandle16@4
+@WS32RegOpenKey@4
+@WK32WOWInitTask@4
+W32MapViewOfFile@8
+@WU32NotifyWow@4
+@WG32SetMapMode@4
+@WK32ICallProc32@4
+@WK32FileGetDateTime@4
+@WG32CreateRectRgn@4
+VDDAllocateDosHandle@12
+FreeRes16@4
+@WG32GetDIBits@4
+GetStdClassThunkProc@4
+AddTaskSharedList@16
+@WU32LoadCursor@4
+@WU32RegisterClipboardFormat@4
+W32ReadWOWCompatFlags@8
+@WG32DPtoLP@4
+WOWRtlGetExpWinVer@4
+_strupr
+@WU32ChangeMenu@4
+UnlockResource16@4
+SetCursorIconFlag@8
+W32RefreshCurrentDirectories@4
+IsNamedPipeName@4
+SetCurrentDir@8
+IsVdmRedirLoaded@0
+@WU32SelectPalette@4
+@WG32GetSystemPaletteEntries@4
+FlushMapFileCaches@0
+DispatchInterrupts@0
+CopyBMIH16ToBMIH32@8
+@WG32SetWindowOrg@4
+AllocCursorIconAlias@0
+DosWowGetCurrentDirectory@8
+FindCursorIconAlias@8
+@WU32ValidateRect@4
+@WK32Yield@4
+@WKB32OemToAnsi@4
+@WU32InsertMenu@4
+@WG32UnrealizeObject@4
+@WU32GetMenuString@4
+CacheBlockAllocate@8
+W32CheckIfAlreadyLoaded@8
+@WK32FileClose@4
+ParseHotkeyReserved@4
+W32Create16BitCursorIcon@44
+NormalizeDosPath@12
+FindParamMap@12
+ConvertMenuItems16@16
+_strlwr
+@WU32GetWindowPlacement@4
+GetFileAttributesOem@4
+@WK32WowIsKnownDLL@4
+@WK32VirtualAlloc@4
+@WG32InvertRgn@4
+ParamMapUpdateNode@12
+DeleteParamMap@12
+GetParam16@4
+CheckForSameCurdir@4
+@WG32CreateIC@4
+CreateFileOem@28
+@WU32SignalProc@4
+@WU32GetCapture@4
+@WG32CreateCompatibleBitmap@4
+@WM32SetText@4
+@WK32GetProfileInt@4
+AddParamMap@8
+CacheBlockFree@8
+@WU32SetMenu@4
+ConvertMenu16@20
+@WKB32AnsiToOem@4
+GetCursorIconAlias32@8
+GetCursorIconAlias16@8
+IsCacheBlock@8
+ShowStartGlass@4
+W32FindResource@16
+W32GetExpWinVer@4
+FreeMapFileCache@4
+SetupCursorIconAlias@24
+@WS32RegQueryValue@4
+@WM32GetMinMaxInfo@4
+@WK32FileLSeek@4
+FindHtaskAlias@4
+@WU32GetUpdateRgn@4
+@WU32GetSystemMenu@4
+FindMapFileCache@4
+WOWGlobalUnlock16@4
+getpoint16@12
+@WU32SetScrollRange@4
+@WG32BitBlt@4
+@WG32CreateBrushIndirect@4
+@free16@4
+@WG32CreateRectRgnIndirect@4
+@WM32NCCalcSize@4
+LockWowSharedMemory@0
+@WU32SetMessageQueue@4
+LoadResource16@8
+@WU32GetClassInfo@4
+@WG32CreateSolidBrush@4
+@WU32AdjustWindowRect@4
+@WG32SetBkMode@4
+AddRes16@16
+@W32WowDdeFreeHandle@4
+@W32CreateWindow@4
+W32IsSetupProgram@8
+SetupResCursorIconAlias@20
+GetNextVDMCommand@4
+W32Create16BitCursorIconFrom32BitHandle@12
+GetClassCursorIconAlias32@4
+@WG32GetWindowOrg@4
+@malloc_w@4
+@WK32GetCurrentDirectory@4
+@WG32GetTextMetrics@4
+@WG32CreateBitmap@4
+@WK32WowGetNextVdmCommand@4
+@WU32FillRect@4
+@WU32RegisterClass@4
+@WK32FileLock@4
+@WG32GetDeviceCaps@4
+DDEFindNode16@4
+FindResource16@12
+@WG32SetBitmapBits@4
+FreeResource16@4
+@WG32LPtoDP@4
+putmsg16@8
+@WG32GetObject@4
+@WG32GetPixel@4
+@WU32CreateWindowEx@4
+@free_w@4
+puttextmetric16@8
+@WG32GetTextFace@4
+@WG32GetDCOrg@4
+@WG32CreatePatternBrush@4
+UnThunkWMGetMinMaxInfo16@8
+GetThunkWindowProc@16
+W32UnlockResource@8
+putlogfont16@12
+@WU32SetWindowText@4
+IsDebuggerAttached@0
+@WG32CombineRgn@4
+DosWowSetCurrentDirectory@4
+putstr16@12
+@WKB32VkKeyScan@4
+@WU32RegisterWindowMessage@4
+@WM32Create@4
+@WK32WowReserveHtask@4
+@WU32LoadMenu@4
+@WS32RegCloseKey@4
+ConvertToWin31Error@4
+@WG32SetROP2@4
+@WG32SelectClipRgn@4
+@WK32GetPrivateProfileString@4
+@WG32SetRectRgn@4
+getlogfont16@8
+putpoint16@12
+@WG32CreateDIBitmap@4
+@WK32WowFailedExec@4
+@WG32CreateFontIndirect@4
+@WU32CreateWindow@4
+ThunkWMGetMinMaxInfo16@8
+W32LoadResource@8
+GetBMI16Size@12
+UpdateDosCurrentDirectory@4
+@WK32FileGetAttributes@4
+host_CreateThread@24
+@WS32RegCreateKey@4
+@WK32WowGetModuleHandle@4
+@WU32InvalidateRect@4
+@WU32WOWGetIdFromDirectory@4
+GetDefaultDevMode32@4
+FindClass16@8
+@WK32WaitEvent@4
+@WK32GetProfileString@4
+LockResource16@4
+GetEnvironmentVariableOem@12
+WOWGlobalAllocLock16@12
+SetCurrentDirectoryOem@4
+@WG32IntersectClipRect@4
+@WU32UpdateWindow@4
+@WK32GlobalMemoryStatus@4
+SuspendTimerThread@0
+WOWYield16@0
+HMFFromWinMetaFile@8
+WinMetaFileFromHMF@8
+@WG32CloseMetaFile@4
+host_ExitThread@4
+@WG32SetWindowExt@4
+@WG32SaveDC@4
+@WG32RestoreDC@4
+@WG32Rectangle@4
+WK32DeleteTask@4
+@WG32Polygon@4
+@WG32GetRgnBox@4
+ModuleUnload@8
+@WG32CreatePen@4
+@WU32MoveWindow@4
+@WG32SetTextAlign@4
+@WG32CreateMetaFile@4
+WOWGlobalFree16@4
+WOWGlobalLock16@4
+WOWGlobalLockSize16@8
+W32EmptyClipboard@0
+getintarray16@12
+WOWHandle32@8
+W32UnhookHooks@8
+FreeCommSupportResources@4
+@WU32DestroyMenu@4
+W32DestroyTask@4
+@WMM32CallProc32@4
+@WU32PostQuitMessage@4
+W32CheckAndFreeDibInfo@4
+FreeTaskFormFeedHacks@4
+W32FreeTask@4
+@WM32Destroy@4
+ExitVDM@8
+WOWGlobalUnlockFree16@4
+@WU32DestroyWindow@4
+@WK32VirtualFree@4
+@WK32FreeLibrary32@4
+RemoveTaskSharedList@0
+@WK32KillTask@4
+W32FreeOwnedHooks@4
+InvalidateCursorIconAlias@4
+FreeCursorIconAlias@8
+RemoveHmodFromCache@4
+@WU32RemoveMenu@4
+@WG32DeleteDC@4
+DestroyTimers16@4
+FreeParamMap@4
+DestroyAccelAlias@4
+FreeCachedDCs@4
+DestroyRes16@4
+@WU32SetCursor@4
+@WG32ExcludeClipRect@4
+@WG32LineTo@4
+@WG32MoveTo@4
+DosWowSetDefaultDrive@4
+SafeLoadLibrary@4
+LoadLibraryAndGetProcAddresses@12
+@WK32SetDefaultDrive@4
+GetThreadIDHTASKALIAS@8
+@malloc_w_small@4
+AddHtaskAlias@4
+@WM32GetFont@4
+W32EnumFontHandler@8
+@WG32EnumFonts@4
+W32EnumFontFunc@16
+putnewtextmetric16@8
+putenumlogfont16@8
+@WG32GetStockObject@4
+@CreateSmallHeap@0
+InitStdCursorIconAlias@0
+RegisterWowBaseHandlers@4
+@W32GetTableOffsets@4
+@WK32GetShortPathName@4
+RegisterWowExec@4
+AddProcessSharedList@0
+@WK32RegisterShellWindowHandle@4
+@malloc_w_or_die@4
+LoadCriticalStringResources@0
+W32InitWOWSetupNames@0
+W32EWExecer@0
+SortedInsert@8
+getIntelRegistersPointer@0
+InitThunkTableOffsets@0
+CleanseSharedList@0
+@WK32DosWowInit@4
+InitVisRgn@0
+W32EWExecData@12
+UserRegisterWowHandlers@8
+W32InitHookState@4
+@WU32FinalUserInit@4
+W32Dispatch@0
+CacheBlockInit@8
+InitParamMap@0
+WowCreateSharedMemory@0
+InitCBFormats@0
+getMSW@0
+@realloc_w@12
+@WU32FindWindow@4
+DeleteFileOem@4
+@W32GetFlatAddressArray@4
+InitMapFileCache@0
+GetSupportedFaxDrivers@4
+WK32InitWowIsKnownDLL@4
+RegisterWOWIdle@0
+W32Init@0
+@W32GetFastCbRetAddress@4
+@WK32WOWNotifyWOW32@4
+WK32InitializeHungAppSupport@0
+@WK32DeviceIOCTL@4
+WOW32FaxHandler@8
+BuildStrList@8
+@WK32WowDelFile@4
+GdiQueryTable@0
+@W32GetFastAddress@4
diff --git a/private/mvdm/wow32/wow32.rc b/private/mvdm/wow32/wow32.rc
new file mode 100644
index 000000000..94ac697a0
--- /dev/null
+++ b/private/mvdm/wow32/wow32.rc
@@ -0,0 +1,26 @@
+//---------------------------------------------------------------------------
+// wow32.rc
+//
+// Copyright (c) Microsoft Corporation, 1990-
+//---------------------------------------------------------------------------
+
+#define WIN31 1
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "32-bit WOW Subsystem Library"
+#define VER_INTERNALNAME_STR "WOW32"
+#define VER_ORIGINALFILENAME_STR "WOW32.DLL"
+
+#include "common.ver"
+
+#include "isz.h"
+
+//----Strings----------------------------------------------------------------
+
+STRINGTABLE LOADONCALL MOVEABLE DISCARDABLE
+BEGIN
+#include "sz.src"
+END
diff --git a/private/mvdm/wow32/wow32.tt b/private/mvdm/wow32/wow32.tt
new file mode 100644
index 000000000..34d2b9660
--- /dev/null
+++ b/private/mvdm/wow32/wow32.tt
@@ -0,0 +1,125 @@
+$INPUT$win30api$END$
+$SELECT$$IFN:dll:$$END$
+$OUTPUT$$IFN:file:$t$DATA:file$.c$ELSE$t$DATA:dll$.c$ENDIF$$END$
+$HEADER
+
+$TEMPLATE
+
+
+ULONG W32$DATA:API$(VPVOID vpFrame)
+{
+$IFE:params:void
+$IFN:type:void$ ULONG ul;
+
+$ENDIF
+$ELSE
+$IFN:type:void$ ULONG ul = 0;
+$ENDIF
+$LOOP:paramdir
+$IFE:paramdir*:IN
+$IFE:params*:LPSTR
+ int cb$COUNT$; PSZ psz$COUNT$ = NULL;
+$ELSEIFIN:params*:LP:LPz
+ $DATA:params*$ t$COUNT$;
+$ENDIF
+$ELSEIFE:paramdir*:IN OUT
+$IFE:params*:LPSTR
+ int cb$COUNT$; PSZ psz$COUNT$ = NULL;
+$ELSEIFIN:params*:LP:LPz
+ $DATA:params*$ t$COUNT$;
+$ENDIF
+$ELSEIFE:paramdir*:DESTROY IN
+$IFE:params*:LPSTR
+ int cb$COUNT$; PSZ psz$COUNT$ = NULL;
+$ELSEIFIN:params*:LP:LPz
+ $DATA:params*$ t$COUNT$;
+$ENDIF
+$ELSEIFE:paramdir*:OUT
+$IFE:params*:LPSTR
+ PSZ psz$COUNT$ = NULL;
+$ELSEIFIN:params*:LP:LPz
+ $DATA:params*$ t$COUNT$;
+$ENDIF
+$ENDIF
+$ENDLOOP
+ register P$DATA:API$16 parg16;
+
+ GETARGPTR(vpFrame, sizeof($DATA:API$16), parg16);
+$LOOP:paramdir
+$IFE:params*:LPSTR
+$IFE:paramdir*:IN
+ GETPSZPTR(parg16->f$COUNT$, &cb$COUNT$, psz$COUNT$);
+$ELSEIFE:paramdir*:IN OUT
+ GETPSZPTR(parg16->f$COUNT$, &cb$COUNT$, psz$COUNT$);
+$ELSEIFE:paramdir*:DESTROY IN
+ GETPSZPTR(parg16->f$COUNT$, &cb$COUNT$, psz$COUNT$);
+$ELSEIFE:paramdir*:OUT
+ GETPSZPTR(parg16->f$COUNT$, cb$COUNT$, psz$COUNT$);
+$ENDIF
+$ELSEIFIN:params*:LP:LPz
+$IFE:paramdir*:IN
+ GET$DATA:params*$16(parg16->f$COUNT$, &t$COUNT$);
+$ELSEIFE:paramdir*:IN OUT
+ GET$DATA:params*$16(parg16->f$COUNT$, &t$COUNT$);
+$ELSEIFE:paramdir*:DESTROY IN
+ GET$DATA:params*$16(parg16->f$COUNT$, &t$COUNT$);
+$ENDIF
+$ENDIF
+$ENDLOOP
+
+$ENDIF
+$IFE:params:void
+ $IFN:type:void$ul = GET$DATA:type$16($ENDIF$$DATA:API$();
+$ELSE
+ $IFN:type:void$ul = GET$DATA:type$16($ENDIF$$DATA:API$($LOOP:params
+
+$IFE:params*:LPSTR
+ psz$COUNT
+$ELSEIFIN:params*:LP:LPz
+ &t$COUNT
+$ELSEIFOUT:params*:LP:LPz
+$IFN:params*:void
+ $DATA:params*$32(parg16->f$COUNT$)$ENDIF
+$ENDIF
+$ENDLOOP:,$
+ $IFN:type:void$)$ENDIF$);
+$ENDIF
+
+$IFN:params:void
+$LOOP:paramdir
+$IFE:params*:LPSTR
+$IFE:paramdir*:OUT
+ FLUSHPSZPTR(parg16->f$COUNT$, cb$COUNT$, psz$COUNT$);
+$ELSEIFE:paramdir*:IN OUT
+ FLUSHPSZPTR(parg16->f$COUNT$, cb$COUNT$, psz$COUNT$);
+$ENDIF
+$ELSEIFIN:params*:LP:LPz
+$IFE:paramdir*:OUT
+ PUT$DATA:params*$16(parg16->f$COUNT$, &t$COUNT$);
+$ELSEIFE:paramdir*:IN OUT
+ PUT$DATA:params*$16(parg16->f$COUNT$, &t$COUNT$);
+$ENDIF
+$ENDIF
+$ENDLOOP
+ Error:
+$LOOP:paramdir
+$IFE:paramdir*:IN
+$IFE:params*:LPSTR
+ FREEPSZPTR(psz$COUNT$);
+$ENDIF
+$ELSEIFE:paramdir*:IN OUT
+$IFE:params*:LPSTR
+ FREEPSZPTR(psz$COUNT$);
+$ENDIF
+$ELSEIFE:paramdir*:DESTROY IN
+$IFE:params*:LPSTR
+ FREEPSZPTR(psz$COUNT$);
+$ENDIF
+$ENDIF
+$ENDLOOP
+ FREEARGPTR(parg16);
+$ENDIF
+$IFN:type:void$ return ul;
+$ELSE$ return 0;
+$ENDIF
+}
diff --git a/private/mvdm/wow32/wow32fax.c b/private/mvdm/wow32/wow32fax.c
new file mode 100644
index 000000000..85e399cd8
--- /dev/null
+++ b/private/mvdm/wow32/wow32fax.c
@@ -0,0 +1,1063 @@
+//****************************************************************************
+// WOW32 fax support.
+//
+// History:
+// 02-jan-95 nandurir created.
+// 01-feb-95 reedb Clean-up, support printer install and bug fixes.
+//
+//****************************************************************************
+
+#include "precomp.h"
+#pragma hdrstop
+#define WOWFAX_INC_COMMON_CODE
+#include "wowgdip.h"
+#define DEFINE_DDRV_DEBUG_STRINGS
+#include "wowfax.h"
+#include "winddi.h"
+#include "winspool.h"
+
+MODNAME(wowfax.c);
+
+//****************************************************************************
+// globals -
+//
+//****************************************************************************
+
+DWORD DeviceCapsHandler(LPWOWFAXINFO lpfaxinfo);
+DWORD ExtDevModeHandler(LPWOWFAXINFO lpfaxinfo);
+BOOL ConvertDevMode(PDEVMODE16 lpdm16, LPDEVMODEW lpdmW, BOOL fTo16);
+BOOL ConvertGdiInfo(LPGDIINFO16 lpginfo16, PGDIINFO lpginfo, BOOL fTo16);
+
+extern HANDLE hmodWOW32;
+
+LPWOWFAXINFO glpfaxinfoCur = 0;
+WOWFAXINFO gfaxinfo;
+
+UINT uNumSupFaxDrv;
+LPSTR *SupFaxDrv;
+
+//****************************************************************************
+// SortedInsert - Alpha sort.
+//****************************************************************************
+
+VOID SortedInsert(LPSTR lpElement, LPSTR *alpList)
+{
+ LPSTR lpTmp, lpSwap;
+
+ while (*alpList) {
+ if (_stricmp(lpElement, *alpList) < 0) {
+ break;
+ }
+ alpList++;
+ }
+ lpTmp = *alpList;
+ *alpList++ = lpElement;
+ while (lpTmp) {
+ // SWAP(*alpList, lpTmp);
+ lpSwap = *alpList; *alpList = lpTmp; lpTmp = lpSwap;
+ alpList++;
+ }
+}
+
+//****************************************************************************
+// BuildStrList - Find the starting point of strings in a list (lpList) of
+// NULL terminated strings which is double NULL terminated.
+// If a non-NULL alpList parameter is passed, it will be
+// filled with an array of pointers to the starting point
+// of each string in the list. The number of strings in the
+// list is always returned.
+//****************************************************************************
+
+UINT BuildStrList(LPSTR lpList, LPSTR *alpList)
+{
+ LPSTR lp;
+ TCHAR cLastChar = 1;
+ UINT uCount = 0;
+
+ lp = lpList;
+ while ((cLastChar) || (*lp)) {
+ if ((*lp == 0) && (lp != lpList)) {
+ uCount++;
+ }
+
+ if ((lpList == lp) || (cLastChar == 0)) {
+ if ((*lp) && (alpList)) {
+ SortedInsert(lp, alpList);
+ }
+ }
+ cLastChar = *lp++;
+ }
+ return uCount;
+}
+
+//****************************************************************************
+// GetSupportedFaxDrivers - Read in the SupFaxDrv name list from the
+// registry. This list is used to determine if we will
+// install a 16-bit fax printer driver during
+// WriteProfileString and WritePrivateProfileString.
+//****************************************************************************
+
+LPSTR *GetSupportedFaxDrivers(UINT *uCount)
+{
+ HKEY hKey = 0;
+ DWORD dwType;
+ DWORD cbBufSize;
+ LPSTR lpSupFaxDrvBuf;
+ LPSTR *alpSupFaxDrvList;
+
+ *uCount = 0;
+
+ // Open the registry key.
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\WowFax\\SupportedFaxDrivers",
+ 0, KEY_READ, &hKey ) != ERROR_SUCCESS) {
+ goto GSFD_error;
+ }
+
+ // Query value for size of buffer and allocate.
+ if (RegQueryValueEx(hKey, "DriverNames", 0, &dwType, NULL, &cbBufSize) != ERROR_SUCCESS) {
+ goto GSFD_error;
+ }
+ if ((dwType != REG_MULTI_SZ) ||
+ ((lpSupFaxDrvBuf = (LPSTR) malloc_w(cbBufSize)) == NULL)) {
+ goto GSFD_error;
+ }
+
+ if (RegQueryValueEx(hKey, "DriverNames", 0, &dwType, lpSupFaxDrvBuf, &cbBufSize) != ERROR_SUCCESS) {
+ goto GSFD_error;
+ }
+
+ // Get the number of elements in the list
+ if (*uCount = BuildStrList(lpSupFaxDrvBuf, NULL)) {
+ // Build an array of pointers to the start of the strings in the list.
+ alpSupFaxDrvList = (LPSTR *) malloc_w(*uCount * sizeof(LPSTR));
+ RtlZeroMemory(alpSupFaxDrvList, *uCount * sizeof(LPSTR));
+ if (alpSupFaxDrvList) {
+ // Fill the array with string starting points.
+ BuildStrList(lpSupFaxDrvBuf, alpSupFaxDrvList);
+ }
+ }
+ goto GSFD_exit;
+
+GSFD_error:
+ LOGDEBUG(0,("WOW32!GetSupportedFaxDrivers failed!\n"));
+
+GSFD_exit:
+ if (hKey) {
+ RegCloseKey(hKey);
+ }
+ return alpSupFaxDrvList;
+}
+
+
+//****************************************************************************
+// WowFaxWndProc - This is the 32-bit WndProc which will SubClass the 16-bit
+// FaxWndProc in WOWEXEC.EXE. It's main function is to
+// convert 32-bit data passed from the WOW 32-bit generic
+// fax driver to 16-bit data to be used by the various 16-bit
+// fax printer drivers.
+//****************************************************************************
+
+LONG WowFaxWndProc(HWND hwnd, UINT uMsg, UINT uParam, LONG lParam)
+{
+ TCHAR lpPath[MAX_PATH];
+ HANDLE hMap;
+
+ if ((uMsg >= WM_DDRV_FIRST) && (uMsg <= WM_DDRV_LAST)) {
+ //
+ // WM_DDRV_* message: uParam = idMap
+ // lParam = unused.
+ //
+ // The corresponding data is obtained from the shared memory.
+ //
+
+ GetFaxDataMapName(uParam, lpPath);
+ hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, lpPath);
+ if (hMap) {
+ LPWOWFAXINFO lpT;
+ if (lpT = (LPWOWFAXINFO)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0)) {
+ WOW32FaxHandler(lpT->msg, (LPSTR)lpT);
+
+ // Set the status to TRUE indicating that the message
+ // has been 'processed' by WOW. This doesnot indicate
+ // the success or the failure of the actual processing
+ // of the message.
+
+ lpT->status = TRUE;
+ UnmapViewOfFile(lpT);
+ CloseHandle(hMap);
+ return(TRUE);
+ }
+ CloseHandle(hMap);
+ }
+ LOGDEBUG(0,("WowFaxWndProc failed to setup shared data mapping!\n"));
+ WOW32ASSERT(FALSE);
+ }
+ else {
+
+ // Not a WM_DDRV_* message. Pass it on to the original proc.
+
+ return CallWindowProc(gfaxinfo.proc16, hwnd, uMsg, uParam, lParam);
+ }
+ return(TRUE);
+}
+
+//**************************************************************************
+// WOW32FaxHandler -
+//
+// Handles various WowFax related operations.
+//
+//**************************************************************************
+
+ULONG WOW32FaxHandler(UINT iFun, LPSTR lpIn)
+{
+ LPWOWFAXINFO lpT = (LPWOWFAXINFO)lpIn;
+ LPWOWFAXINFO16 lpT16;
+ HWND hwnd = gfaxinfo.hwnd;
+ LPBYTE lpData;
+ VPVOID vp;
+
+#ifdef DEBUG
+ int DebugStringIndex = iFun - (WM_USER+0x100+1);
+
+ if ((DebugStringIndex >= WM_DDRV_FIRST) && (DebugStringIndex <= WM_DDRV_LAST) ) {
+ LOGDEBUG(0,("WOW32FaxHandler, %s, 0x%lX\n", (LPSTR)szWmDdrvDebugStrings[DebugStringIndex], (LPSTR) lpIn));
+ }
+#endif
+
+ switch (iFun) {
+ case WM_DDRV_SUBCLASS:
+ //
+ // Subclass the window - This is so that we get a chance to
+ // transform the 32bit data to 16bit data and vice versa. A
+ // NULL HWND, passed in lpIn, indicates don't subclass.
+ //
+
+ if (gfaxinfo.hwnd = (HWND)lpIn) {
+ gfaxinfo.proc16 = (WNDPROC)SetWindowLong((HWND)lpIn,
+ GWL_WNDPROC, (DWORD)WowFaxWndProc);
+ gfaxinfo.tid = GetWindowThreadProcessId((HWND)lpIn, NULL);
+ }
+
+ WOW32ASSERT(sizeof(DEVMODE16) + 4 == sizeof(DEVMODE31));
+
+ //
+ // Read in the SupFaxDrv name list from the registry.
+ //
+
+ SupFaxDrv = GetSupportedFaxDrivers(&uNumSupFaxDrv);
+
+ break;
+
+ case WM_DDRV_ENABLE:
+
+ // Enable the driver:
+ // . first intialize the 16bit faxinfo datastruct
+ // . then inform the driver (dll name) to be loaded
+ //
+ // format of ddrv_message:
+ // wParam = hdc (just a unique id)
+ // lparam = 16bit faxinfo struct with relevant data
+ // Must call 'callwindowproc' not 'sendmessage' because
+ // WowFaxWndProc is a subclass of the 16-bit FaxWndProc.
+ //
+
+ WOW32ASSERT(lpT->lpinfo16 == (LPSTR)NULL);
+ lpT->lpinfo16 = (LPSTR)CallWindowProc( gfaxinfo.proc16,
+ hwnd, WM_DDRV_INITFAXINFO16, lpT->hdc, (LPARAM)0);
+ if (lpT->lpinfo16) {
+ vp = malloc16(lpT->cData);
+ GETVDMPTR(vp, lpT->cData, lpData);
+ if (lpData == 0) {
+ break;
+ }
+
+ GETVDMPTR(lpT->lpinfo16, sizeof(WOWFAXINFO16), lpT16);
+ if (lpT16) {
+ if (lstrlenW(lpT->szDeviceName) < sizeof(lpT16->szDeviceName)) {
+ WideCharToMultiByte(CP_ACP, 0,
+ lpT->szDeviceName,
+ lstrlenW(lpT->szDeviceName) + 1,
+ lpT16->szDeviceName,
+ sizeof(lpT16->szDeviceName),
+ NULL, NULL);
+
+ lpT16->lpDriverName = lpT->lpDriverName;
+ if (lpT->lpDriverName) {
+ lpT16->lpDriverName = (LPBYTE)vp + (DWORD)lpT->lpDriverName;
+ WideCharToMultiByte(CP_ACP, 0,
+ (PWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName),
+ lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName)) + 1,
+ lpData + (DWORD)lpT->lpDriverName,
+ lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName)) + 1,
+ NULL, NULL);
+ }
+
+ lpT16->lpPortName = lpT->lpPortName;
+ if (lpT->lpPortName) {
+ lpT16->lpPortName = (LPBYTE)vp + (DWORD)lpT->lpPortName;
+ WideCharToMultiByte(CP_ACP, 0,
+ (PWSTR)((LPSTR)lpT + (DWORD)lpT->lpPortName),
+ lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpPortName)) + 1,
+ lpData + (DWORD)lpT->lpPortName,
+ lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpPortName)) + 1,
+ NULL, NULL);
+ }
+
+
+ lpT16->lpIn = lpT->lpIn;
+
+ if (lpT->lpIn) {
+ lpT16->lpIn = (LPBYTE)vp + (DWORD)lpT->lpIn;
+ ConvertDevMode((PDEVMODE16)(lpData + (DWORD)lpT->lpIn),
+ (LPDEVMODEW)((LPSTR)lpT + (DWORD)lpT->lpIn), TRUE);
+ }
+ WOW32ASSERT((sizeof(GDIINFO16) + sizeof(POINT16)) <= sizeof(GDIINFO));
+ lpT16->lpOut = (LPBYTE)vp + (DWORD)lpT->lpOut;
+ FREEVDMPTR(lpData);
+ FREEVDMPTR(lpT16);
+ lpT->retvalue = CallWindowProc( gfaxinfo.proc16,
+ hwnd, lpT->msg, lpT->hdc, (LPARAM)lpT->lpinfo16);
+ if (lpT->retvalue) {
+ GETVDMPTR(vp, lpT->cData, lpData);
+ ConvertGdiInfo((LPGDIINFO16)(lpData + (DWORD)lpT->lpOut),
+ (PGDIINFO)((LPSTR)lpT + (DWORD)lpT->lpOut), FALSE);
+
+ }
+ }
+ }
+ free16(vp);
+ }
+ break;
+
+ case WM_DDRV_ESCAPE:
+ GETVDMPTR(lpT->lpinfo16, sizeof(WOWFAXINFO16), lpT16);
+ if (lpT16) {
+ lpT16->wCmd = lpT->wCmd;
+ }
+ FREEVDMPTR(lpT16);
+ lpT->retvalue = CallWindowProc( gfaxinfo.proc16,
+ hwnd, lpT->msg, lpT->hdc, (LPARAM)lpT->lpinfo16);
+ break;
+
+ case WM_DDRV_PRINTPAGE:
+ //
+ // set the global variable. When the 16bit driver calls DMBitBlt we
+ // get the bitmap info from here. Since WOW is single threaded we
+ // won't receive another printpage msg before we return from here.
+ //
+ // All pointers in the faxinfo structure are actually
+ // 'offsets from the start of the mapfile' to relevant data.
+ //
+
+
+ glpfaxinfoCur = lpT;
+ lpT->lpbits = (LPBYTE)lpT + (DWORD)lpT->lpbits;
+
+ // fall through;
+
+ case WM_DDRV_STARTDOC:
+ case WM_DDRV_ENDDOC:
+ lpT->retvalue = CallWindowProc( gfaxinfo.proc16,
+ hwnd, lpT->msg, lpT->hdc, (LPARAM)lpT->lpinfo16);
+ break;
+
+ case WM_DDRV_DISABLE:
+ CallWindowProc( gfaxinfo.proc16,
+ hwnd, lpT->msg, lpT->hdc, (LPARAM)lpT->lpinfo16);
+ lpT->retvalue = TRUE;
+ break;
+
+
+ case WM_DDRV_EXTDMODE:
+ case WM_DDRV_DEVCAPS:
+ WOW32ASSERT(lpT->lpinfo16 == (LPSTR)NULL);
+ lpT->lpinfo16 = (LPSTR)CallWindowProc( gfaxinfo.proc16,
+ hwnd, WM_DDRV_INITFAXINFO16, lpT->hdc, (LPARAM)0);
+ if (lpT->lpinfo16) {
+ vp = malloc16(lpT->cData);
+ GETVDMPTR(vp, lpT->cData, lpData);
+ if (lpData == 0) {
+ break;
+ }
+ GETVDMPTR(lpT->lpinfo16, sizeof(WOWFAXINFO16), lpT16);
+ if (lpT16) {
+ if (lstrlenW(lpT->szDeviceName) < sizeof(lpT16->szDeviceName)) {
+ WideCharToMultiByte(CP_ACP, 0,
+ lpT->szDeviceName,
+ lstrlenW(lpT->szDeviceName) + 1,
+ lpT16->szDeviceName,
+ sizeof(lpT16->szDeviceName),
+ NULL, NULL);
+
+ lpT16->lpDriverName = lpT->lpDriverName;
+ if (lpT->lpDriverName) {
+ lpT16->lpDriverName = (LPBYTE)vp + (DWORD)lpT->lpDriverName;
+ WideCharToMultiByte(CP_ACP, 0,
+ (PWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName),
+ lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName)) + 1,
+ lpData + (DWORD)lpT->lpDriverName,
+ lstrlenW((LPWSTR)((LPSTR)lpT + (DWORD)lpT->lpDriverName)) + 1,
+ NULL, NULL);
+ }
+
+ FREEVDMPTR(lpData);
+ FREEVDMPTR(lpT16);
+ lpT->retvalue = CallWindowProc( gfaxinfo.proc16,
+ hwnd, WM_DDRV_LOAD, lpT->hdc, (LPARAM)lpT->lpinfo16);
+ if (lpT->retvalue) {
+ lpT->retvalue = (iFun == WM_DDRV_DEVCAPS) ? DeviceCapsHandler(lpT) :
+ ExtDevModeHandler(lpT) ;
+ }
+ CallWindowProc( gfaxinfo.proc16,
+ hwnd, WM_DDRV_UNLOAD, lpT->hdc, (LPARAM)lpT->lpinfo16);
+ }
+ }
+ free16(vp);
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+//**************************************************************************
+// gDC_CopySize -
+//
+// Indicates the size of a list item in bytes for use during
+// the DeviceCapsHandler thunk. A zero entry indicates that an
+// allocate and copy is not needed for the query.
+//
+//**************************************************************************
+
+BYTE gDC_ListItemSize[DC_COPIES + 1] = {
+ 0,
+ 0, // DC_FIELDS 1
+ sizeof(WORD), // DC_PAPERS 2
+ sizeof(POINT), // DC_PAPERSIZE 3
+ sizeof(POINT), // DC_MINEXTENT 4
+ sizeof(POINT), // DC_MAXEXTENT 5
+ sizeof(WORD), // DC_BINS 6
+ 0, // DC_DUPLEX 7
+ 0, // DC_SIZE 8
+ 0, // DC_EXTRA 9
+ 0, // DC_VERSION 10
+ 0, // DC_DRIVER 11
+ 24, // DC_BINNAMES 12 //ANSI
+ sizeof(LONG) * 2, // DC_ENUMRESOLUTIONS 13
+ 64, // DC_FILEDEPENDENCIES 14 //ANSI
+ 0, // DC_TRUETYPE 15
+ 64, // DC_PAPERNAMES 16 //ANSI
+ 0, // DC_ORIENTATION 17
+ 0 // DC_COPIES 18
+};
+
+//**************************************************************************
+// DeviceCapsHandler -
+//
+// Makes a single call down to the 16-bit printer driver for queries
+// which don't need to allocate and copy. For queries which do, two
+// calls to the 16-bit printer driver are made. One to get the number
+// of items, and a second to get the actual data.
+//
+//**************************************************************************
+
+DWORD DeviceCapsHandler(LPWOWFAXINFO lpfaxinfo)
+{
+ LPWOWFAXINFO16 lpWFI16;
+ LPSTR lpSrc;
+ LPBYTE lpDest;
+ INT i;
+ DWORD cbData16; // Size of data items.
+ UINT cbUni;
+
+ LOGDEBUG(0,("DeviceCapsHandler, lpfaxinfo: %X, wCmd: %X\n", lpfaxinfo, lpfaxinfo->wCmd));
+
+ GETVDMPTR(lpfaxinfo->lpinfo16, sizeof(WOWFAXINFO16), lpWFI16);
+
+ // Get the number of data items with a call to the 16-bit printer driver.
+
+ lpWFI16->lpDriverName = 0;
+ lpWFI16->lpPortName = 0;
+ lpWFI16->wCmd = lpfaxinfo->wCmd;
+ lpWFI16->cData = 0;
+ lpWFI16->lpOut = 0;
+ lpfaxinfo->cData = 0;
+
+ lpfaxinfo->retvalue = CallWindowProc(gfaxinfo.proc16, gfaxinfo.hwnd,
+ lpfaxinfo->msg, lpfaxinfo->hdc,
+ (LPARAM)lpfaxinfo->lpinfo16);
+
+ cbData16 = gDC_ListItemSize[lpfaxinfo->wCmd];
+ if (lpfaxinfo->lpOut && cbData16 && lpfaxinfo->retvalue) {
+
+ // We need to allocate and copy for this query
+ lpWFI16->cData = cbData16 * lpfaxinfo->retvalue;
+
+ // assert the size of output buffer - and set it the actual data size
+ switch (lpfaxinfo->wCmd) {
+ case DC_BINNAMES:
+ case DC_PAPERNAMES:
+ // These fields need extra room for ANSI to UNICODE conversion.
+ WOW32ASSERT((lpfaxinfo->cData - (DWORD)lpfaxinfo->lpOut) >= lpWFI16->cData * sizeof(WCHAR));
+ lpfaxinfo->cData = lpWFI16->cData * sizeof(WCHAR);
+ break;
+ default:
+ WOW32ASSERT((lpfaxinfo->cData - (DWORD)lpfaxinfo->lpOut) >= lpWFI16->cData);
+ lpfaxinfo->cData = lpWFI16->cData;
+ break;
+ }
+
+ if ((lpWFI16->lpOut = (LPSTR)malloc16(lpWFI16->cData)) == NULL) {
+ lpfaxinfo->retvalue = 0;
+ goto LeaveDeviceCapsHandler;
+ }
+
+ // Get the list data with a call to the 16-bit printer driver.
+ lpfaxinfo->retvalue = CallWindowProc(gfaxinfo.proc16, gfaxinfo.hwnd,
+ lpfaxinfo->msg, lpfaxinfo->hdc,
+ (LPARAM)lpfaxinfo->lpinfo16);
+
+ GETVDMPTR(lpWFI16->lpOut, 0, lpSrc);
+ lpDest = (LPBYTE)lpfaxinfo + (DWORD)lpfaxinfo->lpOut;
+
+ switch (lpfaxinfo->wCmd) {
+ case DC_BINNAMES:
+ case DC_PAPERNAMES:
+ for (i = 0; i < (INT)lpfaxinfo->retvalue; i++) {
+ RtlMultiByteToUnicodeN((LPWSTR)lpDest,
+ cbData16 * sizeof(WCHAR),
+ (PULONG)&cbUni,
+ (LPBYTE)lpSrc, cbData16);
+ lpDest += cbData16 * sizeof(WCHAR);
+ lpSrc += cbData16;
+ }
+ break;
+
+ default:
+ RtlCopyMemory(lpDest, lpSrc, lpWFI16->cData);
+ break;
+ }
+ free16((VPVOID)lpWFI16->lpOut);
+ FREEVDMPTR(lpSrc);
+ }
+
+LeaveDeviceCapsHandler:
+ FREEVDMPTR(lpWFI16);
+ return lpfaxinfo->retvalue;
+}
+
+//**************************************************************************
+// ExtDevModeHandler
+//
+//**************************************************************************
+
+DWORD ExtDevModeHandler(LPWOWFAXINFO lpfaxinfo)
+{
+ LPWOWFAXINFO16 lpT16;
+ LPSTR lpT;
+ VPVOID vp;
+
+ LOGDEBUG(0,("ExtDevModeHandler\n"));
+
+ (LONG)lpfaxinfo->retvalue = -1;
+
+ GETVDMPTR(lpfaxinfo->lpinfo16, sizeof(WOWFAXINFO16), lpT16);
+
+ if (lpT16) {
+
+ // assumption that 16bit data won't be larger than 32bit data.
+ // this makes life easy in two ways; first we don't need to calculate
+ // the exact size and secondly the 16bit pointers can be set to same
+ // relative offsets as input(32 bit) pointers
+
+ vp = malloc16(lpfaxinfo->cData);
+ if (vp) {
+ GETVDMPTR(vp, lpfaxinfo->cData, lpT);
+ if (lpT) {
+ lpT16->wCmd = lpfaxinfo->wCmd;
+ lpT16->lpOut = (LPSTR)lpfaxinfo->lpOut;
+ lpT16->lpIn = (LPSTR)lpfaxinfo->lpIn;
+ lpT16->lpDriverName = (LPBYTE)vp + (DWORD)lpfaxinfo->lpDriverName;
+ lpT16->lpPortName = (LPBYTE)vp + (DWORD)lpfaxinfo->lpPortName;
+ WideCharToMultiByte(CP_ACP, 0,
+ (PWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpDriverName),
+ lstrlenW((LPWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpDriverName)) + 1,
+ lpT + (DWORD)lpfaxinfo->lpDriverName,
+ lstrlenW((LPWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpDriverName)) + 1,
+ NULL, NULL);
+ WideCharToMultiByte(CP_ACP, 0,
+ (PWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpPortName),
+ lstrlenW((LPWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpPortName)) + 1,
+ lpT + (DWORD)lpfaxinfo->lpPortName,
+ lstrlenW((LPWSTR)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpPortName)) + 1,
+ NULL, NULL);
+ if (lpfaxinfo->lpIn) {
+ lpT16->lpIn = (LPBYTE)vp + (DWORD)lpfaxinfo->lpIn;
+ ConvertDevMode((PDEVMODE16)(lpT + (DWORD)lpfaxinfo->lpIn),
+ (LPDEVMODEW)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpIn), TRUE);
+ }
+
+ if (lpfaxinfo->lpOut) {
+ lpT16->lpOut = (LPBYTE)vp + (DWORD)lpfaxinfo->lpOut;
+ }
+
+ lpT16->hwndui = GETHWND16(lpfaxinfo->hwndui);
+
+ FREEVDMPTR(lpT);
+ lpfaxinfo->retvalue = CallWindowProc( gfaxinfo.proc16, gfaxinfo.hwnd,
+ lpfaxinfo->msg, lpfaxinfo->hdc, (LPARAM)lpfaxinfo->lpinfo16);
+
+ if ((lpfaxinfo->wCmd == 0) && (lpfaxinfo->retvalue > 0)) {
+ // the 16bit driver has returned 16bit struct size. change
+ // the return value to correspond to the devmodew struct.
+ //
+ // since devmode16 (the 3.0 version) is smaller than devmode31
+ // the retvalue will take careof both win30/win31 devmode
+
+ WOW32ASSERT(sizeof(DEVMODE16) < sizeof(DEVMODE31));
+ lpfaxinfo->retvalue += (sizeof(DEVMODEW) - sizeof(DEVMODE16));
+ }
+
+ GETVDMPTR(vp, lpfaxinfo->cData, lpT);
+
+ if ((lpfaxinfo->wCmd & DM_COPY) &&
+ lpfaxinfo->lpOut && (lpfaxinfo->retvalue == IDOK)) {
+ ConvertDevMode((PDEVMODE16)(lpT + (DWORD)lpfaxinfo->lpOut),
+ (LPDEVMODEW)((LPSTR)lpfaxinfo + (DWORD)lpfaxinfo->lpOut), FALSE);
+ }
+
+ }
+ free16(vp);
+ }
+
+ }
+
+ FREEVDMPTR(lpT16);
+
+ return lpfaxinfo->retvalue;
+}
+
+//***************************************************************************
+// ConvertDevMode
+//***************************************************************************
+
+BOOL ConvertDevMode(PDEVMODE16 lpdm16, LPDEVMODEW lpdmW, BOOL fTo16)
+{
+ LOGDEBUG(0,("ConvertDevMode\n"));
+
+ if (!lpdm16 || !lpdmW)
+ return TRUE;
+
+ if (fTo16) {
+ RtlZeroMemory(lpdm16, sizeof(DEVMODE16));
+
+ WideCharToMultiByte(CP_ACP, 0,
+ lpdmW->dmDeviceName,
+ sizeof(lpdmW->dmDeviceName) / sizeof(lpdmW->dmDeviceName[0]),
+ lpdm16->dmDeviceName,
+ sizeof(lpdm16->dmDeviceName) / sizeof(lpdm16->dmDeviceName[0]),
+ NULL, NULL);
+
+ lpdm16->dmSpecVersion = lpdmW->dmSpecVersion;
+ lpdm16->dmDriverVersion = lpdmW->dmDriverVersion;
+ lpdm16->dmSize = lpdmW->dmSize;
+ lpdm16->dmDriverExtra = lpdmW->dmDriverExtra;
+ lpdm16->dmFields = lpdmW->dmFields;
+ lpdm16->dmOrientation = lpdmW->dmOrientation;
+ lpdm16->dmPaperSize = lpdmW->dmPaperSize;
+ lpdm16->dmPaperLength = lpdmW->dmPaperLength;
+ lpdm16->dmPaperWidth = lpdmW->dmPaperWidth;
+ lpdm16->dmScale = lpdmW->dmScale;
+ lpdm16->dmCopies = lpdmW->dmCopies;
+ lpdm16->dmDefaultSource = lpdmW->dmDefaultSource;
+ lpdm16->dmPrintQuality = lpdmW->dmPrintQuality;
+ lpdm16->dmColor = lpdmW->dmColor;
+ lpdm16->dmDuplex = lpdmW->dmDuplex;
+
+ // adjust lpdm16->dmSize (between win30 and win31 version)
+
+ lpdm16->dmSize = (lpdm16->dmSpecVersion > 0x300) ? sizeof(DEVMODE31) :
+ sizeof(DEVMODE16);
+ if (lpdm16->dmSize >= sizeof(DEVMODE31)) {
+ ((PDEVMODE31)lpdm16)->dmYResolution = lpdmW->dmYResolution;
+ ((PDEVMODE31)lpdm16)->dmTTOption = lpdmW->dmTTOption;
+ }
+
+ RtlCopyMemory((LPBYTE)lpdm16 + (DWORD)lpdm16->dmSize, (lpdmW + 1),
+ lpdmW->dmDriverExtra);
+ }
+ else {
+
+ // LATER: should specversion be NT version rather than win30 driver version?
+
+ MultiByteToWideChar(CP_ACP, 0,
+ lpdm16->dmDeviceName,
+ sizeof(lpdm16->dmDeviceName) / sizeof(lpdm16->dmDeviceName[0]),
+ lpdmW->dmDeviceName,
+ sizeof(lpdmW->dmDeviceName) / sizeof(lpdmW->dmDeviceName[0]));
+
+ lpdmW->dmSpecVersion = lpdm16->dmSpecVersion;
+ lpdmW->dmDriverVersion = lpdm16->dmDriverVersion;
+ lpdmW->dmSize = lpdm16->dmSize;
+ lpdmW->dmDriverExtra = lpdm16->dmDriverExtra;
+ lpdmW->dmFields = lpdm16->dmFields;
+ lpdmW->dmOrientation = lpdm16->dmOrientation;
+ lpdmW->dmPaperSize = lpdm16->dmPaperSize;
+ lpdmW->dmPaperLength = lpdm16->dmPaperLength;
+ lpdmW->dmPaperWidth = lpdm16->dmPaperWidth;
+ lpdmW->dmScale = lpdm16->dmScale;
+ lpdmW->dmCopies = lpdm16->dmCopies;
+ lpdmW->dmDefaultSource = lpdm16->dmDefaultSource;
+ lpdmW->dmPrintQuality = lpdm16->dmPrintQuality;
+ lpdmW->dmColor = lpdm16->dmColor;
+ lpdmW->dmDuplex = lpdm16->dmDuplex;
+
+ if (lpdm16->dmSize >= sizeof(DEVMODE31)) {
+ lpdmW->dmYResolution = ((PDEVMODE31)lpdm16)->dmYResolution;
+ lpdmW->dmTTOption = ((PDEVMODE31)lpdm16)->dmTTOption;
+ }
+
+ // 16bit world doesnot know anything about the fields like
+ // formname etc.
+
+ RtlCopyMemory(lpdmW + 1, (LPBYTE)lpdm16 + lpdm16->dmSize, lpdm16->dmDriverExtra);
+
+ // adjust size for 32bit world
+
+ lpdmW->dmSize = sizeof(*lpdmW);
+
+ }
+
+ return TRUE;
+}
+
+//**************************************************************************
+// ConvertGdiInfo
+//
+//**************************************************************************
+
+
+BOOL ConvertGdiInfo(LPGDIINFO16 lpginfo16, PGDIINFO lpginfo, BOOL fTo16)
+{
+ LOGDEBUG(0,("ConvertGdiInfo\n"));
+
+ if (!lpginfo16 || !lpginfo)
+ return FALSE;
+
+ if (!fTo16) {
+ lpginfo->ulTechnology = lpginfo16->dpTechnology;
+ lpginfo->ulLogPixelsX = lpginfo16->dpLogPixelsX;
+ lpginfo->ulLogPixelsY = lpginfo16->dpLogPixelsY;
+ lpginfo->ulDevicePelsDPI = lpginfo->ulLogPixelsX;
+ lpginfo->ulHorzSize = lpginfo16->dpHorzSize;
+ lpginfo->ulVertSize = lpginfo16->dpVertSize;
+ lpginfo->ulHorzRes = lpginfo16->dpHorzRes;
+ lpginfo->ulVertRes = lpginfo16->dpVertRes;
+ lpginfo->cBitsPixel = lpginfo16->dpBitsPixel;
+ lpginfo->cPlanes = lpginfo16->dpPlanes;
+ lpginfo->ulNumColors = lpginfo16->dpNumColors;
+ lpginfo->ptlPhysOffset.x = ((PPOINT16)(lpginfo16+1))->x;
+ lpginfo->ptlPhysOffset.y = ((PPOINT16)(lpginfo16+1))->y;
+ lpginfo->szlPhysSize.cx = lpginfo->ulHorzRes;
+ lpginfo->szlPhysSize.cy = lpginfo->ulVertRes;
+ lpginfo->ulPanningHorzRes = lpginfo->ulHorzRes;
+ lpginfo->ulPanningVertRes = lpginfo->ulVertRes;
+ lpginfo->ulAspectX = lpginfo16->dpAspectX;
+ lpginfo->ulAspectY = lpginfo16->dpAspectY;
+ lpginfo->ulAspectXY = lpginfo16->dpAspectXY;
+
+ //
+ // RASDD tries to be smart as to whether the x and y DPI are equal or
+ // not. In the case of 200dpi in the x direction and 100dpi in the
+ // y direction, you may want to adjust this to 2 for xStyleStep, 1 for
+ // yStyleStep and dpi/50 for denStyleStep. This basicaly determines
+ // how long dashes/dots will be when drawing with styled pens.
+ // Since we just hard code denStyleStep to 3, we get different lines
+ // at 100dpi vs 200dpi
+ //
+
+ lpginfo->xStyleStep = 1;
+ lpginfo->yStyleStep = 1;
+ lpginfo->denStyleStep = 3;
+ }
+
+ return TRUE;
+}
+
+
+//**************************************************************************
+// DMBitBlt -
+// The 16bit winfax.drv calls this , in response to a device driver
+// 'bitblt' call.
+//
+//**************************************************************************
+
+ULONG FASTCALL WG32DMBitBlt( PVDMFRAME pFrame)
+{
+ register PDMBITBLT16 parg16;
+ register PBITMAP16 pbm16;
+ LPBYTE lpDest, lpSrc;
+ UINT cBytes;
+ LPBYTE lpbits, lpbitsEnd;
+
+ LOGDEBUG(0,("WG32DMBitBlt\n"));
+
+ GETARGPTR(pFrame, sizeof(DMBITBLT16), parg16);
+ GETVDMPTR(parg16->pbitmapdest, sizeof(BITMAP16), pbm16);
+ GETVDMPTR(pbm16->bmBits, 0, lpDest);
+
+ WOW32ASSERT(glpfaxinfoCur != NULL);
+ lpbits = glpfaxinfoCur->lpbits;
+ lpbitsEnd = (LPBYTE)lpbits + glpfaxinfoCur->bmHeight *
+ glpfaxinfoCur->bmWidthBytes;
+
+ lpDest = lpDest + parg16->destx + parg16->desty * pbm16->bmWidthBytes;
+ lpSrc = (LPBYTE)lpbits + (parg16->srcx / glpfaxinfoCur->bmPixPerByte) +
+ parg16->srcy * glpfaxinfoCur->bmWidthBytes;
+ if (lpSrc >= lpbits) {
+ if ((DWORD)glpfaxinfoCur->bmWidthBytes == (DWORD)pbm16->bmWidthBytes) {
+ cBytes = parg16->exty * glpfaxinfoCur->bmWidthBytes;
+ if (cBytes > (UINT)(pbm16->bmHeight * pbm16->bmWidthBytes)) {
+ cBytes = pbm16->bmHeight * pbm16->bmWidthBytes;
+ WOW32ASSERT(FALSE);
+ }
+ if ((lpSrc + cBytes) <= lpbitsEnd) {
+ RtlCopyMemory(lpDest, lpSrc, cBytes);
+ }
+ }
+ else if ((DWORD)glpfaxinfoCur->bmWidthBytes > (DWORD)pbm16->bmWidthBytes) {
+ int i;
+
+ // we need to transfer bits one partial scanline at a time
+ WOW32ASSERT((DWORD)pbm16->bmHeight <= (DWORD)glpfaxinfoCur->bmHeight);
+ WOW32ASSERT((DWORD)parg16->exty <= (DWORD)pbm16->bmHeight);
+
+ for (i = 0; i < parg16->exty; i++) {
+ if ((lpSrc + pbm16->bmWidthBytes) <= lpbitsEnd) {
+ RtlCopyMemory(lpDest, lpSrc, pbm16->bmWidthBytes);
+ }
+ lpDest += pbm16->bmWidthBytes;
+ lpSrc += glpfaxinfoCur->bmWidthBytes;
+ }
+
+ }
+ else {
+ WOW32ASSERT(FALSE);
+ }
+
+
+ }
+ return (ULONG)TRUE;
+}
+
+PSZ StrDup(PSZ szStr)
+{
+ PSZ pszTmp;
+
+ pszTmp = malloc_w(strlen(szStr)+1);
+ return(strcpy(pszTmp, szStr));
+}
+
+PSZ BuildPath(PSZ szPath, PSZ szFileName)
+{
+ char szTmp[MAX_PATH];
+
+ strcpy(szTmp, szPath);
+ strcat(szTmp, "\\");
+ strcat(szTmp, szFileName);
+ return(StrDup(szTmp));
+}
+
+BOOL InstallWowFaxPrinter(PSZ szSection, PSZ szKey, PSZ szString)
+{
+ CHAR szTmp[MAX_PATH];
+ PSZ szSrcPath;
+ DWORD dwNeeded;
+ DRIVER_INFO_2 DriverInfo;
+ PRINTER_INFO_2 PrinterInfo;
+ PORT_INFO_1 PortInfo;
+ HKEY hKey = 0, hSubKey = 0;
+ BOOL bRetVal;
+
+ LOGDEBUG(0,("InstallWowFaxPrinter, Section = %s, Key = %s, String = %s\n", szSection, szKey, szString));
+
+ // Write the entry to the registry. We'll keep shadow entries
+ // in the registry for the WOW fax applications and drivers to
+ // read, since the entries that the spooler writes pertain
+ // to winspool, not the 16-bit fax driver.
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\WowFax",
+ 0, KEY_WRITE, &hKey ) == ERROR_SUCCESS) {
+ if (RegCreateKey(hKey, szSection, &hSubKey) == ERROR_SUCCESS) {
+ RegSetValueEx(hSubKey, szKey, 0, REG_SZ, szString, strlen(szString)+1);
+ RegCloseKey(hKey);
+ RegCloseKey(hSubKey);
+
+ // Dynamically link to spooler API's
+ if (!(*spoolerapis[WOW_GetPrinterDriverDirectory].lpfn)) {
+ if (!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
+ LOGDEBUG(0,("InstallWowFaxPrinter, Unable to load WINSPOOL API's\n"));
+ return(FALSE);
+ }
+ }
+
+ // Copy the printer driver files.
+ RtlZeroMemory(&DriverInfo, sizeof(DRIVER_INFO_2));
+ RtlZeroMemory(&PrinterInfo, sizeof(PRINTER_INFO_2));
+ if (!(*spoolerapis[WOW_GetPrinterDriverDirectory].lpfn)(NULL, NULL, 1, szTmp, MAX_PATH, &dwNeeded)) {
+ LOGDEBUG(0,("InstallWowFaxPrinter, GetPrinterDriverDirectory failed: 0x%X\n", GetLastError()));
+ return(FALSE);
+ }
+
+ // This is a dummy. We've no data file, but spooler won't take NULL.
+ DriverInfo.pDataFile = BuildPath(szTmp, WOWFAX_DLL_NAME_A);
+
+ DriverInfo.pDriverPath = BuildPath(szTmp, WOWFAX_DLL_NAME_A);
+ LOGDEBUG(0,("InstallWowFaxPrinter, pDriverPath = %s\n", DriverInfo.pDataFile));
+ szSrcPath = BuildPath(pszSystemDirectory, WOWFAX_DLL_NAME_A);
+ CopyFile(szSrcPath, DriverInfo.pDriverPath, FALSE);
+ free_w(szSrcPath);
+
+ DriverInfo.pConfigFile = BuildPath(szTmp, WOWFAXUI_DLL_NAME_A);
+ szSrcPath = BuildPath(pszSystemDirectory, WOWFAXUI_DLL_NAME_A);
+ CopyFile(szSrcPath, DriverInfo.pConfigFile, FALSE);
+ free_w(szSrcPath);
+
+ // Install the printer driver.
+ DriverInfo.cVersion = 1;
+ DriverInfo.pName = "Windows 3.1 Compatible Fax Driver";
+ if ((*spoolerapis[WOW_AddPrinterDriver].lpfn)(NULL, 2, &DriverInfo) == FALSE) {
+ bRetVal = (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
+ }
+
+ if (bRetVal) {
+ // Parse out the printer name.
+ RtlZeroMemory(&PrinterInfo, sizeof(PRINTER_INFO_2));
+ PrinterInfo.pPrinterName = szKey;
+
+ LOGDEBUG(0,("InstallWowFaxPrinter, pPrinterName = %s\n", PrinterInfo.pPrinterName));
+
+ // Use private API to add a NULL port. Printer guys need to fix
+ // redirection to NULL bug.
+ RtlZeroMemory(&PortInfo, sizeof(PORT_INFO_1));
+ PrinterInfo.pPortName = "NULL";
+ PortInfo.pName = PrinterInfo.pPortName;
+
+ // Get "Local Port" string.
+ LoadString(hmodWOW32, iszWowFaxLocalPort, szTmp, sizeof szTmp);
+
+ (*spoolerapis[WOW_AddPortEx].lpfn)(NULL, 1, &PortInfo, szTmp);
+
+ // Set the other defaults and install the printer.
+ PrinterInfo.pDriverName = "Windows 3.1 Compatible Fax Driver";
+ PrinterInfo.pPrintProcessor = "WINPRINT";
+ PrinterInfo.pDatatype = "RAW";
+ if ((*spoolerapis[WOW_AddPrinter].lpfn)(NULL, 2, &PrinterInfo) == 0) {
+ bRetVal = (GetLastError() == ERROR_PRINTER_ALREADY_EXISTS);
+ }
+#ifdef DBG
+ if (!bRetVal) {
+ LOGDEBUG(0,("InstallWowFaxPrinter, AddPrinter failed: 0x%X\n", GetLastError()));
+ }
+#endif
+ }
+ else {
+ LOGDEBUG(0,("InstallWowFaxPrinter, AddPrinterDriver failed: 0x%X\n", GetLastError()));
+ }
+ free_w(DriverInfo.pDataFile);
+ free_w(DriverInfo.pDriverPath);
+ free_w(DriverInfo.pConfigFile);
+
+ return(bRetVal);
+ }
+ else {
+ LOGDEBUG(0,("InstallWowFaxPrinter, Unable to create Key: %s\n", szSection));
+ }
+ }
+ else {
+ LOGDEBUG(0,("InstallWowFaxPrinter, Unable to open key: HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\WowFax\n"));
+ }
+
+ if (hKey) {
+ RegCloseKey(hKey);
+ if (hSubKey) {
+ RegCloseKey(hSubKey);
+ }
+ }
+ return(FALSE);
+}
+
+BOOL IsFaxPrinterWriteProfileString(PSZ szSection, PSZ szKey, PSZ szString)
+{
+ BOOL Result;
+
+ // Don't install if trying to clear an entry.
+ if (*szString == '\0') {
+ Result = FALSE;
+ goto Done;
+ }
+
+ // Trying to install a fax printer?
+ LOGDEBUG(0,("IsFaxPrinterWriteProfileString, Section = devices, Key = %s\n", szKey));
+
+ // Is it one of the fax drivers we recognize?
+ if (IsFaxPrinterSupportedDevice(szKey)) {
+ if (!InstallWowFaxPrinter(szSection, szKey, szString)) {
+ WOW32ASSERTMSG(FALSE, "Install of generic fax printer failed.\n");
+ }
+ Result = TRUE;
+ } else {
+ Result = FALSE;
+ }
+
+Done:
+ return Result;
+}
+
+BOOL IsFaxPrinterSupportedDevice(PSZ pszDevice)
+{
+ UINT i, iNotFound;
+
+ // Trying to read from a fax printer entry?
+ LOGDEBUG(0,("IsFaxPrinterSupportedDevice, Device = %s\n", pszDevice));
+
+ // Is it one of the fax drivers we recognize?
+ for (i = 0; i < uNumSupFaxDrv; i++) {
+ iNotFound = _stricmp(pszDevice, SupFaxDrv[i]);
+ if (iNotFound > 0) continue;
+ if (iNotFound == 0) {
+ LOGDEBUG(0,("IsFaxPrinterSupportedDevice returns TRUE\n"));
+ return(TRUE);
+ }
+ else {
+ break;
+ }
+ }
+ return(FALSE);
+}
+
+DWORD GetFaxPrinterProfileString(PSZ szSection, PSZ szKey, PSZ szDefault, PSZ szRetBuf, DWORD cbBufSize)
+{
+ char szTmp[MAX_PATH];
+ HKEY hKey = 0;
+ DWORD dwType;
+
+ // Read the entry from the shadow entries in registry.
+ strcpy(szTmp, "Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\WowFax\\");
+ strcat(szTmp, szSection);
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szTmp, 0, KEY_READ, &hKey ) == ERROR_SUCCESS) {
+ if (RegQueryValueEx(hKey, szKey, 0, &dwType, szRetBuf, &cbBufSize) == ERROR_SUCCESS) {
+ RegCloseKey(hKey);
+ return(cbBufSize);
+ }
+ }
+
+ if (hKey) {
+ RegCloseKey(hKey);
+ }
+ WOW32ASSERTMSGF(FALSE, ("GetFaxPrinterProfileString Failed. Section = %s, Key = %s\n", szSection, szKey));
+ strcpy(szRetBuf, szDefault);
+ return(strlen(szDefault));
+}
diff --git a/private/mvdm/wow32/wowdde.h b/private/mvdm/wow32/wowdde.h
new file mode 100644
index 000000000..14b8a8341
--- /dev/null
+++ b/private/mvdm/wow32/wowdde.h
@@ -0,0 +1,20 @@
+/*----------------------------------------------------------------------------
+| DDEDATA structure
+|
+| WM_DDE_DATA parameter structure for hData (LOWORD(lParam)).
+| The actual size of this structure depends on the size of
+| the Value array.
+|
+----------------------------------------------------------------------------*/
+
+typedef struct {
+ unsigned short wStatus;
+ short cfFormat;
+ HAND16 Value;
+} DDEDATA16;
+
+typedef struct {
+ unsigned short wStatus;
+ short cfFormat;
+ HANDLE Value;
+} DDEDATA32;
diff --git a/private/mvdm/wow32/wowhooks.c b/private/mvdm/wow32/wowhooks.c
new file mode 100644
index 000000000..a996f1c3a
--- /dev/null
+++ b/private/mvdm/wow32/wowhooks.c
@@ -0,0 +1,1997 @@
+//*****************************************************************************
+//
+// HOOKS -
+//
+// 32bit stubs and thunks for 16bit hooks
+//
+//
+// 01-07-92 NanduriR Created.
+//
+//*****************************************************************************
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wowhooks.c);
+
+//*****************************************************************************
+//
+// Global data. Data is valid only in WOW process context. DLL Data is not
+// Shared amongst various processes. If a WOW hook is set WIN32 USER will call
+// the hookproc in the context of the thread that has the hook set. This implies
+// that all the global data in this DLL is acessible by every WOW thread.
+//
+// Just reaffirming: since USER will call the hookprocs in our process/thread
+// context there is no need for this data to be available
+// in shared memory.
+//
+//*****************************************************************************
+
+
+
+HOOKPERPROCESSDATA vaHookPPData = { NULL, 0};
+
+//
+// In SetWindowsHook we return an index into this array if it was
+// successful. Since NULL implies an error, we cannot use the Zeroth element
+// in this array. So we set its 'InUse' flag to TRUE.
+//
+
+
+HOOKSTATEDATA vaHookStateData[] = {
+ 0, TRUE, 0, NULL, (HKPROC)NULL, 0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc01,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc02,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc03,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc04,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc05,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc06,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc07,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc08,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc09,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc10,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc11,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc12,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc13,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc14,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc15,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc16,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc17,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc18,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc19,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc20,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc21,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc22,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc23,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc24,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc25,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc26,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc27,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc28,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc29,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc30,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc31,0, 0, 0, NULL,
+ 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc32,0, 0, 0, NULL
+ };
+
+
+HOOKPARAMS vHookParams = {0, 0, 0};
+
+INT viCurrentHookStateDataIndex = 0;
+ // this is used when 'DefHookProc' is called.
+
+
+
+//*****************************************************************************
+// Sub-Standard Hook Procs -
+//
+// Hook Stubs. The 'index' (the fourth parameter) is an index into the
+// the HookStateData array. All needed info is available in this array.
+// The hook stubs need to be exported.
+//
+//*****************************************************************************
+
+
+LONG APIENTRY WU32SubStdHookProc01(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x01);
+}
+
+LONG APIENTRY WU32SubStdHookProc02(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x02);
+}
+
+LONG APIENTRY WU32SubStdHookProc03(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x03);
+}
+
+LONG APIENTRY WU32SubStdHookProc04(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x04);
+}
+
+LONG APIENTRY WU32SubStdHookProc05(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x05);
+}
+
+LONG APIENTRY WU32SubStdHookProc06(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x06);
+}
+
+LONG APIENTRY WU32SubStdHookProc07(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x07);
+}
+
+LONG APIENTRY WU32SubStdHookProc08(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x08);
+}
+
+LONG APIENTRY WU32SubStdHookProc09(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x09);
+}
+
+LONG APIENTRY WU32SubStdHookProc10(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x0a);
+}
+
+LONG APIENTRY WU32SubStdHookProc11(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x0b);
+}
+
+LONG APIENTRY WU32SubStdHookProc12(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x0c);
+}
+
+LONG APIENTRY WU32SubStdHookProc13(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x0d);
+}
+
+LONG APIENTRY WU32SubStdHookProc14(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x0e);
+}
+
+LONG APIENTRY WU32SubStdHookProc15(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x0f);
+}
+LONG APIENTRY WU32SubStdHookProc16(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x10);
+}
+LONG APIENTRY WU32SubStdHookProc17(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x11);
+}
+LONG APIENTRY WU32SubStdHookProc18(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x12);
+}
+LONG APIENTRY WU32SubStdHookProc19(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x13);
+}
+LONG APIENTRY WU32SubStdHookProc20(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x14);
+}
+LONG APIENTRY WU32SubStdHookProc21(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x15);
+}
+LONG APIENTRY WU32SubStdHookProc22(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x16);
+}
+LONG APIENTRY WU32SubStdHookProc23(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x17);
+}
+LONG APIENTRY WU32SubStdHookProc24(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x18);
+}
+LONG APIENTRY WU32SubStdHookProc25(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x19);
+}
+LONG APIENTRY WU32SubStdHookProc26(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x1a);
+}
+LONG APIENTRY WU32SubStdHookProc27(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x1b);
+}
+LONG APIENTRY WU32SubStdHookProc28(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x1c);
+}
+LONG APIENTRY WU32SubStdHookProc29(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x1d);
+}
+LONG APIENTRY WU32SubStdHookProc30(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x1e);
+}
+LONG APIENTRY WU32SubStdHookProc31(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x1f);
+}
+LONG APIENTRY WU32SubStdHookProc32(INT nCode, LONG wParam, LONG lParam)
+{
+ return WU32StdHookProc(nCode, wParam, lParam, 0x20);
+}
+
+//*****************************************************************************
+// W32InitHookState:
+//
+// Initializes the global data. Note that this data is initialized for every
+// Process that loads this DLL. However data that is visible only to the 'WOW'
+// process is what we care about.
+//
+//*****************************************************************************
+
+
+BOOL W32InitHookState(HANDLE hMod)
+{
+ INT i;
+
+ vaHookPPData.hMod = hMod;
+ vaHookPPData.cHookProcs = sizeof(vaHookStateData) /
+ sizeof(vaHookStateData[0]);
+
+ for (i = 0; i < vaHookPPData.cHookProcs; i++) {
+ vaHookStateData[i].iIndex = i;
+ vaHookStateData[i].hMod = hMod;
+ }
+
+ return TRUE;
+}
+
+
+
+//*****************************************************************************
+// W32GetNotInUseHookStateData:
+//
+// Steps through the Global HookStateData and returns a pointer to an 'unused'
+// element. This is called only when the Hook is being Set.
+//
+//*****************************************************************************
+
+
+BOOL W32GetNotInUseHookStateData(LPHOOKSTATEDATA lpData)
+{
+ INT i;
+ for (i = 0; i < vaHookPPData.cHookProcs; i++) {
+ if (!vaHookStateData[i].InUse) {
+ vaHookStateData[i].InUse = TRUE;
+ *lpData = vaHookStateData[i];
+ return TRUE;
+ }
+ }
+ LOGDEBUG(LOG_ALWAYS, ("W32GetNotInUseHookStateData: All thunk hook procs in use.\n"));
+ return FALSE;
+}
+
+
+
+//*****************************************************************************
+// W32SetHookStateData:
+//
+// Writes into the global data structure at the specified index.
+//
+//*****************************************************************************
+
+BOOL W32SetHookStateData(LPHOOKSTATEDATA lpData)
+{
+ vaHookStateData[lpData->iIndex] = *lpData;
+ return TRUE;
+}
+
+//*****************************************************************************
+// W32GetHookStateData:
+//
+// Retrieves data from the global data structure at the specified index.
+//
+//*****************************************************************************
+
+BOOL W32GetHookStateData(LPHOOKSTATEDATA lpData)
+{
+ if ( lpData->iIndex >= 0 && lpData->iIndex < vaHookPPData.cHookProcs ) {
+ *lpData = vaHookStateData[lpData->iIndex];
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+//*****************************************************************************
+// W32GetThunkHookProc:
+//
+// Its callled to find a 32stub for the hook that is being set.
+// Returns TRUE if successful else FALSE.
+// The data is partially updated to reflect the characteristics of the hook
+// that is being set.
+//
+//*****************************************************************************
+
+BOOL W32GetThunkHookProc(INT iHook, DWORD Proc16, LPHOOKSTATEDATA lpData)
+{
+ register PTD ptd = CURRENTPTD();
+
+ if (W32GetNotInUseHookStateData(lpData)) {
+ lpData->iHook = iHook;
+ lpData->Proc16 = Proc16;
+ lpData->TaskId = ptd->htask16 ;
+ W32SetHookStateData(lpData);
+ return TRUE;
+ }
+ else
+ return FALSE;
+
+}
+
+
+
+//*****************************************************************************
+// W32IsDuplicateHook:
+//
+// Verifies if the given hook has already been set. This is to catch
+// certain apps which go on Setting the same hook without Unhooking the
+// previous hook.
+//
+// Returns the 'stubindex' if hook already exists else 0;
+//
+//*****************************************************************************
+
+INT W32IsDuplicateHook(INT iHook, DWORD Proc16, INT TaskId)
+{
+ INT i;
+ for (i = 0; i < vaHookPPData.cHookProcs; i++) {
+ if (vaHookStateData[i].InUse &&
+ vaHookStateData[i].iHook == iHook &&
+ vaHookStateData[i].TaskId == TaskId &&
+ vaHookStateData[i].Proc16 == Proc16 ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+//*****************************************************************************
+// W32FreeHHook:
+//
+// The state of the specified hook is set to 'Not in use'.
+// Returns hHook of the hook being freed.
+//
+//*****************************************************************************
+
+
+HHOOK W32FreeHHook(INT iHook, DWORD Proc16)
+{
+
+ register PTD ptd = CURRENTPTD();
+ INT i;
+ for (i = 0; i < vaHookPPData.cHookProcs; i++) {
+ if (vaHookStateData[i].InUse &&
+ vaHookStateData[i].iHook == iHook &&
+ vaHookStateData[i].TaskId == (INT)ptd->htask16 &&
+ vaHookStateData[i].Proc16 == Proc16) {
+ vaHookStateData[i].InUse = FALSE;
+ return vaHookStateData[i].hHook;
+ }
+ }
+ LOGDEBUG(LOG_ALWAYS, ("W32FreeHHook: Couldn't locate the specified hook."));
+ return (HHOOK)NULL;
+}
+
+
+
+
+//*****************************************************************************
+// W32FreeHHookOfIndex:
+//
+// The state of the specified hook is set to 'Not in use'.
+// Returns hHook of the hook being freed.
+//
+//*****************************************************************************
+
+
+HHOOK W32FreeHHookOfIndex(INT iFunc)
+{
+ register PTD ptd = CURRENTPTD();
+
+ if (iFunc && iFunc < vaHookPPData.cHookProcs)
+ if (vaHookStateData[iFunc].InUse &&
+ vaHookStateData[iFunc].TaskId == (INT)ptd->htask16) {
+ vaHookStateData[iFunc].InUse = FALSE;
+ return vaHookStateData[iFunc].hHook;
+ }
+ LOGDEBUG(LOG_ALWAYS, ("W32FreeHHookOfIndex: Couldn't locate the specified hook."));
+ return (HHOOK)NULL;
+}
+
+
+
+
+//*****************************************************************************
+// W32GetHookParams:
+//
+// Returns the 32bit hookparams of the current hook.
+//
+//*****************************************************************************
+
+
+BOOL W32GetHookParams(LPHOOKPARAMS lpHookParams)
+{
+ if (lpHookParams) {
+ *lpHookParams = vHookParams;
+ }
+
+ return (BOOL)lpHookParams;
+}
+
+
+
+//*****************************************************************************
+// W32StdHookProc: (Standard Hook Proc)
+//
+// All the stubs call this proc.
+// Return value is dependent on the hook type.
+//
+//*****************************************************************************
+
+LONG APIENTRY WU32StdHookProc(INT nCode, LONG wParam, LONG lParam, INT iFunc)
+{
+ //
+ // USER will call us in WOW context. Just Verify.
+ //
+
+ if (!vaHookStateData[iFunc].InUse) {
+ // DbgPrint("WU32StdHookProc:Stub %04x called in WRONG process\n", iFunc);
+ return FALSE;
+ }
+
+ //
+ // USER can call us even if we have GP Faulted - so just ignore the input
+ //
+
+ if (CURRENTPTD()->dwFlags & TDF_IGNOREINPUT) {
+ LOGDEBUG(LOG_ALWAYS,("WU32StdHookProc Ignoring Input\n"));
+ WOW32ASSERTMSG(!gfIgnoreInputAssertGiven,
+ "WCD32CommonDialogProc: TDF_IGNOREINPUT hack was used, shouldn't be, "
+ "please email DaveHart with repro instructions. Hit 'g' to ignore this "
+ "and suppress this assertion from now on.\n");
+ gfIgnoreInputAssertGiven = TRUE;
+ return FALSE;
+ }
+
+ //
+ // store the stubindex. If the hookproc calls the DefHookProc() we will
+ // be able to findout the Hook Type.
+ //
+
+ viCurrentHookStateDataIndex = iFunc;
+
+ //
+ // store the hook params. These will be used if DefHookProc gets called
+ // by the 16bit stub. We are interested only in lParam.
+ //
+
+ vHookParams.nCode = nCode;
+ vHookParams.wParam = wParam;
+ vHookParams.lParam = lParam;
+
+ switch (vaHookStateData[iFunc].iHook) {
+ case WH_CALLWNDPROC:
+ return ThunkCallWndProcHook(nCode, wParam, (LPCWPSTRUCT)lParam,
+ &vaHookStateData[iFunc]);
+
+ case WH_CBT:
+
+ return ThunkCbtHook(nCode, wParam, lParam,
+ &vaHookStateData[iFunc]);
+
+
+ case WH_KEYBOARD:
+ return ThunkKeyBoardHook(nCode, wParam, lParam,
+ &vaHookStateData[iFunc]);
+
+ case WH_MSGFILTER:
+
+ // This code is TEMP only and must be fixed. ChandanC 5/2/92.
+ if ((WORD)vaHookStateData[iFunc].TaskId !=
+ (WORD)((PTD)CURRENTPTD())->htask16)
+ break;
+
+ WOW32ASSERT((WORD)vaHookStateData[iFunc].TaskId ==
+ (WORD)((PTD)CURRENTPTD())->htask16);
+ case WH_SYSMSGFILTER:
+ case WH_GETMESSAGE:
+
+ return ThunkMsgFilterHook(nCode, wParam, (LPMSG)lParam,
+ &vaHookStateData[iFunc]);
+ break;
+
+ case WH_JOURNALPLAYBACK:
+ case WH_JOURNALRECORD:
+ return ThunkJournalHook(nCode, wParam, (LPEVENTMSG)lParam,
+ &vaHookStateData[iFunc]);
+
+ case WH_DEBUG:
+ return ThunkDebugHook(nCode, wParam, lParam,
+ &vaHookStateData[iFunc]);
+
+
+ case WH_MOUSE:
+ return ThunkMouseHook(nCode, wParam, (LPMOUSEHOOKSTRUCT)lParam,
+ &vaHookStateData[iFunc]);
+
+ case WH_SHELL:
+ return ThunkShellHook(nCode, wParam, lParam,
+ &vaHookStateData[iFunc]);
+
+ default:
+ LOGDEBUG(LOG_ALWAYS,("W32StdHookProc: Unknown Hook type."));
+ }
+
+ return (LONG)FALSE;
+
+}
+
+
+
+//*****************************************************************************
+//
+// ThunkHookProc for Hooks of type WH_CALLWNDPROC -
+//
+// Return type is VOID.
+//
+//*****************************************************************************
+
+
+LONG ThunkCallWndProcHook(INT nCode, LONG wParam, LPCWPSTRUCT lpCwpStruct,
+ LPHOOKSTATEDATA lpHSData)
+{
+ VPVOID vp;
+ PCWPSTRUCT16 pCwpStruct16;
+ PARM16 Parm16;
+ WM32MSGPARAMEX wm32mpex;
+ BOOL fMessageNeedsThunking;
+
+ wm32mpex.Parm16.WndProc.wMsg = (WORD) lpCwpStruct->message;
+ wm32mpex.Parm16.WndProc.wParam = (WORD) lpCwpStruct->wParam;
+ wm32mpex.Parm16.WndProc.lParam = (LONG) lpCwpStruct->lParam;
+
+ fMessageNeedsThunking = (lpCwpStruct->message < 0x400) &&
+ (aw32Msg[lpCwpStruct->message].lpfnM32 != WM32NoThunking);
+ if (fMessageNeedsThunking) {
+
+ LOGDEBUG(3,("%04X (%s)\n", CURRENTPTD()->htask16, (aw32Msg[lpCwpStruct->message].lpszW32)));
+
+ wm32mpex.fThunk = THUNKMSG;
+ wm32mpex.hwnd = lpCwpStruct->hwnd;
+ wm32mpex.uMsg = lpCwpStruct->message;
+ wm32mpex.uParam = lpCwpStruct->wParam;
+ wm32mpex.lParam = lpCwpStruct->lParam;
+ wm32mpex.lpfnM32 = aw32Msg[wm32mpex.uMsg].lpfnM32;
+ wm32mpex.pww = (PWW)NULL;
+ if (!(wm32mpex.lpfnM32)(&wm32mpex)) {
+ LOGDEBUG(LOG_ALWAYS,("ThunkCallWndProcHook: cannot thunk 32-bit message %04x\n",
+ lpCwpStruct->message));
+ }
+ }
+
+ vp = stackalloc16(sizeof(CWPSTRUCT16));
+
+ GETMISCPTR(vp, pCwpStruct16);
+
+ STOREWORD(pCwpStruct16->hwnd, GETHWND16(lpCwpStruct->hwnd));
+ STOREWORD(pCwpStruct16->message, wm32mpex.Parm16.WndProc.wMsg );
+ STOREWORD(pCwpStruct16->wParam, wm32mpex.Parm16.WndProc.wParam);
+ STORELONG(pCwpStruct16->lParam, wm32mpex.Parm16.WndProc.lParam);
+
+ FLUSHVDMPTR(vp, sizeof(CWPSTRUCT16), pCwpStruct16);
+ FREEVDMPTR(pCwpStruct16);
+
+ Parm16.HookProc.nCode = (SHORT)nCode;
+ Parm16.HookProc.wParam = (SHORT)wParam;
+ Parm16.HookProc.lParam = vp;
+
+ CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&wm32mpex.lReturn);
+
+#ifdef DEBUG
+ GETMISCPTR(vp, pCwpStruct16);
+
+ if (pCwpStruct16->message != wm32mpex.Parm16.WndProc.wMsg)
+ LOGDEBUG(LOG_ALWAYS,("ThunkCallWndProcHook: IN message != OUT message"));
+
+ FREEVDMPTR(pCwpStruct16);
+#endif
+
+ if (fMessageNeedsThunking) {
+
+ wm32mpex.fThunk = UNTHUNKMSG;
+ (wm32mpex.lpfnM32)(&wm32mpex);
+ }
+
+ stackfree16(vp);
+
+ return (LONG)FALSE; // return value doesn't matter
+}
+
+
+
+//*****************************************************************************
+//
+// ThunkHookProc for Hooks of type WH_CBT -
+//
+// Return type is BOOL.
+//
+//*****************************************************************************
+
+LONG ThunkCbtHook(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn = FALSE;
+ PARM16 Parm16;
+
+ VPVOID vp;
+ PMOUSEHOOKSTRUCT16 pMHStruct16;
+ PCBTACTIVATESTRUCT16 pCbtAStruct16;
+ VPCREATESTRUCT16 vpcs16;
+ PCBT_CREATEWND16 pCbtCWnd16;
+ WM32MSGPARAMEX wm32mpex;
+
+ Parm16.HookProc.nCode = (SHORT)nCode;
+ Parm16.HookProc.wParam = (SHORT)wParam;
+ Parm16.HookProc.lParam = lParam;
+
+ switch(nCode) {
+ case HCBT_MOVESIZE:
+
+ // wParam = HWND, lParam = LPRECT
+
+ Parm16.HookProc.wParam = GETHWND16(wParam);
+ vp = stackalloc16(sizeof(RECT16));
+
+ PUTRECT16(vp, (LPRECT)lParam);
+
+ Parm16.HookProc.lParam = vp;
+
+ break;
+
+ case HCBT_MINMAX:
+
+ // wParam = HWND, lParam = SW_* --- a command
+
+ Parm16.HookProc.wParam = GETHWND16(wParam);
+ break;
+
+ case HCBT_QS:
+
+ // wParam = 0, lParam = 0
+
+ break;
+
+ case HCBT_CREATEWND:
+
+ // wParam = HWND, lParam = LPCBT_CREATEWND
+
+ wm32mpex.fThunk = THUNKMSG;
+ wm32mpex.hwnd = (HWND)wParam;
+ wm32mpex.uMsg = 0;
+ wm32mpex.uParam = 0;
+ wm32mpex.lParam = (LONG)((LPCBT_CREATEWND)lParam)->lpcs;
+ wm32mpex.pww = (PWW)GetWindowLong((HWND)wParam, GWL_WOWWORDS);
+ /*
+ * WM32Create now requires that pww be initialized
+ */
+ if (!wm32mpex.pww || !WM32Create(&wm32mpex))
+ return FALSE;
+ vpcs16 = wm32mpex.Parm16.WndProc.lParam;
+ lReturn = wm32mpex.lReturn;
+
+ vp = stackalloc16(sizeof(CBT_CREATEWND16));
+
+ GETMISCPTR(vp, pCbtCWnd16);
+ STOREDWORD(pCbtCWnd16->vpcs, vpcs16);
+ STOREWORD(pCbtCWnd16->hwndInsertAfter,
+ GETHWNDIA16(((LPCBT_CREATEWND)lParam)->hwndInsertAfter));
+
+ Parm16.HookProc.wParam = GETHWND16(wParam);
+ Parm16.HookProc.lParam = vp;
+
+ FLUSHVDMPTR(vp, sizeof(CBT_CREATEWND16), pCbtCWnd16);
+ FREEVDMPTR(pCbtCWnd16);
+ break;
+
+ case HCBT_DESTROYWND:
+
+ // wParam = HWND, lParam = 0
+
+ Parm16.HookProc.wParam = GETHWND16(wParam);
+ break;
+
+ case HCBT_ACTIVATE:
+
+ // wParam = HWND, lParam = LPCBTACTIVATESTRUCT
+
+ vp = stackalloc16(sizeof(CBTACTIVATESTRUCT16));
+
+ GETMISCPTR(vp, pCbtAStruct16);
+ PUTCBTACTIVATESTRUCT16(pCbtAStruct16, ((LPCBTACTIVATESTRUCT)lParam));
+
+ Parm16.HookProc.wParam = GETHWND16(wParam);
+ Parm16.HookProc.lParam = vp;
+
+ FLUSHVDMPTR(vp, sizeof(CBTACTIVATESTRUCT16), pCbtAStruct16);
+ FREEVDMPTR(pCbtAStruct16);
+ break;
+
+ case HCBT_CLICKSKIPPED:
+
+ // wParam = mouse message, lParam = LPMOUSEHOOKSTRUCT
+
+ vp = stackalloc16(sizeof(MOUSEHOOKSTRUCT16));
+
+ GETMISCPTR(vp, pMHStruct16);
+ PUTMOUSEHOOKSTRUCT16(pMHStruct16, (LPMOUSEHOOKSTRUCT)lParam);
+
+ Parm16.HookProc.lParam = vp;
+
+ FLUSHVDMPTR(vp, sizeof(MOUSEHOOKSTRUCT16), pMHStruct16);
+ FREEVDMPTR(pMHStruct16);
+ break;
+
+ case HCBT_KEYSKIPPED:
+
+ // wParam, lParam -- keyup/down message params
+
+ break;
+
+ case HCBT_SYSCOMMAND:
+
+ // wParam = SC_ syscomand, lParam = DWORD(x,y)
+
+ break;
+
+ case HCBT_SETFOCUS:
+
+ // wParam = HWND, lParam = HWND
+
+ Parm16.HookProc.wParam = GETHWND16(wParam);
+ Parm16.HookProc.lParam = GETHWND16(lParam);
+ break;
+
+ default:
+ LOGDEBUG(LOG_ALWAYS, ("ThunkCbtHook: Unknown HCBT_ code\n"));
+ break;
+ }
+
+ CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&lReturn);
+
+ switch(nCode) {
+ case HCBT_MOVESIZE:
+
+ GETRECT16(vp, (LPRECT)lParam);
+ stackfree16(vp);
+ break;
+
+ case HCBT_CREATEWND:
+ GETMISCPTR(vp, pCbtCWnd16);
+ ((LPCBT_CREATEWND)lParam)->hwndInsertAfter =
+ HWNDIA32(FETCHWORD(pCbtCWnd16->hwndInsertAfter));
+ FREEVDMPTR(pCbtCWnd16);
+ wm32mpex.fThunk = UNTHUNKMSG;
+ wm32mpex.lReturn = lReturn;
+ WM32Create(&wm32mpex);
+ lReturn = wm32mpex.lReturn;
+ stackfree16(vp);
+ break;
+
+
+ case HCBT_ACTIVATE:
+
+ GETMISCPTR(vp, pCbtAStruct16);
+ GETCBTACTIVATESTRUCT16(pCbtAStruct16, (LPCBTACTIVATESTRUCT)lParam);
+ FREEVDMPTR(pCbtAStruct16);
+ stackfree16(vp);
+ break;
+
+ case HCBT_CLICKSKIPPED:
+
+ GETMISCPTR(vp, pMHStruct16);
+ GETMOUSEHOOKSTRUCT16(pMHStruct16, (LPMOUSEHOOKSTRUCT)lParam);
+ FREEVDMPTR(pMHStruct16);
+ stackfree16(vp);
+ break;
+
+ // case HCBT_MINMAX:
+ // case HCBT_QS:
+ // case HCBT_DESTROYWND:
+ // case HCBT_KEYSKIPPED:
+ // case HCBT_SYSCOMMAND:
+ // case HCBT_SETFOCUS:
+
+ default:
+ break;
+ }
+
+ // the value in LOWORD is the valid return value
+
+ return (LONG)(BOOL)LOWORD(lReturn);
+}
+
+
+
+//*****************************************************************************
+//
+// ThunkHookProc for Hooks of type WH_KEYBOARD -
+//
+// Return type is BOOL.
+//
+//*****************************************************************************
+
+LONG ThunkKeyBoardHook(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn;
+ PARM16 Parm16;
+
+ Parm16.HookProc.nCode = (SHORT)nCode;
+ Parm16.HookProc.wParam = (SHORT)wParam;
+ Parm16.HookProc.lParam = lParam;
+
+ CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&lReturn);
+
+ // the value in LOWORD is the valid return value
+
+ return (LONG)(BOOL)LOWORD(lReturn);
+}
+
+
+
+//*****************************************************************************
+//
+// ThunkHookProc for Hooks of type WH_GETMESSAGE -
+// WH_MSGFILTER -
+// WH_SYSMSGFILTER -
+//
+// WARNING: May cause 16-bit memory movement, invalidating flat pointers.
+//
+// Return type is BOOL.
+//
+//*****************************************************************************
+
+LONG ThunkMsgFilterHook(INT nCode, LONG wParam, LPMSG lpMsg,
+ LPHOOKSTATEDATA lpHSData)
+{
+ VPVOID vp;
+ PMSG16 pMsg16;
+ PARM16 Parm16;
+ WM32MSGPARAMEX wm32mpex;
+
+ BOOL fHookModifiedLpMsg;
+ HWND hwnd32;
+ MSGPARAMEX mpex;
+ BOOL fUseOld;
+ static MSG msgSave;
+ static int cRecurse = 0;
+ static PARM16 Parm16Save;
+ BOOL fMessageNeedsThunking;
+
+ // This should be removed when all thunk functions appropiately fill these
+ // in, till then we must have these 3 lines before calling thunk functions !
+ // ChandanC, 2/28/92
+ //
+
+ wm32mpex.Parm16.WndProc.wMsg = (WORD) lpMsg->message;
+ wm32mpex.Parm16.WndProc.wParam = (WORD) lpMsg->wParam;
+ wm32mpex.Parm16.WndProc.lParam = (LONG) lpMsg->lParam;
+
+ fMessageNeedsThunking = (lpMsg->message < 0x400) &&
+ (aw32Msg[lpMsg->message].lpfnM32 != WM32NoThunking);
+ fThunkDDEmsg = FALSE;
+
+ if (fMessageNeedsThunking) {
+ LOGDEBUG(3,("%04X (%s)\n", CURRENTPTD()->htask16,
+ (aw32Msg[lpMsg->message].lpszW32)));
+
+ wm32mpex.fThunk = THUNKMSG;
+ wm32mpex.hwnd = lpMsg->hwnd;
+ wm32mpex.uMsg = lpMsg->message;
+ wm32mpex.uParam = lpMsg->wParam;
+ wm32mpex.lParam = lpMsg->lParam;
+ wm32mpex.pww = (PWW)NULL;
+ wm32mpex.fFree = FALSE;
+ wm32mpex.lpfnM32 = aw32Msg[wm32mpex.uMsg].lpfnM32;
+ if (!((wm32mpex.lpfnM32)(&wm32mpex))) {
+ LOGDEBUG(LOG_ALWAYS,("ThunkMsgFilterHook: cannot thunk 32-bit message %04x\n",
+ lpMsg->message));
+ }
+ }
+
+ fThunkDDEmsg = TRUE;
+
+ //
+ // Check to see if we've recursed into this routine. If so and the message
+ // contents are the same, use the last message pointer we gave the 16
+ // bit app rather than allocating a new one. Need this to solve the
+ // SoundBits Browser problem. It checks to see if the lpmsg passed
+ // is the same as it got last time - if so, it doesn't call this other
+ // function that causes recursion.
+ //
+
+ fUseOld = FALSE;
+
+ if (cRecurse != 0 && lpMsg->hwnd == msgSave.hwnd &&
+ lpMsg->message == msgSave.message &&
+ lpMsg->wParam == msgSave.wParam &&
+ lpMsg->lParam == msgSave.lParam &&
+ lpMsg->time == msgSave.time &&
+ lpMsg->pt.x == msgSave.pt.x &&
+ lpMsg->pt.y == msgSave.pt.y) {
+
+ fUseOld = TRUE;
+
+ } else {
+ //
+ // Not the same... reset this thing in case the count is screwed
+ // up. Also remember this message, in case we do recurse.
+ //
+
+ cRecurse = 0;
+ msgSave = *lpMsg;
+ }
+
+ if (!fUseOld) {
+ vp = malloc16(sizeof(MSG16));
+ if (vp == (VPVOID)NULL)
+ return FALSE;
+
+ GETMISCPTR(vp, pMsg16);
+ STOREWORD(pMsg16->hwnd, GETHWND16((lpMsg)->hwnd));
+ STOREWORD(pMsg16->message, wm32mpex.Parm16.WndProc.wMsg );
+ STOREWORD(pMsg16->wParam, wm32mpex.Parm16.WndProc.wParam);
+ STORELONG(pMsg16->lParam, wm32mpex.Parm16.WndProc.lParam);
+ STORELONG(pMsg16->time, (lpMsg)->time);
+ STOREWORD(pMsg16->pt.x, (lpMsg)->pt.x);
+ STOREWORD(pMsg16->pt.y, (lpMsg)->pt.y);
+
+ Parm16.HookProc.nCode = (SHORT)nCode;
+ Parm16.HookProc.wParam = (SHORT)wParam;
+ Parm16.HookProc.lParam = vp;
+
+ //
+ // Remember Parm16 in case we need to use it again due to the recursion
+ // case.
+ //
+
+ Parm16Save = Parm16;
+
+ } else {
+
+ //
+ // Use old message contents.
+ //
+
+ Parm16 = Parm16Save;
+ vp = (VPVOID)Parm16Save.HookProc.lParam;
+
+ GETMISCPTR(vp, pMsg16);
+ }
+
+ FLUSHVDMPTR(vp, sizeof(MSG16), pMsg16);
+
+ //
+ // Count how many times we recurse through this hook proc. Need this count
+ // to solve the SoundBits Browser problem. It checks to see if the lpMsg
+ // passed is the same as it got last time - if so, it doesn't call this
+ // other function that causes recursion.
+ //
+
+ cRecurse++;
+ CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&wm32mpex.lReturn);
+ cRecurse--;
+
+ // set the correct return value BEFORE unthunking
+ wm32mpex.lReturn = (LONG)(BOOL)LOWORD(wm32mpex.lReturn);
+
+ //
+ // Free the 32 pointer to 16 bit args and get it again in case underlying
+ // memory movement occured.
+ //
+
+ FREEVDMPTR(pMsg16);
+ GETMISCPTR(vp, pMsg16);
+
+ fThunkDDEmsg = FALSE;
+
+ // Theoretically an app can change the lpMsg and return a totall different
+ // data altogether. In practice most apps don't do anything so it is pretty
+ // expensive to go through the 'unthunk' procedure all the time. So here is
+ // a compromise. We copy the message params only if the output message is
+ // different from the input message.
+ //
+ // (davehart) Polaris PackRat modifies WM_KEYDOWN messages sent to its
+ // multiline "Note" edit control in its Phone Book Entry dialog box.
+ // It changes wParam (the VK_ code) from 0xD (VK_RETURN) to 0xA, which
+ // is understood by the edit control to be identical to VK_RETURN but
+ // won't cause the dialog box to close. So we special-case here
+ // WM_KEYDOWN where the hook proc changed the virtual key (in wParam)
+ // and unthunk it properly.
+
+ fHookModifiedLpMsg = (pMsg16->message != wm32mpex.Parm16.WndProc.wMsg) ||
+ (wm32mpex.Parm16.WndProc.wMsg == WM_KEYDOWN &&
+ pMsg16->wParam != wm32mpex.Parm16.WndProc.wParam) ||
+ (pMsg16->hwnd != GETHWND16(lpMsg->hwnd));
+
+
+ if (fHookModifiedLpMsg) {
+ mpex.Parm16.WndProc.hwnd = pMsg16->hwnd;
+ mpex.Parm16.WndProc.wMsg = pMsg16->message;
+ mpex.Parm16.WndProc.wParam = pMsg16->wParam;
+ mpex.Parm16.WndProc.lParam = pMsg16->lParam,
+ mpex.iMsgThunkClass = WOWCLASS_UNKNOWN;
+ hwnd32 = ThunkMsg16(&mpex);
+
+ //
+ // Free the 32 pointer to 16 bit args and get it again in case
+ // underlying memory movement occured.
+ //
+
+ FREEVDMPTR(pMsg16);
+ GETMISCPTR(vp, pMsg16);
+
+ // reset flag if message thunking failed.
+
+ if (!hwnd32)
+ fHookModifiedLpMsg = FALSE;
+ }
+
+ if (fMessageNeedsThunking) {
+
+ wm32mpex.fThunk = UNTHUNKMSG;
+ (wm32mpex.lpfnM32)(&wm32mpex);
+
+ //
+ // Free the 32 pointer to 16 bit args and get it again in case
+ // underlying memory movement occured.
+ //
+
+ FREEVDMPTR(pMsg16);
+ GETMISCPTR(vp, pMsg16);
+ }
+
+ fThunkDDEmsg = TRUE;
+
+ if (fHookModifiedLpMsg) {
+ lpMsg->hwnd = hwnd32;
+ lpMsg->message = mpex.uMsg;
+ lpMsg->wParam = mpex.uParam;
+ lpMsg->lParam = mpex.lParam;
+ lpMsg->time = FETCHLONG(pMsg16->time);
+ lpMsg->pt.x = FETCHSHORT(pMsg16->pt.x);
+ lpMsg->pt.y = FETCHSHORT(pMsg16->pt.y);
+ }
+
+
+ FREEVDMPTR(pMsg16);
+
+ if (!fUseOld) {
+ free16(vp);
+ }
+
+ // the value in LOWORD is the valid return value
+
+ return (LONG)(BOOL)LOWORD(wm32mpex.lReturn);
+}
+
+
+
+//*****************************************************************************
+//
+// ThunkHookProc for Hooks of type WH_JOURNALPLAYBACK -
+// WH_JOUNRALRECORD -
+//
+// Return type is DWORD.
+//
+//*****************************************************************************
+
+LONG ThunkJournalHook(INT nCode, LONG wParam, LPEVENTMSG lpEventMsg,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn;
+ VPVOID vp;
+ PEVENTMSG16 pEventMsg16;
+ PARM16 Parm16;
+
+ if ( lpEventMsg ) {
+ vp = stackalloc16(sizeof(EVENTMSG16));
+
+
+ // The WIN32 EVENTMSG structure has an additional field 'hwnd', which
+ // is not there in WIN31 EVENTMSG structure. This field can be ignored
+ // without any repercussions.
+
+ if (lpHSData->iHook == WH_JOURNALRECORD) {
+ GETMISCPTR(vp, pEventMsg16);
+ PUTEVENTMSG16(pEventMsg16, lpEventMsg);
+ FLUSHVDMPTR(vp, sizeof(EVENTMSG16), pEventMsg16);
+ FREEVDMPTR(pEventMsg16);
+ }
+
+
+ } else {
+ // lpEventMsg can be NULL indicating that no message data is requested.
+ // If this is the case, there is no need to copy data for either
+ // journal record or playback.
+ vp = (VPVOID)0;
+ }
+
+ Parm16.HookProc.nCode = (SHORT)nCode;
+ Parm16.HookProc.wParam = (SHORT)wParam;
+ Parm16.HookProc.lParam = vp;
+
+ CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&lReturn);
+
+ if ( lpEventMsg ) {
+ GETMISCPTR(vp, pEventMsg16);
+
+ if (lpHSData->iHook == WH_JOURNALPLAYBACK) {
+ GetEventMessage16(pEventMsg16, lpEventMsg);
+
+#ifdef DEBUG
+ if (MessageNeedsThunking(lpEventMsg->message)) {
+ LOGDEBUG(LOG_ALWAYS, ("ThunkJournalHook: Playing back unexpected message 0x%x", lpEventMsg->message));
+ }
+#endif
+
+ } else {
+ WOW32ASSERT(lpHSData->iHook == WH_JOURNALRECORD);
+ WOW32ASSERT(aw32Msg[FETCHWORD(pEventMsg16->message)].lpfnM32 == WM32NoThunking);
+
+ // If the app modified the message then copy the new message info
+ // (rather than copying it every time we only copy it if the
+ // app change the message)
+ if (FETCHWORD(pEventMsg16->message) != lpEventMsg->message) {
+ GetEventMessage16(pEventMsg16, lpEventMsg);
+ }
+ }
+
+ FREEVDMPTR(pEventMsg16);
+ stackfree16(vp);
+ }
+
+ return lReturn;
+}
+
+
+
+//*****************************************************************************
+//
+// ThunkHookProc for Hooks of type WH_DEBUG -
+//
+// Return type is BOOL.
+//
+//*****************************************************************************
+
+LONG ThunkDebugHook(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn;
+
+ lReturn = TRUE;
+
+ UNREFERENCED_PARAMETER(nCode);
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+ UNREFERENCED_PARAMETER(lpHSData);
+
+ LOGDEBUG(LOG_ALWAYS, ("ThunkDebugHook:Not implemented.\n"));
+
+ // the value in LOWORD is the valid return value
+
+ return (LONG)(BOOL)LOWORD(lReturn);
+}
+
+
+
+//*****************************************************************************
+//
+// ThunkHookProc for Hooks of type WH_MOUSE -
+//
+// Return type is BOOL.
+//
+//*****************************************************************************
+
+LONG ThunkMouseHook(INT nCode, LONG wParam, LPMOUSEHOOKSTRUCT lpMHStruct,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn;
+ VPVOID vp;
+ PMOUSEHOOKSTRUCT16 pMHStruct16;
+ PARM16 Parm16;
+
+ vp = stackalloc16(sizeof(MOUSEHOOKSTRUCT16));
+
+ GETMISCPTR(vp, pMHStruct16);
+ PUTMOUSEHOOKSTRUCT16(pMHStruct16, lpMHStruct);
+
+ Parm16.HookProc.nCode = (SHORT)nCode;
+ Parm16.HookProc.wParam = (SHORT)wParam;
+ Parm16.HookProc.lParam = vp;
+
+ FLUSHVDMPTR(vp, sizeof(MOUSEHOOKSTRUCT16), pMHStruct16);
+ FREEVDMPTR(pMHStruct16);
+
+ CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&lReturn);
+
+ GETMISCPTR(vp, pMHStruct16);
+ GETMOUSEHOOKSTRUCT16(pMHStruct16, lpMHStruct);
+ FREEVDMPTR(pMHStruct16);
+ stackfree16(vp);
+ return (LONG)(BOOL)LOWORD(lReturn);
+}
+
+
+
+//*****************************************************************************
+//
+// ThunkHookProc for Hooks of type WH_SHELL -
+//
+// Return value apparently is zero.
+//
+//*****************************************************************************
+
+LONG ThunkShellHook(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn;
+ PARM16 Parm16;
+
+ Parm16.HookProc.nCode = (SHORT)nCode;
+ Parm16.HookProc.lParam = lParam;
+
+ switch (nCode) {
+ case HSHELL_WINDOWCREATED:
+ case HSHELL_WINDOWDESTROYED:
+ Parm16.HookProc.wParam = (SHORT)GETHWND16(wParam);
+ break;
+
+ case HSHELL_ACTIVATESHELLWINDOW:
+ // fall thru
+
+ default:
+ Parm16.HookProc.wParam = (SHORT)wParam;
+ break;
+ }
+
+ CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&lReturn);
+
+ // lReturn = 0?
+
+ return (LONG)lReturn;
+}
+
+
+
+//*****************************************************************************
+// W32UnhookHooks:
+//
+// Scans the list of active hooks for those for the passed in handle.
+// Those that match are unhooked.
+//
+//*****************************************************************************
+
+VOID W32UnhookHooks( HAND16 hMod16, BOOL fQueue )
+{
+ INT i;
+
+ for (i = 0; i < vaHookPPData.cHookProcs; i++) {
+ if (vaHookStateData[i].InUse ) {
+
+ if ( !fQueue && ((HAND16)(vaHookStateData[i].hMod16) == hMod16) ) {
+ //
+ // Unhook this guy!
+ //
+
+ if (UnhookWindowsHookEx(vaHookStateData[i].hHook)) {
+ LOGDEBUG(7, ("W32FreeModuleHooks: Freed iHook (WH_*) %04x\n",
+ vaHookStateData[i].iHook));
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS, ("W32FreeModuleHooks: ERROR Freeing iHook (WH_*) %04x\n",
+ vaHookStateData[i].iHook));
+ }
+
+ // reset the state, even if Unhooking failed.
+
+ vaHookStateData[i].TaskId = 0;
+ vaHookStateData[i].InUse = FALSE;
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+// W32FreeOwnedHooks -
+//
+// Called during thread exit time. Frees all hooks set by specified thread.
+//
+//*****************************************************************************
+
+BOOL W32FreeOwnedHooks(INT iTaskId)
+{
+ INT i;
+ for (i = 0; i < vaHookPPData.cHookProcs; i++) {
+ if (vaHookStateData[i].InUse &&
+ vaHookStateData[i].TaskId == iTaskId) {
+ if (UnhookWindowsHookEx(vaHookStateData[i].hHook)) {
+ LOGDEBUG(7, ("W32FreeOwnedHooks: Freed iHook (WH_*) %04x\n",
+ vaHookStateData[i].iHook));
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS, ("W32FreeOwnedHooks: ERROR Freeing iHook (WH_*) %04x\n",
+ vaHookStateData[i].iHook));
+ }
+
+ // reset the state, even if Unhooking failed.
+
+ vaHookStateData[i].TaskId = 0;
+ vaHookStateData[i].InUse = FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+//*****************************************************************************
+// W32StdDefHookProc: (Standard Def Hook Proc)
+//
+// WU32DefHookProc is called here.
+// WARNING: May cause 16-bit memory movement, invalidating flat pointers.
+// Return value is the new lParam.
+//
+//*****************************************************************************
+
+LONG APIENTRY WU32StdDefHookProc(INT nCode, LONG wParam, LONG lParam, INT iFunc)
+{
+ switch (vaHookStateData[iFunc].iHook) {
+ case WH_CALLWNDPROC:
+ return ThunkCallWndProcHook16(nCode, wParam, (VPVOID)lParam,
+ &vaHookStateData[iFunc]);
+
+ case WH_CBT:
+
+ return ThunkCbtHook16(nCode, wParam, (VPVOID)lParam,
+ &vaHookStateData[iFunc]);
+
+
+ case WH_KEYBOARD:
+ return ThunkKeyBoardHook16(nCode, wParam, lParam,
+ &vaHookStateData[iFunc]);
+
+ case WH_MSGFILTER:
+ case WH_SYSMSGFILTER:
+ case WH_GETMESSAGE:
+
+ return ThunkMsgFilterHook16(nCode, wParam, (VPVOID)lParam,
+ &vaHookStateData[iFunc]);
+
+ case WH_JOURNALPLAYBACK:
+ case WH_JOURNALRECORD:
+ return ThunkJournalHook16(nCode, wParam, (VPVOID)lParam,
+ &vaHookStateData[iFunc]);
+
+ case WH_DEBUG:
+ return ThunkDebugHook16(nCode, wParam, lParam,
+ &vaHookStateData[iFunc]);
+
+
+ case WH_MOUSE:
+ return ThunkMouseHook16(nCode, wParam, (VPVOID)lParam,
+ &vaHookStateData[iFunc]);
+
+ case WH_SHELL:
+ return ThunkShellHook16(nCode, wParam, lParam,
+ &vaHookStateData[iFunc]);
+
+ default:
+ LOGDEBUG(LOG_ALWAYS,("WU32StdDefHookProc: Unknown Hook type.\n"));
+ }
+
+ return (LONG)FALSE;
+
+}
+
+//*****************************************************************************
+//
+// 16->32 ThunkHookProc for Hooks of type WH_CALLWNDPROC -
+//
+// Return type is VOID.
+//
+//*****************************************************************************
+
+
+
+LONG ThunkCallWndProcHook16(INT nCode, LONG wParam, VPVOID vpCwpStruct,
+ LPHOOKSTATEDATA lpHSData)
+{
+ CWPSTRUCT CwpStruct;
+ PCWPSTRUCT16 pCwpStruct16;
+ MSGPARAMEX mpex;
+
+ GETMISCPTR(vpCwpStruct, pCwpStruct16);
+
+ mpex.Parm16.WndProc.hwnd = pCwpStruct16->hwnd;
+ mpex.Parm16.WndProc.wMsg = pCwpStruct16->message;
+ mpex.Parm16.WndProc.wParam = pCwpStruct16->wParam;
+ mpex.Parm16.WndProc.lParam = pCwpStruct16->lParam,
+ mpex.iMsgThunkClass = WOWCLASS_UNKNOWN;
+
+ mpex.hwnd = ThunkMsg16(&mpex);
+ // memory may have moved
+ FREEVDMPTR(pCwpStruct16);
+
+ CwpStruct.message = mpex.uMsg;
+ CwpStruct.wParam = mpex.uParam;
+ CwpStruct.lParam = mpex.lParam;
+ CwpStruct.hwnd = mpex.hwnd;
+
+ mpex.lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam,
+ (LPARAM)&CwpStruct);
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ mpex.uMsg = CwpStruct.message;
+ mpex.uParam = CwpStruct.wParam;
+ mpex.lParam = CwpStruct.lParam;
+ (mpex.lpfnUnThunk16)(&mpex);
+ }
+
+ return mpex.lReturn;
+}
+
+
+//*****************************************************************************
+//
+// 16->32 ThunkHookProc for Hooks of type WH_CBT -
+//
+// Return type is BOOL.
+//
+//*****************************************************************************
+
+LONG ThunkCbtHook16(INT nCode, LONG wParam, VPVOID lParam,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn = FALSE;
+ WPARAM wParamNew;
+ LPARAM lParamNew;
+ MSGPARAMEX mpex;
+
+ PMOUSEHOOKSTRUCT16 pMHStruct16;
+ PCBTACTIVATESTRUCT16 pCbtAStruct16;
+ PCBT_CREATEWND16 pCbtCWnd16;
+
+ MOUSEHOOKSTRUCT MHStruct;
+ RECT Rect;
+ CBTACTIVATESTRUCT CbtAStruct;
+ CBT_CREATEWND CbtCWnd;
+
+ // SudeepB 28-May-1996
+ //
+ // Some apps like SureTrack project management package are passing
+ // corrupted values in lParam. GETMISCPTR returns 0 for such an lParam.
+ // Using this 0 on X86 causes corruption of IVT and on RISC causes an
+ // AV in wow32 as zero is not a valid linear address. Such apps get
+ // away from such criminal acts on win3.1/Win95 as no thunking is needed
+ // there. The below check separates out such cases and handles them in
+ // the simplest possible way without any thunking.
+
+ GETMISCPTR(lParam, pCbtCWnd16);
+ if (!pCbtCWnd16 ) {
+ lReturn = CallNextHookEx(lpHSData->hHook, nCode,
+ wParam, (LPARAM)lParam);
+ return (LONG)(BOOL)LOWORD(lReturn);
+ }
+
+ wParamNew = wParam;
+ lParamNew = lParam;
+
+ switch(nCode) {
+ case HCBT_MOVESIZE:
+ // wParam = HWND, lParam = LPRECT
+
+ wParamNew = (WPARAM)HWND32(wParam);
+ lParamNew = (LPARAM)&Rect;
+
+ GETRECT16(lParam, &Rect);
+
+ break;
+
+
+ case HCBT_MINMAX:
+ // wParam = HWND, lParam = SW_* --- a command
+
+ wParamNew = (WPARAM)HWND32(wParam);
+ break;
+
+ case HCBT_QS:
+
+ break;
+
+ case HCBT_CREATEWND:
+ // wParam = HWND, lParam = LPCBT_CREATEWND
+
+ lParamNew = (LPARAM)&CbtCWnd;
+
+ mpex.Parm16.WndProc.hwnd = LOWORD(wParam);
+ mpex.Parm16.WndProc.wMsg = WM_CREATE;
+ mpex.Parm16.WndProc.wParam = 0;
+ mpex.Parm16.WndProc.lParam = FETCHDWORD(pCbtCWnd16->vpcs);
+ mpex.iMsgThunkClass = 0;
+
+ ThunkMsg16(&mpex);
+
+ //
+ // Memory movement can occur on the 16-bit side.
+ //
+
+ FREEVDMPTR(pCbtCWnd16);
+ GETMISCPTR(lParam, pCbtCWnd16);
+
+ (LONG)CbtCWnd.lpcs = mpex.lParam;
+
+ wParamNew = (WPARAM)HWND32(wParam);
+ CbtCWnd.hwndInsertAfter =
+ HWNDIA32(FETCHWORD(pCbtCWnd16->hwndInsertAfter));
+
+ FREEVDMPTR(pCbtCWnd16);
+
+ break;
+
+ case HCBT_DESTROYWND:
+
+ // wParam = HWND, lParam = 0
+
+ wParamNew = (WPARAM)HWND32(wParam);
+ break;
+
+ case HCBT_ACTIVATE:
+
+ // wParam = HWND, lParam = LPCBTACTIVATESTRUCT
+
+ wParamNew = (WPARAM)HWND32(wParam);
+ lParamNew = (LPARAM)&CbtAStruct;
+
+ GETMISCPTR(lParam, pCbtAStruct16);
+ GETCBTACTIVATESTRUCT16(pCbtAStruct16, &CbtAStruct);
+ FREEVDMPTR(pCbtAStruct16);
+
+ break;
+
+ case HCBT_CLICKSKIPPED:
+
+ // wParam = mouse message, lParam = LPMOUSEHOOKSTRUCT
+
+ lParamNew = (LPARAM)&MHStruct;
+
+ GETMISCPTR(lParam, pMHStruct16);
+ GETMOUSEHOOKSTRUCT16(pMHStruct16, &MHStruct);
+ FREEVDMPTR(pMHStruct16);
+ break;
+
+ case HCBT_KEYSKIPPED:
+
+ // wParam, lParam -- keyup/down message params
+
+ break;
+
+ case HCBT_SYSCOMMAND:
+
+ // wParam = SC_ syscomand, lParam = DWORD(x,y)
+
+ break;
+
+ case HCBT_SETFOCUS:
+
+ // wParam = HWND, lParam = HWND
+
+ wParamNew = (WPARAM)HWND32(wParam);
+ lParamNew = (WPARAM)HWND32(lParam);
+ break;
+
+ default:
+ LOGDEBUG(LOG_ALWAYS, ("ThunkCbtHook: Unknown HCBT_ code\n"));
+ break;
+ }
+
+
+ lReturn = CallNextHookEx(lpHSData->hHook, nCode,
+ wParamNew, (LPARAM)lParamNew);
+
+ switch(nCode) {
+ case HCBT_MOVESIZE:
+
+ PUTRECT16(lParam, (LPRECT)lParamNew);
+ break;
+
+ case HCBT_CREATEWND:
+ GETMISCPTR(lParam, pCbtCWnd16);
+ mpex.lParam = (LONG)CbtCWnd.lpcs;
+ mpex.lReturn = lReturn;
+ WOW32ASSERT(MSG16NEEDSTHUNKING(&mpex));
+ (mpex.lpfnUnThunk16)(&mpex);
+ lReturn = mpex.lReturn;
+
+ STOREWORD(pCbtCWnd16->hwndInsertAfter,
+ GETHWNDIA16(((LPCBT_CREATEWND)lParamNew)->
+ hwndInsertAfter));
+ FLUSHVDMPTR((VPVOID)lParam, sizeof(CBT_CREATEWND16), pCbtCWnd16);
+ FREEVDMPTR(pCbtCWnd16);
+ break;
+
+
+ case HCBT_ACTIVATE:
+
+ GETMISCPTR(lParam, pCbtAStruct16);
+ PUTCBTACTIVATESTRUCT16(pCbtAStruct16, (LPCBTACTIVATESTRUCT)lParamNew);
+ FLUSHVDMPTR((VPVOID)lParam, sizeof(CBTACTIVATESTRUCT16),
+ pCbtAStruct16);
+ FREEVDMPTR(pCbtAStruct16);
+ break;
+
+ case HCBT_CLICKSKIPPED:
+
+ GETMISCPTR(lParam, pMHStruct16);
+ PUTMOUSEHOOKSTRUCT16(pMHStruct16, (LPMOUSEHOOKSTRUCT)lParamNew);
+ FLUSHVDMPTR((VPVOID)lParam, sizeof(MOUSEHOOKSTRUCT16),
+ pMHStruct16);
+ FREEVDMPTR(pMHStruct16);
+ break;
+
+ // case HCBT_MINMAX:
+ // case HCBT_QS:
+ // case HCBT_DESTROYWND:
+ // case HCBT_KEYSKIPPED:
+ // case HCBT_SYSCOMMAND:
+ // case HCBT_SETFOCUS:
+
+ default:
+ break;
+ }
+
+ // the value in LOWORD is the valid return value
+
+ return (LONG)(BOOL)LOWORD(lReturn);
+}
+
+
+
+//*****************************************************************************
+//
+// 16->32 ThunkHookProc for Hooks of type WH_KEYBOARD -
+//
+// Return type is BOOL.
+//
+//*****************************************************************************
+
+LONG ThunkKeyBoardHook16(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn;
+
+ lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam,
+ (LPARAM)lParam);
+
+ // the value in LOWORD is the valid return value
+
+ return (LONG)(BOOL)LOWORD(lReturn);
+}
+
+
+
+//*****************************************************************************
+//
+// 16->32 ThunkHookProc for Hooks of type WH_GETMESSAGE -
+// WH_MSGFILTER -
+// WH_SYSMSGFILTER -
+//
+// Return type is BOOL.
+//
+//*****************************************************************************
+
+LONG ThunkMsgFilterHook16(INT nCode, LONG wParam, VPVOID vpMsg,
+ LPHOOKSTATEDATA lpHSData)
+{
+ PMSG16 pMsg16;
+ MSG Msg;
+ MSGPARAMEX mpex;
+
+
+
+ GETMISCPTR(vpMsg, pMsg16);
+
+ fThunkDDEmsg = FALSE;
+
+ mpex.Parm16.WndProc.hwnd = pMsg16->hwnd;
+ mpex.Parm16.WndProc.wMsg = pMsg16->message;
+ mpex.Parm16.WndProc.wParam = pMsg16->wParam;
+ mpex.Parm16.WndProc.lParam = pMsg16->lParam;
+ mpex.iMsgThunkClass = 0;
+
+ ThunkMsg16(&mpex);
+
+ //
+ // Memory movement can occur on the 16-bit side.
+ //
+
+ FREEVDMPTR(pMsg16);
+ GETMISCPTR(vpMsg, pMsg16);
+
+ fThunkDDEmsg = TRUE;
+
+ Msg.message = mpex.uMsg;
+ Msg.wParam = mpex.uParam;
+ Msg.lParam = mpex.lParam;
+ Msg.hwnd = HWND32(FETCHWORD(pMsg16->hwnd));
+ Msg.time = FETCHLONG(pMsg16->time);
+ Msg.pt.x = FETCHSHORT(pMsg16->pt.x);
+ Msg.pt.y = FETCHSHORT(pMsg16->pt.y);
+
+ FREEVDMPTR(pMsg16);
+
+ mpex.lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam,
+ (LPARAM)&Msg);
+ GETMISCPTR(vpMsg, pMsg16);
+
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ mpex.uMsg = Msg.message;
+ mpex.uParam = Msg.wParam;
+ mpex.lParam = Msg.lParam;
+ (mpex.lpfnUnThunk16)(&mpex);
+ GETMISCPTR(vpMsg, pMsg16);
+ }
+
+ STORELONG(pMsg16->time, Msg.time);
+ STOREWORD(pMsg16->pt.x, Msg.pt.x);
+ STOREWORD(pMsg16->pt.y, Msg.pt.y);
+
+ FLUSHVDMPTR(vpMsg, sizeof(MSG16), pMsg16);
+ FREEVDMPTR(pMsg16);
+
+ // the value in LOWORD is the valid return value
+
+ return (LONG)(BOOL)LOWORD(mpex.lReturn);
+}
+
+
+
+//*****************************************************************************
+//
+// 16->32 ThunkHookProc for Hooks of type WH_JOURNALPLAYBACK -
+// WH_JOUNRALRECORD -
+//
+// Return type is DWORD.
+//
+//*****************************************************************************
+
+LONG ThunkJournalHook16(INT nCode, LONG wParam, VPVOID vpEventMsg,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn;
+ PEVENTMSG16 pEventMsg16;
+ EVENTMSG EventMsg;
+ LPEVENTMSG lpEventMsg;
+
+ if ( vpEventMsg ) {
+
+
+ // The WIN32 EVENTMSG structure has an additional field 'hwnd', which
+ // is not there in WIN31 EVENTMSG structure. This field can be ignored
+ // without any repercussions.
+
+ if (lpHSData->iHook == WH_JOURNALRECORD) {
+ GETMISCPTR(vpEventMsg, pEventMsg16);
+ GetEventMessage16(pEventMsg16, &EventMsg);
+ EventMsg.hwnd = (HWND)0;
+ FREEVDMPTR(pEventMsg16);
+ }
+ lpEventMsg = &EventMsg;
+
+
+ } else {
+ lpEventMsg = NULL;
+ }
+
+
+ lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam, (LPARAM)lpEventMsg );
+
+ if ( vpEventMsg ) {
+
+ if (lpHSData->iHook == WH_JOURNALPLAYBACK) {
+ GETMISCPTR(vpEventMsg, pEventMsg16);
+ PUTEVENTMSG16(pEventMsg16, &EventMsg);
+ FLUSHVDMPTR(vpEventMsg, sizeof(EVENTMSG16), pEventMsg16);
+ FREEVDMPTR(pEventMsg16);
+ }
+
+ }
+
+ return lReturn;
+}
+
+
+
+//*****************************************************************************
+//
+// 16->32 ThunkHookProc for Hooks of type WH_DEBUG -
+//
+// Return type is BOOL.
+//
+//*****************************************************************************
+
+LONG ThunkDebugHook16(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn;
+
+ lReturn = TRUE;
+
+ UNREFERENCED_PARAMETER(nCode);
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+ UNREFERENCED_PARAMETER(lpHSData);
+
+ LOGDEBUG(LOG_ALWAYS, ("ThunkDebugHook16:Not implemented.\n"));
+
+ // the value in LOWORD is the valid return value
+
+ return (LONG)(BOOL)LOWORD(lReturn);
+}
+
+
+
+//*****************************************************************************
+//
+// 16->32 ThunkHookProc for Hooks of type WH_MOUSE -
+//
+// Return type is BOOL.
+//
+//*****************************************************************************
+
+LONG ThunkMouseHook16(INT nCode, LONG wParam, VPVOID vpMHStruct,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn;
+ PMOUSEHOOKSTRUCT16 pMHStruct16;
+ MOUSEHOOKSTRUCT MHStruct;
+
+ GETMISCPTR(vpMHStruct, pMHStruct16);
+ GETMOUSEHOOKSTRUCT16(pMHStruct16, &MHStruct);
+ FREEVDMPTR(pMHStruct16);
+
+ lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam,
+ (LPARAM)&MHStruct);
+
+ GETMISCPTR(vpMHStruct, pMHStruct16);
+ PUTMOUSEHOOKSTRUCT16(pMHStruct16, &MHStruct);
+ FLUSHVDMPTR((VPVOID)vpMHStruct, sizeof(MOUSEHOOKSTRUCT16), pMHStruct16);
+ FREEVDMPTR(pMHStruct16);
+
+ return (LONG)(BOOL)LOWORD(lReturn);
+}
+
+
+
+//*****************************************************************************
+//
+// 16->32 ThunkHookProc for Hooks of type WH_SHELL -
+//
+// Return value is apparently zero.
+//
+//*****************************************************************************
+
+LONG ThunkShellHook16(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData)
+{
+ LONG lReturn;
+
+ switch (nCode) {
+ case HSHELL_WINDOWCREATED:
+ case HSHELL_WINDOWDESTROYED:
+ wParam = (LONG)HWND32(wParam);
+ break;
+
+ case HSHELL_ACTIVATESHELLWINDOW:
+ // fall thru
+
+ default:
+ break;
+ }
+
+ lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam,
+ (LPARAM)lParam);
+
+ // lReturn = 0?
+
+ return (LONG)lReturn;
+}
+
+
+//*****************************************************************************
+// W32GetHookDDEMsglParam:
+//
+// Returns the lParam of the actual hook message. called for dde messages
+// only. returns valid lParam else 0.
+//
+//*****************************************************************************
+
+
+DWORD W32GetHookDDEMsglParam()
+{
+ INT iFunc;
+ LONG lParam;
+
+ iFunc = viCurrentHookStateDataIndex;
+ lParam = vHookParams.lParam;
+
+ if (lParam) {
+ switch (vaHookStateData[iFunc].iHook) {
+ case WH_CALLWNDPROC:
+ lParam = ((LPCWPSTRUCT)lParam)->lParam;
+ break;
+
+ case WH_MSGFILTER:
+ case WH_SYSMSGFILTER:
+ case WH_GETMESSAGE:
+ lParam = ((LPMSG)lParam)->lParam;
+ break;
+
+ default:
+ lParam = 0;
+ }
+ }
+
+ return lParam;
+
+}
+
+//*****************************************************************************
+// GetEventMessage16:
+//
+//*****************************************************************************
+
+
+VOID GetEventMessage16(PEVENTMSG16 pEventMsg16, LPEVENTMSG lpEventMsg)
+{
+ lpEventMsg->message = FETCHWORD(pEventMsg16->message);
+ lpEventMsg->time = FETCHLONG(pEventMsg16->time);
+ if ((lpEventMsg->message >= WM_KEYFIRST) && (lpEventMsg->message <= WM_KEYLAST)) {
+ // Key event
+ lpEventMsg->paramL = FETCHWORD(pEventMsg16->paramL);
+ lpEventMsg->paramH = FETCHWORD(pEventMsg16->paramH) & 0x8000;
+ lpEventMsg->paramH |= (lpEventMsg->paramL & 0xFF00) >> 8;
+ lpEventMsg->paramL &= 0xFF;
+ }
+ else {
+ // Mouse event
+ lpEventMsg->paramL = FETCHWORD(pEventMsg16->paramL);
+ lpEventMsg->paramH = FETCHWORD(pEventMsg16->paramH);
+ }
+}
diff --git a/private/mvdm/wow32/wowhooks.h b/private/mvdm/wow32/wowhooks.h
new file mode 100644
index 000000000..d36a4a8bf
--- /dev/null
+++ b/private/mvdm/wow32/wowhooks.h
@@ -0,0 +1,185 @@
+//*****************************************************************************
+//
+// HOOKS -
+//
+// Header file for 32bit stubs and thunks of 16bit hooks
+//
+//
+// 01-07-92 NanduriR Created.
+//
+//*****************************************************************************
+
+typedef LONG (APIENTRY *HKPROC)(INT, LONG, LONG);
+
+typedef struct {
+ HANDLE hMod; // Module handle
+ INT cHookProcs; // Total Number of thunk stubs.
+} HOOKPERPROCESSDATA, FAR *LPHOOKPERPROCESSDATA;
+
+typedef struct {
+ BYTE iIndex; // array index;
+ BYTE InUse; // TRUE if this Proc32 is already hooked
+ HAND16 hMod16; // 16bit HookDLL module handle
+ HANDLE hMod; // Modulehande of Thunk Hook Dll
+ HKPROC Proc32; // 32bit HookProc stub
+ INT iHook; // type of Hook
+ DWORD Proc16; // actual 16bit HookProc
+ INT TaskId; // id of task that callled setwindowshook
+ HHOOK hHook; // handle returned by SetWindowHookEx
+} HOOKSTATEDATA, FAR *LPHOOKSTATEDATA;
+
+typedef struct {
+ INT nCode; // the input params to a hook func.
+ LONG wParam;
+ LONG lParam;
+} HOOKPARAMS, FAR *LPHOOKPARAMS;
+
+#define PUTMSGFILTER16(pMsg16,lpMsg) {\
+ STOREWORD(pMsg16->hwnd, GETHWND16((lpMsg)->hwnd));\
+ STOREWORD(pMsg16->message, (lpMsg)->message);\
+ STOREWORD(pMsg16->wParam, (lpMsg)->wParam);\
+ STORELONG(pMsg16->lParam, (lpMsg)->lParam);\
+ STORELONG(pMsg16->time, (lpMsg)->time);\
+ STOREWORD(pMsg16->pt.x, (lpMsg)->pt.x);\
+ STOREWORD(pMsg16->pt.y, (lpMsg)->pt.y);\
+ }
+
+#define GETMSGFILTER16(pMsg16,lpMsg) {\
+ (lpMsg)->hwnd = HWND32(FETCHWORD(pMsg16->hwnd));\
+ (lpMsg)->message = FETCHWORD(pMsg16->message);\
+ (lpMsg)->wParam = FETCHWORD(pMsg16->wParam);\
+ (lpMsg)->lParam = FETCHLONG(pMsg16->lParam);\
+ (lpMsg)->time = FETCHLONG(pMsg16->time);\
+ (lpMsg)->pt.x = FETCHSHORT(pMsg16->pt.x);\
+ (lpMsg)->pt.y = FETCHSHORT(pMsg16->pt.y);\
+ }
+
+#define PUTMOUSEHOOKSTRUCT16(pMHStruct16,lpMHStruct) {\
+ STOREWORD(pMHStruct16->pt.x, (lpMHStruct)->pt.x);\
+ STOREWORD(pMHStruct16->pt.y, (lpMHStruct)->pt.y);\
+ STOREWORD(pMHStruct16->hwnd, GETHWND16((lpMHStruct)->hwnd));\
+ STOREWORD(pMHStruct16->wHitTestCode, (lpMHStruct)->wHitTestCode);\
+ STORELONG(pMHStruct16->dwExtraInfo, (lpMHStruct)->dwExtraInfo);\
+ }
+
+
+#define GETMOUSEHOOKSTRUCT16(pMHStruct16,lpMHStruct) {\
+ (lpMHStruct)->pt.x = FETCHSHORT(pMHStruct16->pt.x);\
+ (lpMHStruct)->pt.y = FETCHSHORT(pMHStruct16->pt.y);\
+ (lpMHStruct)->hwnd = HWND32(FETCHWORD(pMHStruct16->hwnd));\
+ (lpMHStruct)->wHitTestCode = FETCHWORD(pMHStruct16->wHitTestCode);\
+ (lpMHStruct)->dwExtraInfo = FETCHLONG(pMHStruct16->dwExtraInfo);\
+ }
+
+
+// afterdark 3.0 compares the t1=lpeventmsg->time with t2=getcurrenttime().
+// physically t2 > t1 always - we truncate t2 to a multiple of 64 and
+// thus sometimes t2 < t1 (numerically) which confuses the app and
+// triggers the screen saver. So we do identical truncation here.
+// No compatibility flag is used
+// - nanduri
+
+#define PUTEVENTMSG16(pEventMsg16,lpEventMsg) {\
+ STOREWORD(pEventMsg16->message, (lpEventMsg)->message);\
+ STOREWORD(pEventMsg16->paramL, (lpEventMsg)->paramL);\
+ STOREWORD(pEventMsg16->paramH, (lpEventMsg)->paramH);\
+ STORELONG(pEventMsg16->time, GRAINYTICS((lpEventMsg)->time));\
+ }
+
+
+#define PUTCBTACTIVATESTRUCT16(pCbtAStruct16,lpCbtAStruct) {\
+ STOREWORD(pCbtAStruct16->fMouse, (lpCbtAStruct)->fMouse);\
+ STOREWORD(pCbtAStruct16->hWndActive, (GETHWND16((lpCbtAStruct)->hWndActive)));\
+ }
+
+
+#define GETCBTACTIVATESTRUCT16(pCbtAStruct16,lpCbtAStruct) {\
+ (lpCbtAStruct)->fMouse = FETCHWORD(pCbtAStruct16->fMouse);\
+ (lpCbtAStruct)->hWndActive = HWND32(FETCHWORD(pCbtAStruct16->hWndActive));\
+ }
+
+
+LONG APIENTRY WU32StdHookProc(INT nCode, LONG wParam, LONG lParam, INT iFunc);
+LONG APIENTRY WU32SubStdHookProc01(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc02(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc03(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc04(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc05(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc06(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc07(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc08(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc09(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc10(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc11(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc12(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc13(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc14(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc15(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc16(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc17(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc18(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc19(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc20(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc21(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc22(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc23(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc24(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc25(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc26(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc27(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc28(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc29(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc30(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc31(INT nCode, LONG wParam, LONG lParam);
+LONG APIENTRY WU32SubStdHookProc32(INT nCode, LONG wParam, LONG lParam);
+
+BOOL W32InitHookState(HANDLE hMod);
+BOOL W32GetNotInUseHookStateData(LPHOOKSTATEDATA lpData);
+BOOL W32GetHookStateData(LPHOOKSTATEDATA lpData);
+BOOL W32SetHookStateData(LPHOOKSTATEDATA lpData);
+BOOL W32GetThunkHookProc(INT iHook, DWORD Proc16, LPHOOKSTATEDATA lpData);
+HHOOK W32FreeHHook(INT iHook, DWORD Proc16);
+HHOOK W32FreeHHookOfIndex(INT iFunc);
+BOOL W32GetHookParams(LPHOOKPARAMS lpHookParams);
+LONG ThunkCallWndProcHook(INT nCode, LONG wParam, LPCWPSTRUCT lpCwpStruct,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkCbtHook(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkKeyBoardHook(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkMsgFilterHook(INT nCode, LONG wParam, LPMSG lpMsg,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkJournalHook(INT nCode, LONG wParam, LPEVENTMSG lpEventMsg,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkDebugHook(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkMouseHook(INT nCode, LONG wParam, LPMOUSEHOOKSTRUCT lpMHStruct,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkShellHook(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData);
+
+
+LONG APIENTRY WU32StdDefHookProc(INT nCode, LONG wParam, LONG lParam, INT iFunc);
+VOID W32UnhookHooks( HAND16 hMod16, BOOL fQueue );
+BOOL W32FreeOwnedHooks(INT iTaskId);
+INT W32IsDuplicateHook(INT iHook, DWORD Proc16, INT TaskId);
+
+LONG ThunkCallWndProcHook16(INT nCode, LONG wParam, VPVOID lpCwpStruct,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkCbtHook16(INT nCode, LONG wParam, VPVOID lParam,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkKeyBoardHook16(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkMsgFilterHook16(INT nCode, LONG wParam, VPVOID lpMsg,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkJournalHook16(INT nCode, LONG wParam, VPVOID lpEventMsg,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkDebugHook16(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkMouseHook16(INT nCode, LONG wParam, VPVOID lpMHStruct,
+ LPHOOKSTATEDATA lpHSData);
+LONG ThunkShellHook16(INT nCode, LONG wParam, LONG lParam,
+ LPHOOKSTATEDATA lpHSData);
+DWORD W32GetHookDDEMsglParam(VOID);
+VOID GetEventMessage16(PEVENTMSG16 pEventMsg16, LPEVENTMSG lpEventMsg);
+
diff --git a/private/mvdm/wow32/wowtable.h b/private/mvdm/wow32/wowtable.h
new file mode 100644
index 000000000..fb70f41fe
--- /dev/null
+++ b/private/mvdm/wow32/wowtable.h
@@ -0,0 +1,21 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, 1992, 1993 Microsoft Corporation
+ *
+ * WOWTABLE.H
+ * WOW32 API thunk table
+ *
+--*/
+
+
+
+/* thunk table
+ */
+extern W32 aw32WOW[];
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT cAPIThunks;
+#endif
diff --git a/private/mvdm/wow32/wowtbl.c b/private/mvdm/wow32/wowtbl.c
new file mode 100644
index 000000000..6f4ef6606
--- /dev/null
+++ b/private/mvdm/wow32/wowtbl.c
@@ -0,0 +1,260 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, 1992, 1993 Microsoft Corporation
+ *
+ * WOWTBL.C
+ * WOW32 API thunks
+ *
+ * The reason for having one huge table is so the thunks can be dispatched
+ * faster. When in separate tables, you had to do shifting and
+ * multiplication to derive the thunk routine from the function ID.
+ *
+ *
+ * History:
+ * barry bradie (barryb) 1-dec-92 combined individual tables
+--*/
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+
+
+
+
+
+
+
+
+
+MODNAME(wowtbl.c);
+
+//
+// DON'T CHANGE THE ORDER IN WHICH THESE FILES ARE INCLUDED!
+//
+// see W32GetTableOffsets (wow32.c) and kernel31\kdata.asm
+//
+
+W32 aw32WOW[] = {
+
+#include "wktbl2.h"
+ {W32FUN((LPFNW32)-1, "TABLESEPARATOR", 0, 0)},
+
+#include "wutbl2.h"
+ {W32FUN((LPFNW32)-1, "TABLESEPARATOR", 0, 0)},
+
+#include "wgtbl2.h"
+ {W32FUN((LPFNW32)-1, "TABLESEPARATOR", 0, 0)},
+
+#include "wkbdtbl2.h"
+ {W32FUN((LPFNW32)-1, "TABLESEPARATOR", 0, 0)},
+
+#include "wstbl2.h"
+ {W32FUN((LPFNW32)-1, "TABLESEPARATOR", 0, 0)},
+
+#include "wshtbl2.h"
+ {W32FUN((LPFNW32)-1, "TABLESEPARATOR", 0, 0)},
+
+#include "wwstbl2.h"
+ {W32FUN((LPFNW32)-1, "TABLESEPARATOR", 0, 0)},
+
+#include "wthtbl2.h"
+ {W32FUN((LPFNW32)-1, "TABLESEPARATOR", 0, 0)},
+
+#include "wmmtbl2.h"
+ {W32FUN((LPFNW32)-1, "TABLESEPARATOR", 0, 0)},
+
+#include "wcmdgtbl.h"
+ {W32FUN((LPFNW32)-1, "TABLESEPARATOR", 0, 0)}
+};
+
+
+TABLEOFFSETS tableoffsets;
+
+#ifdef DEBUG_OR_WOWPROFILE
+INT cAPIThunks;
+#endif
+
+#ifdef WOWPROFILE
+PW32 pawThunkTable = aw32WOW;
+#endif
+
+
+VOID InitThunkTableOffsets(VOID)
+{
+ UINT current;
+ WORD offsetarray[(MOD_LAST - MOD_KERNEL) / FUN_MASK + 1];
+ UINT i;
+
+ for (current = 0; current < sizeof(aw32WOW)/sizeof(aw32WOW[0]); current++) {
+ if (current == 0) {
+ i = 0;
+ offsetarray[i++] = current;
+ }
+ else if (aw32WOW[current].lpfnW32 == (LPFNW32)-1) {
+ offsetarray[i++] = current + 1;
+ }
+
+ }
+ tableoffsets.kernel =
+ tableoffsets.dkernel = offsetarray[MOD_KERNEL / FUN_MASK];
+ tableoffsets.user =
+ tableoffsets.duser = offsetarray[MOD_USER / FUN_MASK];
+ tableoffsets.gdi =
+ tableoffsets.dgdi = offsetarray[MOD_GDI / FUN_MASK];
+ tableoffsets.keyboard = offsetarray[MOD_KEYBOARD / FUN_MASK];
+ tableoffsets.sound = offsetarray[MOD_SOUND / FUN_MASK];
+ tableoffsets.shell = offsetarray[MOD_SHELL / FUN_MASK];
+ tableoffsets.winsock = offsetarray[MOD_WINSOCK / FUN_MASK];
+ tableoffsets.toolhelp = offsetarray[MOD_TOOLHELP / FUN_MASK];
+ tableoffsets.mmedia = offsetarray[MOD_MMEDIA / FUN_MASK];
+ tableoffsets.commdlg = offsetarray[MOD_COMMDLG / FUN_MASK];
+
+#ifdef DEBUG_OR_WOWPROFILE
+ cAPIThunks = sizeof(aw32WOW) / sizeof(aw32WOW[0]);
+#endif
+
+}
+
+
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+
+INT ModFromCallID(INT iFun)
+{
+ PTABLEOFFSETS pto = &tableoffsets;
+
+ if (iFun < pto->user)
+ return MOD_KERNEL;
+
+ if (iFun < pto->gdi)
+ return MOD_USER;
+
+ if (iFun < pto->keyboard)
+ return MOD_GDI;
+
+ if (iFun < pto->sound)
+ return MOD_KEYBOARD;
+
+ if (iFun < pto->shell)
+ return MOD_SOUND;
+
+ if (iFun < pto->winsock)
+ return MOD_SHELL;
+
+ if (iFun < pto->toolhelp)
+ return MOD_WINSOCK;
+
+ if (iFun < pto->mmedia)
+ return MOD_TOOLHELP;
+
+ if (iFun < pto->commdlg) {
+ return(MOD_MMEDIA);
+ }
+
+ if (iFun < cAPIThunks)
+ return MOD_COMMDLG;
+
+ return -1;
+}
+
+
+
+PSZ apszModNames[] = { "Kernel",
+ "User",
+ "Gdi",
+ "Keyboard",
+ "Sound",
+ "Shell",
+ "Winsock",
+ "Toolhelp",
+ "MMedia",
+ "Commdlg"
+ };
+
+INT nModNames = NUMEL(apszModNames);
+
+PSZ GetModName(INT iFun)
+{
+ INT nMod;
+
+ nMod = ModFromCallID(iFun);
+
+ if (nMod == -1) {
+ return "BOGUS!!";
+ }
+
+ nMod = nMod >> 12; // get the value into the low byte
+
+ return apszModNames[nMod];
+
+}
+
+INT GetOrdinal(INT iFun)
+{
+ INT nMod;
+
+ nMod = ModFromCallID(iFun);
+
+ if (nMod == -1) {
+ return 0;
+ }
+
+ return (iFun - TableOffsetFromName(apszModNames[nMod >> 12]));
+
+}
+
+INT TableOffsetFromName(PSZ szTab)
+{
+ INT i;
+ PTABLEOFFSETS pto = &tableoffsets;
+
+ for (i = 0; i < NUMEL(apszModNames); i++) {
+ if (!strcmp(szTab, apszModNames[i]))
+ break;
+ }
+
+ if (i >= NUMEL(apszModNames))
+ return 0;
+
+ switch (i << 12) {
+
+ case MOD_KERNEL:
+ return pto->kernel;
+
+ case MOD_USER:
+ return pto->user;
+
+ case MOD_DGDI:
+ return pto->gdi;
+
+ case MOD_KEYBOARD:
+ return pto->keyboard;
+ case MOD_SOUND:
+ return pto->sound;
+
+ case MOD_SHELL:
+ return pto->shell;
+
+ case MOD_WINSOCK:
+ return pto->winsock;
+
+ case MOD_TOOLHELP:
+ return pto->toolhelp;
+
+ case MOD_MMEDIA:
+ return pto->mmedia;
+
+ case MOD_COMMDLG:
+ return(pto->commdlg);
+
+ default:
+ return(-1);
+ }
+
+}
+
+#endif
diff --git a/private/mvdm/wow32/wowtbl.h b/private/mvdm/wow32/wowtbl.h
new file mode 100644
index 000000000..efc7312a7
--- /dev/null
+++ b/private/mvdm/wow32/wowtbl.h
@@ -0,0 +1,58 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, 1992, 1993 Microsoft Corporation
+ *
+ * WOWTBL.H
+ * WOW32 API thunk table
+ *
+--*/
+
+
+
+/* thunk table
+ */
+extern W32 aw32WOW[];
+
+
+//
+// the order of these must not change! see kernel31\kdata.asm
+//
+typedef struct {
+ WORD kernel;
+ WORD dkernel;
+ WORD user;
+ WORD duser;
+ WORD gdi;
+ WORD dgdi;
+ WORD keyboard;
+ WORD sound;
+ WORD shell;
+ WORD winsock;
+ WORD toolhelp;
+ WORD mmedia;
+ WORD commdlg;
+} TABLEOFFSETS;
+typedef TABLEOFFSETS UNALIGNED *PTABLEOFFSETS;
+
+
+VOID InitThunkTableOffsets(VOID);
+
+extern TABLEOFFSETS tableoffsets;
+
+#ifdef DEBUG_OR_WOWPROFILE
+
+extern PSZ apszModNames[];
+extern INT nModNames;
+extern INT cAPIThunks;
+
+
+
+INT ModFromCallID(INT iFun);
+PSZ GetModName(INT iFun);
+INT GetOrdinal(INT iFun);
+INT TableOffsetFromName(PSZ szTab);
+
+
+#endif
diff --git a/private/mvdm/wow32/wparam.c b/private/mvdm/wow32/wparam.c
new file mode 100644
index 000000000..6727b02af
--- /dev/null
+++ b/private/mvdm/wow32/wparam.c
@@ -0,0 +1,666 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1996, Microsoft Corporation
+ *
+ * WPARAM.C
+ *
+ * Created: VadimB
+ * Added cache VadimB
+ *
+-*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wparam.c);
+
+///////////////////////////////////////////////////////////////////////////
+// Some defines
+
+
+// Pre-allocated cache size for nodes
+#define MAPCACHESIZE 0x1000 // 4K
+
+// max "pointer movements" allowed per mapping
+#define MAXNODEALIAS 0x10 // 16 aliases max
+ // (never ever seen more then 2 used)
+
+// macro to generate the number of elements in array
+#define ARRAYCOUNT(array) (sizeof(array)/sizeof((array)[0]))
+
+// This define will enable code that allows for keeping 32-bit buffers
+// allocated and integrated with nodes in cache
+// #define MAPPARAM_EXTRA
+
+
+///////////////////////////////////////////////////////////////////////////
+typedef struct tagParamNode* LPPARAMNODE;
+
+typedef struct tagParamNode {
+ LPPARAMNODE pNext;
+
+ DWORD dwPtr32; // flat pointer
+ DWORD dwPtr16;
+ DWORD dwFlags; // flags just in case
+ DWORD dwRefCount; // reference count
+
+#ifdef MAPPARAM_EXTRA
+ DWORD cbExtra; // buffer size
+#endif
+
+ DWORD nAliasCount; // index for an alias array
+ DWORD rgdwAlias[MAXNODEALIAS];
+
+ // word sized member of the struct -- alignment alert
+ HAND16 htask16; // this is HAND16 really - keep simple and aligned
+
+} PARAMNODE, *LPPARAMNODE;
+
+typedef struct tagMapParam {
+
+ LPPARAMNODE pHead;
+
+ BLKCACHE blkCache;
+
+} MAPPARAM, *LPMAPPARAM;
+
+typedef struct tagFindParam {
+ LPPARAMNODE lpNode;
+ LPPARAMNODE lpLast;
+} FINDPARAM, *LPFINDPARAM;
+
+MAPPARAM gParamMap;
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// FindParamMap
+// Finds lParam in a list assuming it is 16-bit (fMode == PARAM_16) or
+// 32-bit flat (fMode == PARAM_32) pointer
+//
+// lpFindParam should be NULL or point to a valid FINDPARAM structure
+//
+
+
+DWORD FindParamMap(VOID* lpFindParam, DWORD lParam, UINT fMode)
+{
+ LPPARAMNODE lpn = gParamMap.pHead;
+ LPPARAMNODE lplast = NULL;
+ DWORD dwRet = 0;
+ BOOL fFound = FALSE;
+
+ switch(fMode) {
+
+ case PARAM_16:
+ while (NULL != lpn) {
+ if (lParam == lpn->dwPtr16) {
+ dwRet = lpn->dwPtr32;
+ break;
+ }
+ lplast = lpn;
+ lpn = lpn->pNext;
+ }
+ break;
+
+ case PARAM_32:
+ // We are looking for a 32-bit pointer
+ // cases:
+ // - exact match
+ // - no match because ptr has moved (ouch!)
+
+ while (NULL != lpn) {
+
+ INT i;
+
+ if (lParam == lpn->dwPtr32) {
+ fFound = TRUE;
+ }
+ else
+ if (lParam == (DWORD)GetPModeVDMPointer(lpn->dwPtr16, 0)) {
+ LOGDEBUG(LOG_ALWAYS,
+ ("WPARAM: Pointer has moved: 16:16 @%lx was 32 @%lx now @%lx\n",
+ lpn->dwPtr16, lpn->dwPtr32, lParam));
+ fFound = TRUE;
+ }
+ else {
+
+ // look through the list of aliases
+
+ for (i = 0; i < (INT)lpn->nAliasCount; ++i) {
+ if (lpn->rgdwAlias[i] == lParam) {
+ fFound = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (fFound) { // we found alias one way or the other...
+ dwRet = lpn->dwPtr16;
+ break;
+ }
+
+
+ lplast = lpn;
+ lpn = lpn->pNext;
+ }
+ break;
+ }
+
+ if (lpn) {
+ LPFINDPARAM lpfp = (LPFINDPARAM)lpFindParam;
+ lpfp->lpNode = lpn;
+ lpfp->lpLast = lplast;
+ }
+
+ return dwRet;
+}
+
+//
+// Find 32-bit param and return 16-bit equivalent
+//
+//
+
+
+DWORD GetParam16(DWORD dwParam32)
+{
+ FINDPARAM fp;
+ DWORD dwParam16;
+
+ dwParam16 = FindParamMap(&fp, dwParam32, PARAM_32);
+ if (dwParam16) {
+ ++fp.lpNode->dwRefCount;
+ }
+
+ return dwParam16;
+}
+
+
+//
+// Typically this is called either from a thunk for an api or from
+// 16->32 thunk for a message
+//
+// dwPtr32 most often is obtained by GETPSZPTR or GetPModeVdmPointer
+//
+//
+
+PVOID AddParamMap(DWORD dwPtr32, DWORD dwPtr16)
+{
+ LPPARAMNODE lpn;
+ FINDPARAM fp;
+
+ // see if it's there already
+ if (FindParamMap(&fp, dwPtr16, PARAM_16)) {
+
+ lpn = fp.lpNode; // a bit faster ref
+
+ ++lpn->dwRefCount; // increase ref count
+
+ ParamMapUpdateNode(dwPtr32, PARAM_32, lpn); // just update the node
+ }
+ else {
+ if (NULL != (lpn = CacheBlockAllocate(&gParamMap.blkCache, sizeof(*lpn)))) {
+ lpn->dwPtr32 = dwPtr32;
+ lpn->dwPtr16 = dwPtr16;
+ lpn->pNext = gParamMap.pHead;
+ lpn->dwRefCount = 1;
+#ifdef MAPPARAM_EXTRA
+ lpn->cbExtra = 0;
+#endif
+ lpn->nAliasCount = 0;
+ lpn->htask16 = CURRENTPTD()->htask16;
+ gParamMap.pHead = lpn;
+ }
+ }
+
+ return lpn ? (PVOID)lpn->dwPtr32 : NULL;
+}
+
+#ifdef MAPPARAM_EXTRA
+
+PVOID AddParamMapEx(DWORD dwPtr16, DWORD cbExtra)
+{
+ LPPARAMNODE lpn;
+ FINDPARAM fp;
+
+ // see if it's there already
+ if (FindParamMap(&fp, dwPtr16, PARAM_16)) {
+ lpn = fp.lpNode;
+ if (lpn->cbExtra == cbExtra) {
+ ++lpn->dwRefCount;
+ }
+ else {
+ WOW32ASSERTMSG(FALSE, ("\nWOW32: AddParamEx misused. Please contact VadimB or DOSWOW alias\n"));
+ lpn = NULL;
+ }
+ }
+ else {
+ if (NULL != (lpn = CacheBlockAllocate(&gParamMap.blkCache, sizeof(*lpn) + cbExtra))) {
+ lpn->dwPtr32 = (DWORD)(PVOID)(lpn+1);
+ lpn->dwPtr16 = dwPtr16;
+ lpn->pNext = gParamMap.pHead;
+ lpn->dwRefCount = 1;
+ lpn->cbExtra = cbExtra;
+ lpn->htask16 = CURRENTPTD()->htask16;
+ gParamMap.pHead = lpn;
+ }
+ }
+
+ return lpn ? (PVOID)lpn->dwPtr32 : NULL;
+}
+
+#endif
+
+//
+// This should be called from the places we know pointers could get updated
+//
+//
+PVOID ParamMapUpdateNode(DWORD dwPtr, UINT fMode, VOID* lpNode)
+{
+ LPPARAMNODE lpn;
+ PVOID pv;
+
+ if (NULL == lpNode) {
+ FINDPARAM fp;
+ if (FindParamMap(&fp, dwPtr, fMode)) {
+ lpn = fp.lpNode; // node found!
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS, ("WOW: ParamMapUpdateNode could not find node\n"));
+ // return here as we've failed to find node same as we got in
+ return (PVOID)dwPtr;
+ }
+ }
+ else {
+ lpn = (LPPARAMNODE)lpNode;
+ }
+
+ // if pointer is up-to-date then exit
+ pv = GetPModeVDMPointer(lpn->dwPtr16, 0);
+ if ((DWORD)pv == lpn->dwPtr32) {
+ return pv; // up-to-date
+ }
+#ifdef MAPPARAM_EXTRA
+ else
+ if (0 < lpn->cbExtra) {
+ return (PVOID)lpn->dwPtr32;
+ }
+#endif
+
+
+ if (lpn->nAliasCount < ARRAYCOUNT(lpn->rgdwAlias)) {
+
+ lpn->rgdwAlias[lpn->nAliasCount++] = lpn->dwPtr32;
+ }
+ else {
+ WOW32ASSERTMSG(FALSE, ("WOW:AddParamMap is out of alias space\n"));
+ // so we will throw the oldest alias out - this will mean if they refer
+ // to it - they are doomed... That is why we assert here!
+ lpn->rgdwAlias[0] = lpn->dwPtr32;
+ }
+
+ lpn->dwPtr32 = (DWORD)pv; // new pointer here
+
+ return pv;
+}
+
+
+//
+// lParam - 16- or 32-bit pointer (see fMode)
+// fMode - PARAM_16 or PARAM_32 - specifies what lParam represents
+// pfFreePtr - points to a boolean that receives TRUE if caller should
+// do a FREEVDMPTR on a 32-bit parameter
+// Returns TRUE if parameter was found and FALSE otherwise
+//
+
+
+BOOL DeleteParamMap(DWORD lParam, UINT fMode, BOOL* pfFreePtr)
+{
+ FINDPARAM fp;
+ LPPARAMNODE lpn = NULL;
+
+ if (FindParamMap(&fp, lParam, fMode)) {
+ lpn = fp.lpNode;
+
+ if (!--lpn->dwRefCount) {
+
+ if (NULL != fp.lpLast) {
+ fp.lpLast->pNext = lpn->pNext;
+ }
+ else {
+ gParamMap.pHead = lpn->pNext;
+ }
+
+ if (NULL != pfFreePtr) {
+#ifdef MAPPARAM_EXTRA
+ *pfFreePtr = !!lpn->cbExtra;
+#else
+ *pfFreePtr = FALSE;
+#endif
+ }
+ CacheBlockFree(&gParamMap.blkCache, lpn);
+ }
+ else {
+ LOGDEBUG(12, ("\nWOW: DeleteParamMap called refCount > 0 Node@%x\n", (DWORD)lpn));
+
+ if (NULL != pfFreePtr) { // not done with mapping yet
+ *pfFreePtr = FALSE;
+ }
+ }
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS, ("\nWOW: DeleteParamMap called but param was not found\n"));
+ if (NULL != pfFreePtr) {
+ *pfFreePtr = TRUE; // we found none, assume free
+ }
+ }
+
+ return NULL != lpn;
+}
+
+BOOL W32CheckThunkParamFlag(void)
+{
+ return !!(CURRENTPTD()->dwWOWCompatFlags & WOWCF_NOCBDIRTHUNK);
+}
+
+//
+// This function is called to cleanup all the leftover items in case
+// application is dead. Please note, that it should not be called in
+// any other case ever.
+//
+//
+
+VOID FreeParamMap(HAND16 htask16)
+{
+ LPPARAMNODE lpn = gParamMap.pHead;
+ LPPARAMNODE lplast = NULL, lpnext;
+
+ while (NULL != lpn) {
+
+ lpnext = lpn->pNext;
+
+ if (lpn->htask16 == htask16) {
+
+ if (NULL != lplast) {
+ lplast->pNext = lpnext;
+ }
+ else {
+ gParamMap.pHead = lpnext;
+ }
+
+ CacheBlockFree(&gParamMap.blkCache, lpn);
+ }
+ else {
+ lplast = lpn;
+ }
+
+ lpn = lpnext;
+ }
+}
+
+VOID InitParamMap(VOID)
+{
+ CacheBlockInit(&gParamMap.blkCache, MAPCACHESIZE);
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Cache manager
+//
+//
+
+// This is a rather simplistic allocator which uses stack-like allocation
+// as this is the pattern in which allocation/free is being used
+// each block is preceded by a 2-dword header indicating it's size
+
+
+/*
+
+ Note:
+
+ 1. Free Blocks are included in the list in the order of descending
+ address value, that is, the free block with the highest address
+ goes first. This leads allocator not to re-use free blocks unless
+ there is no more memory left
+ 2. When the block is allocated, it is chipped away from the first block
+ that fits (no best-fit or other allocating strategy).
+ 3. When the block is being freed, it is inserted in appropriate place in
+ the list of free blocks or appended to the existing block
+
+ Usually allocations occur on first in - first out basis. These points
+ above provide for minimal overhead in this scenario. In more complicated
+ cases (when hooks are installed and some other crazy things happen) it
+ could be necessary to free block that was allocated out-of order
+ In this case this block would be included somewhere in the free list
+ and possibly re-used.
+
+ The list of free blocks never needs compacting as it could never become
+ fragmented.
+
+ My performance testing suggests that 95% of allocations occur in a stack-
+ like fashion. The most often hit code path is optimized for this case.
+ With random allocations (which is not the case with wow thunks)
+ the ratio of left merges to right(more effective) merges on 'free' calls
+ is 3:1. With wow thunks it is more like 1:10.
+
+*/
+
+
+BOOL IsCacheBlock(PBLKCACHE pc, LPVOID pv);
+
+
+#define LINK_FREELIST(pc, pNew, pLast) \
+if (NULL == pLast) { \
+ pc->pCacheFree = pNew; \
+} \
+else { \
+ pLast->pNext = pNew; \
+}
+
+#ifdef DEBUG
+#define LINK_WORKLIST(pc, pNew, pLast) \
+if (NULL == pLast) { \
+ pc->pCacheHead = pNew; \
+} \
+else { \
+ pLast->pNext = pNew; \
+}
+#else
+#define LINK_WORKLIST(pc, pNew, pLast)
+#endif
+
+VOID CacheBlockInit(PBLKCACHE pc, DWORD dwCacheSize)
+{
+ PBLKHEADER pCache = (PBLKHEADER)malloc_w(dwCacheSize);
+
+ RtlZeroMemory(pc, sizeof(*pc));
+
+ if (NULL != pCache) {
+ pc->pCache = (LPBYTE)pCache;
+ pc->pCacheFree = pCache;
+ pc->dwCacheSize= dwCacheSize;
+ pCache->dwSize = dwCacheSize;
+ pCache->pNext = NULL;
+ }
+}
+
+LPVOID CacheBlockAllocate(PBLKCACHE pc, DWORD dwSize)
+{
+ LPVOID lpv;
+
+ // suballocate a block from the free list
+
+ if (NULL != pc->pCacheFree) {
+
+ PBLKHEADER pbh = pc->pCacheFree;
+ PBLKHEADER pbhLast = NULL;
+ DWORD dwSizeBlk;
+
+ // dword - align dwSizeBlk, sizeof(DWORD) is power of 2 always
+ dwSizeBlk = (dwSize + sizeof(BLKHEADER) + (sizeof(DWORD) - 1)) & ~(sizeof(DWORD)-1);
+
+ // so we allocate from the highest address in hopes of filling holes
+ // almost always this will be the largest block around
+
+ while (NULL != pbh) {
+ if (pbh->dwSize >= dwSizeBlk) { // does this block fit ?
+
+ if (pbh->dwSize - dwSizeBlk > sizeof(BLKHEADER)) { // do we keep the leftovers ?
+
+ // most often hit - chip off from the end
+
+ pbh->dwSize -= dwSizeBlk;
+
+ // now on to the new chunk
+
+ pbh = (PBLKHEADER)((LPBYTE)pbh + pbh->dwSize);
+ pbh->dwSize = dwSizeBlk;
+ }
+ else {
+
+ // less likely case - entire block will be used
+ // so unlink from the free list
+
+ LINK_FREELIST(pc, pbh->pNext, pbhLast);
+ }
+
+ // include into busy blocks
+#ifdef DEBUG
+ pbh->pNext = pc->pCacheHead;
+ pc->pCacheHead = pbh;
+#endif
+ return (LPVOID)(pbh+1);
+ }
+
+ pbhLast = pbh;
+ pbh = pbh->pNext;
+ }
+
+ }
+
+ // no free blocks
+ if (NULL == (lpv = (LPPARAMNODE)malloc_w(dwSize))) {
+ LOGDEBUG(2, ("Malloc failure in CacheBlockAllocate\n"));
+ }
+
+ return (lpv);
+}
+
+
+VOID CacheBlockFree(PBLKCACHE pc, LPVOID lpv)
+{
+ if (IsCacheBlock(pc, lpv)) {
+ PBLKHEADER pbh = (PBLKHEADER)lpv - 1;
+
+#ifdef DEBUG
+ PBLKHEADER pbhf = pc->pCacheHead;
+ PBLKHEADER pbhLast = NULL;
+
+ // remove from the list of working nodes
+ while (NULL != pbhf && pbhf != pbh) {
+ pbhLast = pbhf;
+ pbhf = pbhf->pNext;
+ }
+
+ if (NULL != pbhf) {
+
+ // link in pbh->pNext into a worklist
+
+ LINK_WORKLIST(pc, pbh->pNext, pbhLast);
+ }
+ else {
+ LOGDEBUG(LOG_ALWAYS, ("Alert! CacheBlockFree - invalid ptr\n"));
+ return;
+ }
+
+ pbhf = pc->pCacheFree;
+ pbhLast = NULL;
+
+#else
+ PBLKHEADER pbhf = pc->pCacheFree;
+ PBLKHEADER pbhLast = NULL;
+#endif
+ // list of free nodes
+
+ // insert in order
+ while (NULL != pbhf) {
+
+ // most often case - append from the right
+
+ if (((LPBYTE)pbhf + pbhf->dwSize) == (LPBYTE)pbh) {
+
+ pbhf->dwSize += pbh->dwSize; // adjust the size
+
+ // now see if we need compact
+ if (NULL != pbhLast) {
+ if (((LPBYTE)pbhf + pbhf->dwSize) == (LPBYTE)pbhLast) {
+ // consolidate
+ pbhLast->dwSize += pbhf->dwSize;
+ pbhLast->pNext = pbhf->pNext;
+ }
+ }
+
+ return;
+ }
+ else
+ // check if we can append from the left
+ if (((LPBYTE)pbh + pbh->dwSize) == (LPBYTE)pbhf) {
+
+ pbh->dwSize += pbhf->dwSize; // adjust the size
+ pbh->pNext = pbhf->pNext; // next ptr too
+
+ // now also check the next free ptr so we can compact
+ // the next ptr has lesser address
+
+ if (NULL != pbh->pNext) {
+ pbhf = pbh->pNext;
+
+ if (((LPBYTE)pbhf + pbhf->dwSize) == (LPBYTE)pbh) {
+
+ pbhf->dwSize += pbh->dwSize;
+ pbh = pbhf;
+ }
+ }
+
+ LINK_FREELIST(pc, pbh, pbhLast);
+
+ return;
+ }
+
+ // check for address
+
+ if (pbh > pbhf) {
+ // we have to link-in a standalone block
+ break;
+ }
+
+ pbhLast = pbhf;
+ pbhf = pbhf->pNext; // on to the next block
+ }
+
+ // LOGDEBUG(LOG_ALWAYS, ("Param Map Cache: OUT-OF-ORDER free!!!\n"));
+
+ pbh->pNext = pbhf;
+
+ LINK_FREELIST(pc, pbh, pbhLast);
+
+ }
+ else {
+ free_w(lpv);
+ }
+}
+
+BOOL IsCacheBlock(PBLKCACHE pc, LPVOID pv)
+{
+ LONG lOffset = (LONG)pv - (LONG)pc->pCache;
+ return (lOffset >= 0 && lOffset < (LONG)pc->dwCacheSize);
+}
+
+
+
+
+
+
+
diff --git a/private/mvdm/wow32/wparam.h b/private/mvdm/wow32/wparam.h
new file mode 100644
index 000000000..a28afc21a
--- /dev/null
+++ b/private/mvdm/wow32/wparam.h
@@ -0,0 +1,85 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WPARAM.H
+ * WOW32 16-bit handle alias support
+ *
+ * History:
+--*/
+
+typedef enum ParamMode {
+ PARAM_NONE,
+ PARAM_16,
+ PARAM_32
+} ParamMode;
+
+/*
+ * FindParamMap
+ *
+ * lpFindParam is for wparam.c use (set to NULL)
+ *
+ * lParam is either 16-bit or 32-bit memory pointer
+ *
+ * fMode is either param_16 or param_32
+ *
+ */
+
+
+DWORD FindParamMap(VOID* lpFindParam, DWORD lParam, UINT fMode);
+
+PVOID AddParamMap(DWORD dwPtr32, DWORD dwPtr16);
+
+BOOL DeleteParamMap(DWORD lParam, UINT fMode, BOOL* pfFreePtr);
+
+DWORD GetParam16(DWORD dwParam32);
+
+BOOL W32CheckThunkParamFlag(void);
+
+VOID FreeParamMap(HAND16 htask16);
+
+// Add dwPtr16 mapping for a parameter, which is allocated
+// size of the buffer is cbExtra and 32-bit pointer to the buffer
+// is returned
+
+PVOID AddParamMapEx(DWORD dwPtr16, DWORD cbExtra);
+
+// Update node when pointer is suspect to have been moved
+// returns updated pointer (32-bit)
+PVOID ParamMapUpdateNode(DWORD dwPtr, UINT fMode, VOID* lpn);
+
+VOID InitParamMap(VOID);
+
+///////////////////////////////////////////////////////////////
+//
+// This is rather fast and dirty heap allocator
+//
+
+typedef struct tagBlkHeader *PBLKHEADER;
+
+typedef struct tagBlkHeader {
+ PBLKHEADER pNext;
+ DWORD dwSize; // block size
+} BLKHEADER, *PBLKHEADER;
+
+typedef struct tagBlkCache {
+ LPBYTE pCache;
+#ifdef DEBUG
+ PBLKHEADER pCacheHead;
+#endif
+ PBLKHEADER pCacheFree;
+ DWORD dwCacheSize;
+ DWORD dwFlags;
+
+} BLKCACHE, *PBLKCACHE;
+
+LPVOID CacheBlockAllocate (PBLKCACHE pc, DWORD dwSize);
+VOID CacheBlockFree (PBLKCACHE pc, LPVOID lpv);
+VOID CacheBlockInit (PBLKCACHE pc, DWORD dwCacheSize);
+
+
+/////////////////////////////////////////////////////////////////
+
+
diff --git a/private/mvdm/wow32/wreldc.c b/private/mvdm/wow32/wreldc.c
new file mode 100644
index 000000000..f7a124d36
--- /dev/null
+++ b/private/mvdm/wow32/wreldc.c
@@ -0,0 +1,289 @@
+//*****************************************************************************
+//
+// DC Cacheing -
+//
+// Support for misbehaved apps - which continue to use a DC that has been
+// Released. Well the problem is WIN30 allows it, so we need to be
+// compatible.
+//
+//
+// 03-Feb-92 NanduriR Created.
+//
+//*****************************************************************************
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wreldc.c);
+
+BOOL GdiCleanCacheDC (HDC hdc16);
+
+//*****************************************************************************
+// count of currently cached DCs so that we can quickly check whether any
+// ReleasedDCs are pending.
+//
+//*****************************************************************************
+
+INT iReleasedDCs = 0;
+
+
+//*****************************************************************************
+// The head of the linked list of the DCs Info.
+//
+//*****************************************************************************
+
+LPDCCACHE lpDCCache = NULL;
+
+
+//*****************************************************************************
+// ReleaseCachedDCs -
+// ReleaseDC's a cached DC if it meets the 'search criterion'.
+// The Search flag indicates which input arguments will be used.
+// Unused arguments can be NULL or pure garbage.
+//
+// NOTE: this does not free the memory that has been allocated for
+// the list.
+//
+// We reset the flag 'flState' and thus will be able to
+// reuse the structure.
+//
+// Returns TRUE
+//*****************************************************************************
+
+BOOL ReleaseCachedDCs(HAND16 htask16, HAND16 hwnd16, HAND16 hdc16,
+ HWND hwnd32, UINT flSearch)
+{
+ HAND16 hdcTemp;
+ LPDCCACHE lpT;
+
+ UNREFERENCED_PARAMETER(hdc16);
+
+ if (iReleasedDCs) {
+ for (lpT = lpDCCache; lpT != NULL; lpT = lpT->lpNext) {
+
+ if (!(lpT->flState & DCCACHE_STATE_RELPENDING))
+ continue;
+
+ hdcTemp = (HAND16)NULL;
+
+ if (flSearch & SRCHDC_TASK16_HWND16) {
+
+ if (lpT->htask16 == htask16 &&
+ lpT->hwnd16 == hwnd16)
+ hdcTemp = lpT->hdc16;
+
+ }
+ else if (flSearch & SRCHDC_TASK16) {
+
+ if (lpT->htask16 == htask16)
+ hdcTemp = lpT->hdc16;
+
+ }
+ else {
+ LOGDEBUG(0, ("ReleaseCachedDCs:Invalid Search Flag\n"));
+ }
+
+ if (hdcTemp) {
+ if (ReleaseDC(lpT->hwnd32, HDC32(hdcTemp))) {
+ LOGDEBUG(6,
+ ("ReleaseCachedDCs: success hdc16 %04x - count %04x\n",
+ hdcTemp, (iReleasedDCs-1)));
+ }
+ else {
+ LOGDEBUG(7, ("ReleaseCachedDCs: FAILED hdc16 %04x\n",
+ hdcTemp));
+ }
+
+ // reset the state evenif ReleaseDC failed
+
+ lpT->flState = 0;
+ FREEHDC16(hdcTemp);
+ if (!(--iReleasedDCs))
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+//*****************************************************************************
+// FreeCachedDCs -
+// ReleaseDC's a cached DC - Normally called during taskexit.
+//
+// NOTE: this does not free the memory that has been allocated for
+// the list.
+//
+// We reset the flag 'flState' and thus will be able to
+// reuse the structure.
+//
+// Returns TRUE
+//*****************************************************************************
+
+BOOL FreeCachedDCs(HAND16 htask16)
+{
+ HAND16 hdcTemp;
+ LPDCCACHE lpT;
+
+ for (lpT = lpDCCache; lpT != NULL; lpT = lpT->lpNext) {
+
+ if ((lpT->flState & DCCACHE_STATE_INUSE) &&
+ lpT->htask16 == htask16) {
+
+ hdcTemp = lpT->hdc16;
+ if (lpT->flState & DCCACHE_STATE_RELPENDING) {
+
+ if (ReleaseDC(lpT->hwnd32, HDC32(hdcTemp))) {
+ LOGDEBUG(6,
+ ("FreeCachedDCs: success hdc16 %04x - task %04x\n",
+ hdcTemp, htask16));
+ }
+ else {
+ LOGDEBUG(7, ("FreeCachedDCs: FAILED hdc16 %04x - task %04x\n",
+ hdcTemp, htask16));
+ }
+
+ WOW32ASSERT(iReleasedDCs != 0);
+ --iReleasedDCs;
+ }
+
+ lpT->flState = 0;
+ FREEHDC16(hdcTemp);
+ }
+ }
+
+ return TRUE;
+}
+
+
+//*****************************************************************************
+// StoredDC -
+//
+// Initializes a DCCACHE structure with appropriate values.
+// Uses an empty slot in the linked list if available else
+// allocates a new one and adds to the head of the list.
+//
+// Returns TRUE on success, FALSE on failure
+//*****************************************************************************
+
+BOOL StoreDC(HAND16 htask16, HAND16 hwnd16, HAND16 hdc16)
+{
+ HAND16 hdcTemp = (HAND16)NULL;
+ LPDCCACHE lpT, lpNew;
+
+ // Check for an 'inuse' slot that will match the one that will be created
+ // or check for an empty slot.
+ //
+ // An existing 'inuse' slot may match the one that's being created if
+ // an app makes multiple calls to GetDC(hwnd) without an intervening
+ // ReleaseDC. eg. MathCad.
+ // - Nanduri
+
+ lpNew = (LPDCCACHE)NULL;
+ for (lpT = lpDCCache; lpT != NULL; lpT = lpT->lpNext) {
+ if (lpT->flState & DCCACHE_STATE_INUSE) {
+ if (lpT->hdc16 == hdc16) {
+ if (lpT->hwnd16 == hwnd16 &&
+ lpT->htask16 == htask16 ) {
+ LOGDEBUG(6, ("WOW:An identical second GetDC call without ReleaseDC\n"));
+ }
+ else {
+ LOGDEBUG(6, ("WOW:New DC 0x%04x exists - replacing old cache\n", hdc16));
+ }
+
+ if (lpT->flState & DCCACHE_STATE_RELPENDING) {
+ WOW32ASSERT(iReleasedDCs != 0);
+ --iReleasedDCs;
+ }
+
+ lpNew = lpT;
+ break;
+ }
+ }
+ else {
+ if (!lpNew)
+ lpNew = lpT;
+ }
+ }
+ lpT = lpNew;
+
+ if (lpT == NULL) {
+ lpT = (LPDCCACHE)malloc_w_small(sizeof(DCCACHE));
+ if (lpT) {
+ lpT->lpNext = lpDCCache;
+ lpDCCache = lpT;
+ }
+ else {
+ LOGDEBUG(0, ("StoreDC: malloc_w_small for cache failed\n"));
+ }
+ }
+
+ if (lpT != NULL) {
+ lpT->flState = DCCACHE_STATE_INUSE;
+ lpT->htask16 = htask16;
+ lpT->hwnd16 = hwnd16;
+ lpT->hdc16 = hdc16;
+ lpT->hwnd32 = HWND32(hwnd16);
+ LOGDEBUG(6, ("StoreDC: Added hdc %04x\n",hdc16));
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+//*****************************************************************************
+// CacheReleasedDC -
+//
+// Increments iReleasedDCs to indicate that a ReleaseDC is pending.
+//
+// Increments the iReleasedDC only if there was a corresponding GetDC.
+// i.e, only if the DC exists in the DCcache;
+//
+// This is to handle the scenrio below:
+// hdc = BeginPaint(hwnd,..);
+// ReleaseDC(hwnd, hdc);
+// EndPaint(hwnd, ..);
+//
+//
+// Returns TRUE on success, FALSE on failure
+//*****************************************************************************
+
+BOOL CacheReleasedDC(HAND16 htask16, HAND16 hwnd16, HAND16 hdc16)
+{
+ HAND16 hdcTemp = (HAND16)NULL;
+ LPDCCACHE lpT;
+
+ for (lpT = lpDCCache; lpT != NULL; lpT = lpT->lpNext) {
+
+ if ((lpT->flState & DCCACHE_STATE_INUSE) &&
+ lpT->htask16 == htask16 &&
+ lpT->hwnd16 == hwnd16 &&
+ lpT->hdc16 == hdc16 ) {
+
+
+ // the app might do releasedc twice on the same dc by mistake
+
+ if (!(lpT->flState & DCCACHE_STATE_RELPENDING)) {
+ lpT->flState |= DCCACHE_STATE_RELPENDING;
+ iReleasedDCs++;
+ }
+ LOGDEBUG(6, ("CachedReleasedDC: Pending hdc %04x - count %04x\n",
+ hdc16, iReleasedDCs));
+ GdiCleanCacheDC (HDC32(hdc16));
+
+ // Fix apps that draw then do lots
+ // of disk activity, usually they do
+ // a releaseDC. This flush will syncronize
+ // the drawing with the beginning of the
+ // disk activity. Bug #9704 PackRats install program draws text too late
+
+ GdiFlush();
+
+ return TRUE;
+ }
+
+ }
+
+ return FALSE;
+}
diff --git a/private/mvdm/wow32/wreldc.h b/private/mvdm/wow32/wreldc.h
new file mode 100644
index 000000000..1d03457f5
--- /dev/null
+++ b/private/mvdm/wow32/wreldc.h
@@ -0,0 +1,41 @@
+//*****************************************************************************
+//
+// DC Cacheing - header file
+//
+// Support for misbehaved apps - which continue to use a DC that has been
+// Released. Well the problem is WIN30 allows it, so we need to be
+// compatible.
+//
+//
+// 03-Feb-92 NanduriR Created.
+//
+//*****************************************************************************
+
+
+typedef struct _DCCACHE{
+ struct _DCCACHE FAR *lpNext;
+ BYTE flState;
+ HAND16 htask16;
+ HAND16 hwnd16;
+ HDC16 hdc16;
+ HWND hwnd32;
+} DCCACHE, FAR *LPDCCACHE;
+
+
+extern INT iReleasedDCs;
+
+#define CACHENOTEMPTY() (BOOL)(iReleasedDCs)
+
+#define DCCACHE_STATE_INUSE 0x0001
+#define DCCACHE_STATE_RELPENDING 0x0002
+
+#define SRCHDC_TASK16_HWND16 0x0001
+#define SRCHDC_TASK16_HWND32 0x0002
+#define SRCHDC_TASK16 0x0004
+
+BOOL ReleaseCachedDCs(HAND16 htask16, HAND16 hwnd16, HAND16 hdc16,
+ HWND hwnd32, UINT flSearch);
+BOOL StoreDC(HAND16 htask16, HAND16 hwnd16, HAND16 hdc16);
+BOOL CacheReleasedDC(HAND16 htask16, HAND16 hwnd16, HAND16 hdc16);
+BOOL FreeCachedDCs(HAND16 htask16);
+
diff --git a/private/mvdm/wow32/wres16.c b/private/mvdm/wow32/wres16.c
new file mode 100644
index 000000000..206d9b984
--- /dev/null
+++ b/private/mvdm/wow32/wres16.c
@@ -0,0 +1,654 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WRES16.C
+ * WOW32 16-bit resource support
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// BUGBUG: moved macros from mvdm.h and wo32.h
+// as they are not what they appear to be.
+// Watch out these macros increment the pointer arguments!!!!
+// 02-Feb-1994 Jonle
+//
+#define VALIDPUT(p) ((UINT)p>65535)
+#define PUTWORD(p,w) {if (VALIDPUT(p)) *(PWORD)p=w; ((PWORD)p)++; }
+#define PUTDWORD(p,d) {if (VALIDPUT(p)) *(PDWORD)p=d;((PDWORD)p)++;}
+#define PUTUDWORD(p,d) {if (VALIDPUT(p)) *(DWORD UNALIGNED *)p=d;((DWORD UNALIGNED *)p)++;}
+#define GETWORD(pb) (*((UNALIGNED WORD *)pb)++)
+#define GETDWORD(pb) (*((UNALIGNED DWORD *)pb)++)
+
+#define ADVGET(p,i) {(UINT)p+=i;}
+#define ADVPUT(p,i) {(UINT)p+=i;}
+#define ALIGNWORD(p) {(UINT)p+=( ((UINT)p)&(sizeof(WORD)-1));}
+#define ALIGNDWORD(p) {(UINT)p+=(-((INT)p)&(sizeof(DWORD)-1));}
+
+
+MODNAME(wres16.c);
+
+PRES presFirst; // pointer to first RES entry
+
+#ifdef DEBUG
+
+typedef struct _RTINFO { /* rt */
+ LPSTR lpType; // predefined resource type
+ PSZ pszName; // name of type
+} RTINFO, *PRTINFO;
+
+RTINFO artInfo[] = {
+ {RT_CURSOR, "CURSOR"},
+ {RT_BITMAP, "BITMAP"},
+ {RT_ICON, "ICON"},
+ {RT_MENU, "MENU"},
+ {RT_DIALOG, "DIALOG"},
+ {RT_STRING, "STRING"},
+ {RT_FONTDIR, "FONTDIR"},
+ {RT_FONT, "FONT"},
+ {RT_ACCELERATOR, "ACCELERATOR"},
+ {RT_RCDATA, "RCDATA"},
+ {RT_MESSAGETABLE,"MESSAGETABLE"},
+ {RT_GROUP_CURSOR,"CURSOR DIRECTORY"},
+ {RT_GROUP_ICON, "ICON DIRECTORY"},
+};
+
+PSZ GetResourceType(LPSZ lpszType)
+{
+ INT i;
+ register PRTINFO prt;
+
+ if (HIWORD(lpszType) != 0)
+ return lpszType;
+ for (prt=artInfo,i=NUMEL(artInfo); i>0; i--,prt++)
+ if (prt->lpType == lpszType)
+ return prt->pszName;
+ return "UNKNOWN";
+}
+
+#endif
+
+
+/* Resource management functions
+ */
+
+PRES AddRes16(HMOD16 hmod16, WORD wExeVer, HRESI16 hresinfo16, LPSZ lpszType)
+{
+ register PRES pres;
+
+ if (pres = malloc_w(sizeof(RES))) {
+
+ // Initialize the structure
+ pres->hmod16 = hmod16;
+ pres->wExeVer = wExeVer;
+ pres->flState = 0;
+ pres->hresinfo16 = hresinfo16;
+ pres->hresdata16 = 0;
+ pres->lpszResType = lpszType;
+ pres->pbResData = NULL;
+
+ // And then link it in
+ pres->presNext = presFirst;
+ presFirst = pres;
+ return pres;
+ }
+ return NULL;
+}
+
+
+VOID FreeRes16(PRES presFree)
+{
+ register PRES pres, presPrev;
+
+ presPrev = (PRES)(&presFirst);
+ while (pres = presPrev->presNext) {
+ if (pres == presFree)
+ break;
+ presPrev = pres;
+ }
+ WOW32ASSERT(pres); // not finding a pres would be rather distressing
+ if (pres) {
+ presPrev->presNext = pres->presNext;
+ if (pres->pbResData)
+ UnlockResource16(pres);
+ free_w(pres);
+ }
+}
+
+
+VOID DestroyRes16(HMOD16 hmod16)
+{
+ register PRES pres, presPrev;
+
+ presPrev = (PRES)(&presFirst);
+ while (pres = presPrev->presNext) {
+ if (pres->hmod16 == hmod16) {
+
+ LOGDEBUG(5,("Freeing resource info for current terminating task\n"));
+
+ // Now basically do a FreeRes16
+ presPrev->presNext = pres->presNext;
+ if (pres->pbResData)
+ UnlockResource16(pres);
+ free_w(pres);
+ } else {
+ presPrev = pres;
+ }
+ }
+}
+
+
+PRES FindResource16(HMOD16 hmod16, LPSZ lpszName, LPSZ lpszType)
+{
+ INT cb;
+ PRES pres = NULL;
+ VPVOID vp=0;
+ PARM16 Parm16;
+ VPSZ vpszName = 0, vpszType = 0;
+ WORD wExpWinVer;
+
+ if (HIWORD(lpszName) == 0) {
+ vpszName = (VPSZ)lpszName;
+ LOGDEBUG(5,(" Finding resource %lx, type %s(%lx)\n",
+ lpszName, GetResourceType(lpszType), lpszType));
+ } else {
+ cb = strlen(lpszName)+1;
+ if (vpszName = GlobalAllocLock16(GMEM_MOVEABLE, cb, NULL))
+ putstr16(vpszName, lpszName, cb);
+ LOGDEBUG(5,(" Finding resource \"%s\", type %s(%lx)\n",
+ lpszName, GetResourceType(lpszType), lpszType));
+ }
+
+ if (vpszName) {
+ if (HIWORD(lpszType) == 0) { // predefined resource
+ vpszType = (VPSZ)lpszType; // no doubt from MAKEINTRESOURCE
+ } else {
+ cb = strlen(lpszType)+1;
+ if (vpszType = GlobalAllocLock16(GMEM_MOVEABLE, cb, NULL)) {
+ putstr16(vpszType, lpszType, cb);
+ }
+ }
+ if (vpszType) {
+ PCBVDMFRAME pCBFrame;
+
+ Parm16.WndProc.wParam = hmod16;
+ Parm16.WndProc.lParam = vpszName;
+ Parm16.WndProc.wMsg = LOWORD(vpszType);
+ Parm16.WndProc.hwnd = HIWORD(vpszType);
+ CallBack16(RET_FINDRESOURCE, &Parm16, 0, &vp);
+ pCBFrame = CBFRAMEPTR(CURRENTPTD()->vpCBStack);
+ wExpWinVer = pCBFrame->wGenUse1;
+ FREEVDMPTR(pCBFrame);
+ if (HIWORD(vpszType))
+ GlobalUnlockFree16(vpszType);
+ }
+ if (HIWORD(vpszName))
+ GlobalUnlockFree16(vpszName);
+ }
+
+ if ((HRESI16)vp) {
+ pres = AddRes16(hmod16,wExpWinVer,(HRESI16)vp, lpszType);
+ }
+ return pres;
+}
+
+
+PRES LoadResource16(HMOD16 hmod16, PRES pres)
+{
+ VPVOID vp=0;
+ PARM16 Parm16;
+
+ DBG_UNREFERENCED_PARAMETER(hmod16);
+ WOW32ASSERT(pres && hmod16 == pres->hmod16);
+
+ Parm16.WndProc.wParam = pres->hmod16;
+ Parm16.WndProc.lParam = pres->hresinfo16;
+
+ CallBack16(RET_LOADRESOURCE, &Parm16, 0, &vp);
+
+ if (pres->hresdata16 = (HRESD16)vp)
+ return pres;
+
+ // BUGBUG -- On a LoadResource failure, WIN32 is not required to do a
+ // corresponding FreeResource, so our RES structure will hang around until
+ // task termination clean-up (which may be OK) -JTP
+ return NULL;
+}
+
+
+BOOL FreeResource16(PRES pres)
+{
+ VPVOID vp=0;
+ PARM16 Parm16;
+
+ WOW32ASSERT(pres);
+
+ Parm16.WndProc.wParam = pres->hresdata16;
+ CallBack16(RET_FREERESOURCE, &Parm16, 0, &vp);
+
+ FreeRes16(pres);
+
+ return (BOOL)vp;
+}
+
+
+LPBYTE LockResource16(register PRES pres)
+{
+ DWORD cb, cb16;
+ VPVOID vp=0;
+ PARM16 Parm16;
+ WOW32ASSERT(pres);
+
+ Parm16.WndProc.wParam = pres->hresdata16;
+ CallBack16(RET_LOCKRESOURCE, &Parm16, 0, &vp);
+
+ if (vp) {
+ PCBVDMFRAME pCBFrame;
+
+ // Get size of 16-bit resource
+ pCBFrame = CBFRAMEPTR(CURRENTPTD()->vpCBStack);
+ cb16 = pCBFrame->wGenUse2 | (LONG)pCBFrame->wGenUse1 << 16;
+
+ LOGDEBUG(5,(" Locking/converting resource type %s(%lx)\n",
+ GetResourceType(pres->lpszResType), pres->lpszResType));
+
+ // Handle known resource types here
+ if (pres->lpszResType) {
+
+ switch((INT)pres->lpszResType) {
+
+
+ case (INT)RT_MENU:
+ // cb = ConvertMenu16(pres->wExeVer, NULL, vp, cb, cb16);
+ cb = cb16 * sizeof(WCHAR); // see SizeofResource16
+ if (cb && (pres->pbResData = malloc_w(cb)))
+ ConvertMenu16(pres->wExeVer, pres->pbResData, vp, cb, cb16);
+ return pres->pbResData;
+
+ case (INT)RT_DIALOG:
+ // cb = ConvertDialog16(NULL, vp, cb, cb16);
+ cb = cb16 * sizeof(WCHAR); // see SizeofResource16
+ if (cb && (pres->pbResData = malloc_w(cb)))
+ ConvertDialog16(pres->pbResData, vp, cb, cb16);
+ return pres->pbResData;
+
+ case (INT)RT_ACCELERATOR:
+ WOW32ASSERT(FALSE); // never should we come here.
+ return NULL;
+
+// case (INT)RT_GROUP_CURSOR:
+// case (INT)RT_GROUP_ICON:
+// GETOPTPTR(vp, 0, lp);
+// return lp;
+ }
+ }
+
+ // If we're still here, get desperate and return a simple 32-bit alias
+ GETVDMPTR(vp, cb16, pres->pbResData);
+ pres->flState |= RES_ALIASPTR;
+ return pres->pbResData;
+ }
+ // If we're still here, nothing worked
+ return NULL;
+}
+
+
+BOOL UnlockResource16(PRES pres)
+{
+ VPVOID vp=0;
+ PARM16 Parm16;
+
+ WOW32ASSERT(pres);
+
+ Parm16.WndProc.wParam = pres->hresdata16;
+ CallBack16(RET_UNLOCKRESOURCE, &Parm16, 0, &vp);
+
+ if (pres->pbResData && !(pres->flState & RES_ALIASPTR))
+ free_w(pres->pbResData);
+ pres->pbResData = NULL;
+ pres->flState &= ~RES_ALIASPTR;
+
+ return (BOOL)vp;
+}
+
+
+DWORD SizeofResource16(HMOD16 hmod16, PRES pres)
+{
+ VPVOID vp=0;
+ DWORD cbData;
+ PARM16 Parm16;
+
+ DBG_UNREFERENCED_PARAMETER(hmod16);
+
+ WOW32ASSERT(pres && hmod16 == pres->hmod16);
+
+ Parm16.WndProc.wParam = pres->hmod16;
+ Parm16.WndProc.lParam = pres->hresinfo16;
+
+ CallBack16(RET_SIZEOFRESOURCE, &Parm16, 0, &vp);
+
+ cbData = (DWORD)vp;
+
+ /*
+ * Adjust the size of the resource if they are different
+ * between NT and Windows
+ */
+ // Handle known resource types here
+ if (pres->lpszResType) {
+
+ switch((INT)pres->lpszResType) {
+
+ case (INT)RT_MENU:
+ case (INT)RT_DIALOG:
+
+// If we need an exact count then we would have to enable this code
+// but currently the count is only used in USER to alloc enough space
+// in the client\server transition windows.
+// WARNING - if this code is re-enabled you must also change LockResource16
+// CallBack16(RET_LOADRESOURCE, &Parm16, 0, &vpResLoad);
+// CallBack16(RET_LOCKRESOURCE, vpResLoad, 0, &vp);
+// if ((INT)pres->lpszResType == RT_MENU)
+// cbData = (DWORD)ConvertMenu16(pres->wExeVer, NULL, vp, cbData);
+// else
+// cbData = (DWORD)ConvertDialog16(NULL, vp, cbData);
+// CallBack16(RET_UNLOCKRESOURCE, &Parm16, 0, &vp);
+
+ cbData = (DWORD)((DWORD)vp * sizeof(WCHAR));
+ break;
+
+ case (INT)RT_STRING:
+ cbData = (DWORD)((DWORD)vp * sizeof(WCHAR));
+ break;
+ }
+ }
+
+ return cbData;
+}
+
+/*
+ * ConvertMenu16
+ *
+ * If pmenu32 is NULL then its just a size query
+ *
+ * Returns the number of bytes in the CONVERTED menu
+ */
+
+DWORD ConvertMenu16(WORD wExeVer, PBYTE pmenu32, VPBYTE vpmenu16, DWORD cb, DWORD cb16)
+{
+ WORD wVer, wOffset;
+ PBYTE pmenu16, pmenu16Save;
+ PBYTE pmenu32T = pmenu32;
+
+ pmenu16 = GETVDMPTR(vpmenu16, cb16, pmenu16Save);
+ wVer = 0;
+ if (wExeVer >= 0x300)
+ wVer = GETWORD(pmenu16);
+ PUTWORD(pmenu32, wVer); // transfer versionNumber
+ wOffset = 0;
+ if (wExeVer >= 0x300)
+ wOffset = GETWORD(pmenu16);
+ PUTWORD(pmenu32, wOffset); // transfer offset
+ ADVGET(pmenu16, wOffset); // and advance by offset
+ ADVPUT(pmenu32, wOffset);
+ ALIGNWORD(pmenu32); // this is the DIFFERENCE for WIN32
+ cb = pmenu32 - pmenu32T; // pmenu32 will == 4 for size queries
+ cb += ConvertMenuItems16(wExeVer, &pmenu32, &pmenu16, vpmenu16+(pmenu16 - pmenu16Save));
+
+ FREEVDMPTR(pmenu16Save);
+ RETURN(cb);
+}
+
+
+
+/*
+ * ConvertMenuItems16
+ *
+ * Returns the number of bytes in the CONVERTED menu
+ * Note: This can be called with ppmenu32==4 which means the caller is looking
+ * for the size to allocate for the 32-bit menu structure.
+ */
+
+DWORD ConvertMenuItems16(WORD wExeVer, PPBYTE ppmenu32, PPBYTE ppmenu16, VPBYTE vpmenu16)
+{
+ INT cbAnsi;
+ DWORD cbTotal = 0;
+ UINT cbUni;
+ WORD wOption, wID;
+ PBYTE pmenu32 = *ppmenu32;
+ PBYTE pmenu16 = *ppmenu16;
+ PBYTE pmenu16T = pmenu16;
+ PBYTE pmenu32T = pmenu32;
+
+ do {
+ if (wExeVer < 0x300)
+ wOption = GETBYTE(pmenu16);
+ else
+ wOption = GETWORD(pmenu16);
+ PUTWORD(pmenu32, wOption); // transfer mtOption
+ if (!(wOption & MF_POPUP)) {
+ wID = GETWORD(pmenu16);
+ PUTWORD(pmenu32, wID); // transfer mtID
+ }
+ cbAnsi = strlen(pmenu16)+1;
+
+ // If this is an ownerdraw menu don't copy the ANSI memu string to
+ // Unicode. Put a 16:16 pointer into the 32-bit resource which
+ // points to menu string instead. User will place this pointer in
+ // MEASUREITEMSTRUCT->itemData before sending WM_MEASUREITEM. If it's a
+ // NULL string User will place a NULL in MEASUREITEMSTRUCT->itemData.
+ // Chess Master and Mavis Beacon Teaches Typing depend on this.
+ if ((wOption & MFT_OWNERDRAW) && *pmenu16) {
+ if (VALIDPUT(pmenu32)) {
+ *(DWORD UNALIGNED *)pmenu32 = vpmenu16 + (pmenu16 - pmenu16T);
+ }
+ cbUni = sizeof(DWORD);
+ }
+ else {
+ if (VALIDPUT(pmenu32)) {
+ RtlMultiByteToUnicodeN((LPWSTR)pmenu32, MAXULONG, (PULONG)&cbUni, pmenu16, cbAnsi);
+
+ }
+ else {
+ cbUni = cbAnsi * sizeof(WCHAR);
+ }
+ }
+
+ ADVGET(pmenu16, cbAnsi);
+ ADVPUT(pmenu32, cbUni);
+ ALIGNWORD(pmenu32); // this is the DIFFERENCE for WIN32
+ if (wOption & MF_POPUP)
+ cbTotal += ConvertMenuItems16(wExeVer, &pmenu32, &pmenu16, vpmenu16+(pmenu16 - pmenu16T));
+
+
+ } while (!(wOption & MF_END));
+
+ *ppmenu32 = pmenu32;
+ *ppmenu16 = pmenu16;
+
+ return (pmenu32 - pmenu32T);
+}
+
+
+DWORD ConvertDialog16(PBYTE pdlg32, VPBYTE vpdlg16, DWORD cb, DWORD cb16)
+{
+ BYTE b;
+ WORD w;
+ DWORD dwStyle;
+ INT i, cItems;
+ UINT cbAnsi;
+ UINT cbUni;
+ PBYTE pdlg16, pdlg16Save;
+ PBYTE pdlg32T = pdlg32;
+
+ pdlg16 = GETVDMPTR(vpdlg16, cb16, pdlg16Save);
+ dwStyle = GETDWORD(pdlg16);
+ PUTDWORD(pdlg32, dwStyle); // transfer style
+ PUTDWORD(pdlg32, 0); // Add NEW extended style
+
+ cItems = GETBYTE(pdlg16);
+ PUTWORD(pdlg32, (WORD)cItems); // stretch count to WORD for WIN32
+ for (i=0; i<4; i++) {
+ w = GETWORD(pdlg16);
+ PUTWORD(pdlg32, w); // transfer x & y, then cx & cy
+ }
+
+ //
+ // the next three fields are all strings (possibly null)
+ // menuname, classname, captiontext
+ // the Menu string can be encoded as ff nn mm which
+ // means that the menu id is ordinal mmnn
+ //
+
+ for (i=0; i<3; i++) {
+ if (i==0 && *pdlg16 == 0xFF) { // special encoding of szMenuName
+ GETBYTE(pdlg16); // advance past the ff byte
+ PUTWORD(pdlg32, 0xffff); // copy the f word
+ w = GETWORD(pdlg16); // get the menu ordinal
+ PUTWORD(pdlg32, w); // transfer it
+ } else { // ordinary string
+ cbAnsi = strlen(pdlg16)+1;
+ if (VALIDPUT(pdlg32)) {
+ RtlMultiByteToUnicodeN((LPWSTR)pdlg32, MAXULONG, (PULONG)&cbUni, pdlg16, cbAnsi);
+ } else {
+ cbUni = cbAnsi * sizeof(WCHAR);
+ }
+ ADVGET(pdlg16, cbAnsi);
+ ADVPUT(pdlg32, cbUni);
+ ALIGNWORD(pdlg32); // fix next field alignment for WIN32
+ }
+ }
+
+ if (dwStyle & DS_SETFONT) {
+ w = GETWORD(pdlg16);
+ PUTWORD(pdlg32, w); // transfer cPoints
+ cbAnsi = strlen(pdlg16)+1; // then szTypeFace
+ if (VALIDPUT(pdlg32)) {
+ RtlMultiByteToUnicodeN((LPWSTR)pdlg32, MAXULONG, (PULONG)&cbUni, pdlg16, cbAnsi);
+ } else {
+ cbUni = cbAnsi * sizeof(WCHAR);
+ }
+ ADVGET(pdlg16, cbAnsi);
+ ADVPUT(pdlg32, cbUni);
+
+ }
+ while (cItems--) {
+ ALIGNDWORD(pdlg32); // items start on DWORD boundaries
+ PUTDWORD(pdlg32, FETCHDWORD(*(PDWORD)(pdlg16+sizeof(WORD)*5)));
+ PUTDWORD(pdlg32, 0); // Add NEW extended style
+
+ for (i=0; i<5; i++) {
+ w = GETWORD(pdlg16);
+ PUTWORD(pdlg32, w); // transfer x & y, then cx & cy, then id
+ }
+
+ ADVGET(pdlg16, sizeof(DWORD)); // skip style, which we already copied
+
+ //
+ // get the class name could be string or encoded value
+ // win16 encoding scheme: class is 1 byte with bit 0x80 set,
+ // this byte == predefined class
+ // win32 encoding: a word of ffff, followed by class (word)
+ //
+
+ if (*pdlg16 & 0x80) {
+ PUTWORD(pdlg32, 0xFFFF); // NEW encoding marker 0xFFFF
+ b = GETBYTE(pdlg16); // special encoding for predefined class
+ PUTWORD(pdlg32, (WORD)b);
+ } else {
+ cbAnsi = strlen(pdlg16)+1;
+ if (VALIDPUT(pdlg32)) { // transfer szClass
+ RtlMultiByteToUnicodeN((LPWSTR)pdlg32, MAXULONG, (PULONG)&cbUni, pdlg16, cbAnsi);
+ } else {
+ cbUni = cbAnsi * sizeof(WCHAR);
+ }
+ ADVGET(pdlg16, cbAnsi);
+ ADVPUT(pdlg32, cbUni);
+ }
+ ALIGNWORD(pdlg32); // fix next field alignment for WIN32
+
+ //
+ // transfer the item text
+ //
+
+ if (*pdlg16 == 0xFF) { // special encoding
+ GETBYTE(pdlg16);
+ PUTWORD(pdlg32, 0xFFFF);
+ w = GETWORD(pdlg16);
+ PUTWORD(pdlg32, w);
+ } else {
+ cbAnsi = strlen(pdlg16)+1;
+ if (VALIDPUT(pdlg32)) { // otherwise, just transfer szText
+ RtlMultiByteToUnicodeN((LPWSTR)pdlg32, MAXULONG, (PULONG)&cbUni, pdlg16, cbAnsi);
+ } else {
+ cbUni = cbAnsi * sizeof(WCHAR);
+ }
+ ADVGET(pdlg16, cbAnsi);
+ ADVPUT(pdlg32, cbUni);
+ }
+ ALIGNWORD(pdlg32); // fix next field alignment for WIN32
+
+ //
+ // transfer the create params
+ //
+
+ b = GETBYTE(pdlg16);
+
+ //
+ // If the template has create params, we're going to get tricky.
+ // When USER sends the WM_CREATE message to a control with
+ // createparams, lParam points to the CREATESTRUCT, which
+ // contains lpCreateParams. lpCreateParams needs to point
+ // to the createparams in the DLGTEMPLATE. In order to
+ // accomplish this, we store a 16:16 pointer to the 16-bit
+ // DLGTEMPLATE's createparams in the 32-bit DLGTEMPLATE's
+ // createparams. In other words, whenever the count of
+ // bytes of createparams is nonzero (b != 0), we put 4
+ // bytes of createparams in the 32-bit DLGTEMPLATE that
+ // happen to be a 16:16 pointer to the createparams in
+ // the 16-bit DLGTEMPLATE.
+ //
+ // The other half of this magic is accomplished in USERSRV's
+ // xxxServerCreateDialog, which special-cases the creation
+ // of controls in a WOW dialog box. USERSRV will pass the
+ // DWORD pointed to by lpCreateParams instead of lpCreateParams
+ // to CreateWindow. This DWORD is the 16:16 pointer to the
+ // 16-bit DLGTEMPLATE's createparams.
+ //
+ // DaveHart 14-Mar-93
+ //
+
+ if (b != 0) {
+
+ // store 32-bit createparams size (room for 16:16 ptr)
+
+ PUTWORD(pdlg32, sizeof(pdlg16));
+ //ALIGNDWORD(pdlg32);
+
+ // store 16:16 pointer in 32-bit createparams
+
+ PUTUDWORD(pdlg32, (DWORD)vpdlg16 + (DWORD)(pdlg16 - pdlg16Save));
+
+ // point pdlg16 past createparams
+
+ ADVGET(pdlg16, b);
+
+ } else {
+
+ // there are no createparams, store size of zero.
+
+ PUTWORD(pdlg32, 0);
+ //ALIGNDWORD(pdlg32);
+ }
+
+ }
+ FREEVDMPTR(pdlg16Save);
+ RETURN(pdlg32 - pdlg32T);
+}
diff --git a/private/mvdm/wow32/wres16.h b/private/mvdm/wow32/wres16.h
new file mode 100644
index 000000000..82a2feee5
--- /dev/null
+++ b/private/mvdm/wow32/wres16.h
@@ -0,0 +1,48 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WRES16.H
+ * WOW32 16-bit resource support
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+/* Resource table entries
+ */
+#define RES_ALIASPTR 0x0001 // pbResData is 32-bit alias ptr
+
+#pragma pack(2)
+typedef struct _RES { /* res */
+ struct _RES *presNext; // pointer to next res entry
+ HMOD16 hmod16; // 16-bit handle of owning task
+ WORD wExeVer; // exe version
+ ULONG flState; // misc. flags (see RES_*)
+ HRESI16 hresinfo16; // 16-bit handle of resource info
+ HRESD16 hresdata16; // 16-bit handle of resource data
+ LPSZ lpszResType; // type of resource
+ PBYTE pbResData; // pointer to copy of converted resource data
+} RES, *PRES, **PPRES;
+#pragma pack()
+
+
+/* Function prototypes
+ */
+PRES AddRes16(HMOD16 hmod16, WORD wExeVer, HRESI16 hresinfo16, LPSZ lpszType);
+VOID FreeRes16(PRES pres);
+VOID DestroyRes16(HMOD16 hmod16);
+
+PRES FindResource16(HMOD16 hmod16, LPSZ lpszName, LPSZ lpszType);
+PRES LoadResource16(HMOD16 hmod16, PRES pres);
+BOOL FreeResource16(PRES pres);
+LPBYTE LockResource16(PRES pres);
+BOOL UnlockResource16(PRES pres);
+DWORD SizeofResource16(HMOD16 hmod16, PRES pres);
+
+DWORD ConvertMenu16(WORD wExeVer, PBYTE pmenu32, VPBYTE vpmenu16, DWORD cb, DWORD cb16);
+DWORD ConvertMenuItems16(WORD wExeVer, PPBYTE ppmenu32, PPBYTE ppmenu16, VPBYTE vpmenu16);
+DWORD ConvertDialog16(PBYTE pdlg32, VPBYTE vpdlg16, DWORD cb, DWORD cb16);
diff --git a/private/mvdm/wow32/wres32.c b/private/mvdm/wow32/wres32.c
new file mode 100644
index 000000000..f5dd30b0d
--- /dev/null
+++ b/private/mvdm/wow32/wres32.c
@@ -0,0 +1,126 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WRES32.C
+ * WOW32 16-bit resource support
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wres32.c);
+
+HANDLE APIENTRY W32FindResource(HANDLE hModule, LPCSTR lpType, LPCSTR lpName, WORD wLang)
+{
+ PRES p;
+
+ //
+ // If hModule is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if (LOWORD (hModule) == 0) {
+ return (FindResourceEx(hModule, lpType, lpName, wLang));
+ }
+ else {
+ WOW32ASSERT(GETHMOD16(hModule));
+ p = FindResource16(GETHMOD16(hModule), (LPSTR)lpName, (LPSTR)lpType);
+ return HRES32(p);
+ }
+
+}
+
+HANDLE APIENTRY W32LoadResource(HANDLE hModule, HANDLE hResInfo)
+{
+ PRES p;
+
+ //
+ // If hModule is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if (ISINST16(hModule) && ISRES16(hResInfo)) {
+ WOW32ASSERT(GETHMOD16(hModule));
+ p = LoadResource16(GETHMOD16(hModule), GETHRES16(hResInfo));
+ return HRES32(p);
+ }
+ else {
+ return LoadResource(hModule, hResInfo);
+ }
+}
+
+
+BOOL APIENTRY W32FreeResource(HANDLE hResData, HANDLE hModule)
+{
+
+ //
+ // If hModule is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if ((LOWORD (hModule) != 0) && ISRES16(hResData)) {
+ return FreeResource16(GETHRES16(hResData));
+ }
+ else {
+ return (FreeResource(hResData));
+ }
+}
+
+
+LPSTR APIENTRY W32LockResource(HANDLE hResData, HANDLE hModule)
+{
+
+ //
+ // If hModule is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if ((LOWORD (hModule) != 0) && ISRES16(hResData)) {
+ return LockResource16(GETHRES16(hResData));
+ }
+ else {
+ return (LockResource(hResData));
+ }
+}
+
+
+BOOL APIENTRY W32UnlockResource(HANDLE hResData, HANDLE hModule)
+{
+
+ //
+ // If hModule is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if ((LOWORD (hModule) != 0) && ISRES16(hResData)) {
+ return UnlockResource16(GETHRES16(hResData));
+ }
+ else {
+ return (UnlockResource(hResData));
+ }
+}
+
+
+DWORD APIENTRY W32SizeofResource(HANDLE hModule, HANDLE hResInfo)
+{
+
+ //
+ // If hModule is not ours, then make Win32 call and return the
+ // result to USER.
+ //
+
+ if ((LOWORD (hModule) != 0) && ISINST16(hModule) && ISRES16(hResInfo)) {
+ WOW32ASSERT(GETHMOD16(hModule));
+ return SizeofResource16(GETHMOD16(hModule), GETHRES16(hResInfo));
+ }
+ else {
+ return (SizeofResource(hModule, hResInfo));
+ }
+}
diff --git a/private/mvdm/wow32/wres32.h b/private/mvdm/wow32/wres32.h
new file mode 100644
index 000000000..50776a73e
--- /dev/null
+++ b/private/mvdm/wow32/wres32.h
@@ -0,0 +1,21 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WRES32.H
+ * WOW32 16-bit resource support
+ *
+ * History:
+ * Created 11-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+/* Function prototypes
+ */
+HANDLE APIENTRY W32FindResource(HANDLE hModule, LPCSTR lpType, LPCSTR lpName, WORD wLangId);
+HANDLE APIENTRY W32LoadResource(HANDLE hModule, HANDLE hResInfo);
+BOOL APIENTRY W32FreeResource(HANDLE hResData, HANDLE hModule);
+LPSTR APIENTRY W32LockResource(HANDLE hResData, HANDLE hModule);
+BOOL APIENTRY W32UnlockResource(HANDLE hResData, HANDLE hModule);
+DWORD APIENTRY W32SizeofResource(HANDLE hModule, HANDLE hResInfo);
diff --git a/private/mvdm/wow32/wsdata.c b/private/mvdm/wow32/wsdata.c
new file mode 100644
index 000000000..e12d83314
--- /dev/null
+++ b/private/mvdm/wow32/wsdata.c
@@ -0,0 +1,1875 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ Wsraw.h
+
+Abstract:
+
+ Support for database winsock calls for WOW.
+
+Author:
+
+ David Treadwell (davidtr) 02-Oct-1992
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wsdynmc.h"
+
+#define FIND_16_OFFSET_FROM_32(base16, base32, actual32) \
+ ( (DWORD)base16 + ( (DWORD)actual32 - (DWORD)base32 ) )
+
+DWORD
+BytesInHostent32 (
+ PHOSTENT Hostent32
+ );
+
+DWORD
+CopyHostent32To16 (
+ PHOSTENT16 Hostent16,
+ VPHOSTENT16 VHostent16,
+ int BufferLength,
+ PHOSTENT Hostent32
+ );
+
+DWORD
+BytesInProtoent32 (
+ PPROTOENT Protoent32
+ );
+
+DWORD
+CopyProtoent32To16 (
+ PPROTOENT16 Protoent16,
+ VPPROTOENT16 VProtoent16,
+ int BufferLength,
+ PPROTOENT Protoent32
+ );
+
+DWORD
+BytesInServent32 (
+ PSERVENT Servent32
+ );
+
+DWORD
+CopyServent32To16 (
+ PSERVENT16 Servent16,
+ VPSERVENT16 VServent16,
+ int BufferLength,
+ PSERVENT Servent32
+ );
+
+/*++
+
+ GENERIC FUNCTION PROTOTYPE:
+ ==========================
+
+ULONG FASTCALL WWS32<function name>(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register P<function name>16 parg16;
+
+ GETARGPTR(pFrame, sizeof(<function name>16), parg16);
+
+ <get any other required pointers into 16 bit space>
+
+ ALLOCVDMPTR
+ GETVDMPTR
+ GETMISCPTR
+ et cetera
+
+ <copy any complex structures from 16 bit -> 32 bit space>
+ <ALWAYS use the FETCHxxx macros>
+
+ ul = GET<return type>16(<function name>(parg16->f1,
+ :
+ :
+ parg16->f<n>);
+
+ <copy any complex structures from 32 -> 16 bit space>
+ <ALWAYS use the STORExxx macros>
+
+ <free any pointers to 16 bit space you previously got>
+
+ <flush any areas of 16 bit memory if they were written to>
+
+ FLUSHVDMPTR
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+NOTE:
+
+ The VDM frame is automatically set up, with all the function parameters
+ available via parg16->f<number>.
+
+ Handles must ALWAYS be mapped for 16 -> 32 -> 16 space via the mapping tables
+ laid out in WALIAS.C.
+
+ Any storage you allocate must be freed (eventually...).
+
+ Further to that - if a thunk which allocates memory fails in the 32 bit call
+ then it must free that memory.
+
+ Also, never update structures in 16 bit land if the 32 bit call fails.
+
+ Be aware that the GETxxxPTR macros return the CURRENT selector-to-flat_memory
+ mapping. Calls to some 32-bit functions may indirectly cause callbacks into
+ 16-bit code. These may cause 16-bit memory to move due to allocations
+ made in 16-bit land. If the 16-bit memory does move, the corresponding 32-bit
+ ptr in WOW32 needs to be refreshed to reflect the NEW selector-to-flat_memory
+ mapping.
+
+--*/
+
+ULONG FASTCALL WWS32gethostbyaddr(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETHOSTBYADDR16 parg16;
+ PDWORD paddr16;
+ PHOSTENT hostent32;
+ PHOSTENT16 hostent16;
+ DWORD bytesRequired;
+ DWORD addr32; // address must be in PF_INET format (length == 4 bytes)
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)NULL);
+ }
+
+ GETARGPTR( pFrame, sizeof(GETHOSTBYADDR16), parg16 );
+ GETVDMPTR( parg16->Address, sizeof(DWORD), paddr16 );
+
+ addr32 = *paddr16; // copy the 4-byte address
+
+ hostent32 = (PHOSTENT) (*wsockapis[WOW_GETHOSTBYADDR].lpfn)((CHAR *)&addr32,
+ parg16->Length,
+ parg16->Type);
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEVDMPTR(paddr16);
+ FREEARGPTR(parg16);
+
+ if ( hostent32 != NULL ) {
+
+ GETVDMPTR( WWS32vHostent, MAXGETHOSTSTRUCT, hostent16 );
+ bytesRequired = CopyHostent32To16(
+ hostent16,
+ WWS32vHostent,
+ MAXGETHOSTSTRUCT,
+ hostent32
+ );
+ ASSERT( bytesRequired < MAXGETHOSTSTRUCT );
+
+ FLUSHVDMPTR( WWS32vHostent, (USHORT) bytesRequired, hostent16 );
+ FREEVDMPTR( hostent16 );
+ ul = WWS32vHostent;
+
+ } else {
+
+ ul = 0;
+ }
+
+ FREEVDMPTR( paddr16 );
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+
+} // WWS32gethostbyaddr
+
+ULONG FASTCALL WWS32gethostbyname(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETHOSTBYNAME16 parg16;
+ PHOSTENT hostent32;
+ PHOSTENT16 hostent16;
+ PSZ name32 = NULL;
+ PSZ name16;
+ DWORD bytesRequired;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)NULL);
+ }
+
+ GETARGPTR( pFrame, sizeof(GETHOSTBYNAME16), parg16 );
+
+ GETVDMPTR( parg16->Name, 32, name16 );
+
+ if(name16) {
+ name32 = malloc_w(strlen(name16)+1);
+ strcpy(name32, name16);
+ }
+
+ hostent32 = (PHOSTENT) (*wsockapis[WOW_GETHOSTBYNAME].lpfn)( name32 );
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEVDMPTR(name16);
+ FREEARGPTR(parg16);
+
+ if(name32) {
+ free_w(name32);
+ }
+
+ if ( hostent32 != NULL ) {
+
+ GETVDMPTR( WWS32vHostent, MAXGETHOSTSTRUCT, hostent16 );
+ bytesRequired = CopyHostent32To16(
+ hostent16,
+ WWS32vHostent,
+ MAXGETHOSTSTRUCT,
+ hostent32
+ );
+ ASSERT( bytesRequired < MAXGETHOSTSTRUCT );
+
+ FLUSHVDMPTR( WWS32vHostent, (USHORT) bytesRequired, hostent16 );
+ FREEVDMPTR( hostent16 );
+ ul = WWS32vHostent;
+
+ } else {
+
+ ul = 0;
+ }
+
+ FREEVDMPTR( name32 );
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+
+} // WWS32gethostbyname
+
+ULONG FASTCALL WWS32gethostname(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETHOSTNAME16 parg16;
+ PCHAR name32 = NULL;
+ PCHAR name16;
+ INT NameLength;
+ VPSZ vpszName;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)NULL);
+ }
+
+ GETARGPTR( pFrame, sizeof(GETHOSTNAME16), parg16 );
+
+ vpszName = FETCHDWORD(parg16->Name);
+ NameLength = INT32(parg16->NameLength);
+
+ if(vpszName) {
+ name32 = malloc_w(NameLength);
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_GETHOSTNAME].lpfn)( name32, NameLength ) );
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEVDMPTR(name16);
+ FREEARGPTR(parg16);
+
+ GETVDMPTR( vpszName, NameLength, name16 );
+ if(name16 && name32) {
+ strcpy(name16, name32);
+ }
+ FLUSHVDMPTR( vpszName, NameLength, name16 );
+
+ FREEVDMPTR( name16 );
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+
+} // WWS32gethostname
+
+ULONG FASTCALL WWS32WSAAsyncGetHostByAddr(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWSAASYNCGETHOSTBYADDR16 parg16;
+ PWINSOCK_ASYNC_CONTEXT_BLOCK context;
+ PVOID buffer32;
+ PDWORD paddr16;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN(0);
+ }
+
+ GETARGPTR( pFrame, sizeof(WSAASYNCGETHOSTBYADDR16), parg16 );
+ GETVDMPTR( parg16->Address, sizeof(DWORD), paddr16 );
+
+ //
+ // Set up locals so we know how to clean up on exit.
+ //
+
+ context = NULL;
+ buffer32 = NULL;
+ ul = 0;
+
+ //
+ // Allocate a context block and 32-bit buffer to use for the request.
+ //
+
+ context = malloc_w( sizeof(*context) );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ buffer32 = malloc_w( MAXGETHOSTSTRUCT );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ //
+ // Fill in entries in the context buffer.
+ //
+
+ context->Buffer32 = buffer32;
+ context->vBuffer16 = parg16->Buffer;
+ context->Buffer16Length = parg16->BufferLength;
+
+ //
+ // Enter a critical section to synchronize access to the context block
+ // and their global list.
+ //
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ context->AsyncTaskHandle32 = (HANDLE) (*wsockapis[WOW_WSAASYNCGETHOSTBYADDR].lpfn)(
+ (HWND)HWND32(parg16->hWnd),
+ (parg16->wMsg << 16) |
+ WWS32_MESSAGE_ASYNC_GETHOST,
+ (char *)paddr16,
+ parg16->Length,
+ parg16->Type,
+ buffer32,
+ MAXGETHOSTSTRUCT);
+
+ if ( context->AsyncTaskHandle32 != 0 ) {
+
+ //
+ // The call succeeded so get a 16-bit task handle for this
+ // request and place the context block on the global list. The
+ // resources will be freed by WWS32PostAsyncGetHost.
+ //
+
+ ul = WWS32GetAsyncTaskHandle16( );
+ context->AsyncTaskHandle16 = (HAND16)ul;
+
+ InsertTailList(
+ &WWS32AsyncContextBlockListHead,
+ &context->ContextBlockListEntry
+ );
+ }
+
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+exit:
+
+ if ( ul == 0 ) {
+
+ if ( context != NULL ) {
+ free_w( (PVOID)context );
+ }
+
+ if ( buffer32 != NULL ) {
+ free_w( buffer32 );
+ }
+ }
+
+ FREEVDMPTR( paddr16 );
+ FREEARGPTR( parg16 );
+
+ RETURN(ul);
+
+} // WWS32WSAAsyncGetHostByAddr
+
+ULONG FASTCALL WWS32WSAAsyncGetHostByName(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWSAASYNCGETHOSTBYNAME16 parg16;
+ PWINSOCK_ASYNC_CONTEXT_BLOCK context;
+ PVOID buffer32;
+ PCHAR name32;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN(0);
+ }
+
+ GETARGPTR( pFrame, sizeof(WSAASYNCGETHOSTBYNAME16), parg16 );
+ GETVDMPTR( parg16->Name, 32, name32 );
+
+ //
+ // Set up locals so we know how to clean up on exit.
+ //
+
+ context = NULL;
+ buffer32 = NULL;
+ ul = 0;
+
+ //
+ // Allocate a context block and 32-bit buffer to use for the request.
+ //
+
+ context = malloc_w( sizeof(*context) );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ buffer32 = malloc_w( MAXGETHOSTSTRUCT );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ //
+ // Fill in entries in the context buffer.
+ //
+
+ context->Buffer32 = buffer32;
+ context->vBuffer16 = parg16->Buffer;
+ context->Buffer16Length = parg16->BufferLength;
+
+ //
+ // Enter a critical section to synchronize access to the context block
+ // and their global list.
+ //
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ context->AsyncTaskHandle32 = (HANDLE) (*wsockapis[WOW_WSAASYNCGETHOSTBYNAME].lpfn)(
+ (HWND)HWND32(parg16->hWnd),
+ (parg16->wMsg << 16) |
+ WWS32_MESSAGE_ASYNC_GETHOST,
+ name32,
+ buffer32,
+ MAXGETHOSTSTRUCT
+ );
+
+ if ( context->AsyncTaskHandle32 != 0 ) {
+
+ //
+ // The call succeeded so get a 16-bit task handle for this
+ // request and place the context block on the global list. The
+ // resources will be freed by WWS32PostAsyncGetHost.
+ //
+
+ ul = WWS32GetAsyncTaskHandle16( );
+ context->AsyncTaskHandle16 = (HAND16)ul;
+
+ InsertTailList(
+ &WWS32AsyncContextBlockListHead,
+ &context->ContextBlockListEntry
+ );
+ }
+
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+exit:
+
+ if ( ul == 0 ) {
+
+ if ( context != NULL ) {
+ free_w( (PVOID)context );
+ }
+
+ if ( buffer32 != NULL ) {
+ free_w( buffer32 );
+ }
+ }
+
+ FREEVDMPTR( name32 );
+ FREEARGPTR( parg16 );
+
+ RETURN(ul);
+
+} // WWS32WSAAsyncGetHostByName
+
+
+BOOL
+WWS32PostAsyncGetHost (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ PWINSOCK_ASYNC_CONTEXT_BLOCK context;
+ BOOL ret;
+ PVOID buffer16;
+ DWORD bytesRequired;
+
+ context = WWS32FindAndRemoveAsyncContext( (HANDLE)wParam );
+ ASSERT( context != NULL );
+
+ //
+ // If the call was successful, copy the 32-bit buffer to the
+ // 16-bit buffer specified by the application.
+ //
+
+ if ( WSAGETASYNCERROR( lParam ) == 0 ) {
+
+ //
+ // Copy the 32-bit structure to 16-bit buffer.
+ //
+
+ GETVDMPTR( context->vBuffer16, context->Buffer16Length, buffer16 );
+
+ bytesRequired = CopyHostent32To16(
+ buffer16,
+ context->vBuffer16,
+ context->Buffer16Length,
+ context->Buffer32
+ );
+
+ //
+ // If the application's buffer was too small, return an error
+ // and information aqbout the buffer size required.
+ //
+
+ if ( bytesRequired > context->Buffer16Length ) {
+ lParam = WSAMAKEASYNCREPLY( (WORD)bytesRequired, WSAENOBUFS );
+ }
+ }
+
+ //
+ // Post the completion message to the 16-bit application.
+ //
+
+ ret = PostMessage(
+ hWnd,
+ Msg >> 16,
+ context->AsyncTaskHandle16,
+ lParam
+ );
+
+ //
+ // Free resources and return.
+ //
+
+ free_w( context->Buffer32 );
+ free_w( (PVOID)context );
+
+ return ret;
+
+} // WWS32PostAsyncGetHost
+
+
+DWORD
+CopyHostent32To16 (
+ PHOSTENT16 Hostent16,
+ VPHOSTENT16 VHostent16,
+ int BufferLength,
+ PHOSTENT Hostent32
+ )
+{
+ DWORD requiredBufferLength;
+ DWORD bytesFilled;
+ PCHAR currentLocation = (PCHAR)Hostent16;
+ DWORD aliasCount;
+ DWORD addressCount;
+ DWORD i;
+ VPBYTE *addrList16;
+ VPSZ *aliases16;
+
+ //
+ // Determine how many bytes are needed to fully copy the structure.
+ //
+
+ requiredBufferLength = BytesInHostent32( Hostent32 );
+
+ //
+ // Copy over the hostent structure if it fits.
+ //
+
+ bytesFilled = sizeof(*Hostent32);
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ return requiredBufferLength;
+ }
+
+ STOREWORD( Hostent16->h_addrtype, Hostent32->h_addrtype );
+ STOREWORD( Hostent16->h_length, Hostent32->h_length );
+ currentLocation = (PCHAR)Hostent16 + bytesFilled;
+
+ //
+ // Count the host's aliases and set up an array to hold pointers to
+ // them.
+ //
+
+ for ( aliasCount = 0;
+ Hostent32->h_aliases[aliasCount] != NULL;
+ aliasCount++ );
+
+ bytesFilled += (aliasCount+1) * sizeof(char FAR *);
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ Hostent32->h_aliases = NULL;
+ return requiredBufferLength;
+ }
+
+ Hostent16->h_aliases =
+ FIND_16_OFFSET_FROM_32( VHostent16, Hostent16, currentLocation );
+ aliases16 = (VPSZ *)currentLocation;
+ currentLocation = (PCHAR)Hostent16 + bytesFilled;
+
+ //
+ // Count the host's addresses and set up an array to hold pointers to
+ // them.
+ //
+
+ for ( addressCount = 0;
+ Hostent32->h_addr_list[addressCount] != NULL;
+ addressCount++ );
+
+ bytesFilled += (addressCount+1) * sizeof(void FAR *);
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ Hostent32->h_addr_list = NULL;
+ return requiredBufferLength;
+ }
+
+ Hostent16->h_addr_list =
+ FIND_16_OFFSET_FROM_32( VHostent16, Hostent16, currentLocation );
+ addrList16 = (VPBYTE *)currentLocation;
+ currentLocation = (PCHAR)Hostent16 + bytesFilled;
+
+ //
+ // Start filling in addresses. Do addresses before filling in the
+ // host name and aliases in order to avoid alignment problems.
+ //
+
+ for ( i = 0; i < addressCount; i++ ) {
+
+ bytesFilled += Hostent32->h_length;
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ STOREDWORD( addrList16[i], 0 );
+ return requiredBufferLength;
+ }
+
+ STOREDWORD(
+ addrList16[i],
+ FIND_16_OFFSET_FROM_32( VHostent16, Hostent16, currentLocation )
+ );
+
+ RtlMoveMemory(
+ currentLocation,
+ Hostent32->h_addr_list[i],
+ Hostent32->h_length
+ );
+
+ currentLocation = (PCHAR)Hostent16 + bytesFilled;
+ }
+
+ STOREDWORD( addrList16[i], 0 );
+
+ //
+ // Copy the host name if it fits.
+ //
+
+ bytesFilled += strlen( Hostent32->h_name ) + 1;
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ return requiredBufferLength;
+ }
+
+ Hostent16->h_name =
+ FIND_16_OFFSET_FROM_32( VHostent16, Hostent16, currentLocation );
+
+ RtlMoveMemory( currentLocation, Hostent32->h_name, strlen( Hostent32->h_name ) + 1 );
+ currentLocation = (PCHAR)Hostent16 + bytesFilled;
+
+ //
+ // Start filling in aliases.
+ //
+
+ for ( i = 0; i < aliasCount; i++ ) {
+
+ bytesFilled += strlen( Hostent32->h_aliases[i] ) + 1;
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ STOREDWORD( aliases16[i], 0 );
+ return requiredBufferLength;
+ }
+
+ STOREDWORD(
+ aliases16[i],
+ FIND_16_OFFSET_FROM_32( VHostent16, Hostent16, currentLocation )
+ );
+
+ RtlMoveMemory(
+ currentLocation,
+ Hostent32->h_aliases[i],
+ strlen( Hostent32->h_aliases[i] ) + 1
+ );
+
+ currentLocation = (PCHAR)Hostent16 + bytesFilled;
+ }
+
+ STOREDWORD( aliases16[i], 0 );
+
+ return requiredBufferLength;
+
+} // CopyHostentToBuffer
+
+
+DWORD
+BytesInHostent32 (
+ PHOSTENT Hostent32
+ )
+{
+ DWORD total;
+ int i;
+
+ total = sizeof(HOSTENT);
+ total += strlen( Hostent32->h_name ) + 1;
+ total += sizeof(char *) + sizeof(char *);
+
+ for ( i = 0; Hostent32->h_aliases[i] != NULL; i++ ) {
+ total += strlen( Hostent32->h_aliases[i] ) + 1 + sizeof(char *);
+ }
+
+ for ( i = 0; Hostent32->h_addr_list[i] != NULL; i++ ) {
+ total += Hostent32->h_length + sizeof(char *);
+ }
+
+ return total;
+
+} // BytesInHostent
+
+ULONG FASTCALL WWS32getprotobyname(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETPROTOBYNAME16 parg16;
+ PPROTOENT protoent32;
+ PPROTOENT16 protoent16;
+ PSZ name32 = NULL;
+ PBYTE name16;
+ DWORD bytesRequired;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)NULL);
+ }
+
+ GETARGPTR( pFrame, sizeof(GETPROTOBYNAME16), parg16 );
+ GETVDMPTR( parg16->Name, 32, name16 );
+
+ if(name16) {
+ name32 = malloc_w(strlen(name16)+1);
+ strcpy(name32, name16);
+ }
+
+ protoent32 = (PPROTOENT) (*wsockapis[WOW_GETPROTOBYNAME].lpfn)( name32 );
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEVDMPTR(name16);
+ FREEARGPTR(parg16);
+
+ if(name32) {
+ free_w( name32 );
+ }
+
+ if ( protoent32 != NULL ) {
+
+ GETVDMPTR( WWS32vProtoent, MAXGETHOSTSTRUCT, protoent16 );
+ bytesRequired = CopyProtoent32To16(
+ protoent16,
+ WWS32vProtoent,
+ MAXGETHOSTSTRUCT,
+ protoent32
+ );
+ ASSERT( bytesRequired < MAXGETHOSTSTRUCT );
+
+ FLUSHVDMPTR( WWS32vProtoent, (USHORT) bytesRequired, protoent16 );
+ FREEVDMPTR( protoent16 );
+ ul = WWS32vProtoent;
+
+ } else {
+
+ ul = 0;
+ }
+
+ FREEVDMPTR(name16);
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+
+} // WWS32getprotobyname
+
+ULONG FASTCALL WWS32getprotobynumber(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETPROTOBYNUMBER16 parg16;
+ PPROTOENT protoent32;
+ PPROTOENT16 protoent16;
+ DWORD bytesRequired;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)NULL);
+ }
+
+ GETARGPTR( pFrame, sizeof(GETPROTOBYNUMBER16), parg16 );
+
+ protoent32 = (PPROTOENT) (*wsockapis[WOW_GETPROTOBYNUMBER].lpfn)( parg16->Protocol );
+
+ if ( protoent32 != NULL ) {
+
+ GETVDMPTR( WWS32vProtoent, MAXGETHOSTSTRUCT, protoent16 );
+ bytesRequired = CopyProtoent32To16(
+ protoent16,
+ WWS32vProtoent,
+ MAXGETHOSTSTRUCT,
+ protoent32
+ );
+ ASSERT( bytesRequired < MAXGETHOSTSTRUCT );
+
+ FLUSHVDMPTR( WWS32vProtoent, (USHORT) bytesRequired, protoent16 );
+ FREEVDMPTR( protoent16 );
+ ul = WWS32vProtoent;
+
+ } else {
+
+ ul = 0;
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+
+} // WWS32getprotobynumber
+
+ULONG FASTCALL WWS32WSAAsyncGetProtoByName(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWSAASYNCGETPROTOBYNAME16 parg16;
+ PWINSOCK_ASYNC_CONTEXT_BLOCK context;
+ PVOID buffer32;
+ PSZ name32;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN(0);
+ }
+
+ GETARGPTR( pFrame, sizeof(WSAASYNCGETPROTOBYNAME16), parg16 );
+ GETVDMPTR( parg16->Name, 32, name32 );
+
+ //
+ // Set up locals so we know how to clean up on exit.
+ //
+
+ context = NULL;
+ buffer32 = NULL;
+ ul = 0;
+
+ //
+ // Allocate a context block and 32-bit buffer to use for the request.
+ //
+
+ context = malloc_w( sizeof(*context) );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ buffer32 = malloc_w( MAXGETHOSTSTRUCT );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ //
+ // Fill in entries in the context buffer.
+ //
+
+ context->Buffer32 = buffer32;
+ context->vBuffer16 = parg16->Buffer;
+ context->Buffer16Length = parg16->BufferLength;
+
+ //
+ // Enter a critical section to synchronize access to the context block
+ // and their global list.
+ //
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ context->AsyncTaskHandle32 = (HANDLE) (*wsockapis[WOW_WSAASYNCGETPROTOBYNAME].lpfn)(
+ (HWND)HWND32(parg16->hWnd),
+ (parg16->wMsg << 16) |
+ WWS32_MESSAGE_ASYNC_GETPROTO,
+ name32,
+ buffer32,
+ MAXGETHOSTSTRUCT
+ );
+
+ if ( context->AsyncTaskHandle32 != 0 ) {
+
+ //
+ // The call succeeded so get a 16-bit task handle for this
+ // request and place the context block on the global list. The
+ // resources will be freed by WWS32PostAsyncGetProto.
+ //
+
+ ul = WWS32GetAsyncTaskHandle16( );
+ context->AsyncTaskHandle16 = (HAND16)ul;
+
+ InsertTailList(
+ &WWS32AsyncContextBlockListHead,
+ &context->ContextBlockListEntry
+ );
+ }
+
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+exit:
+
+ if ( ul == 0 ) {
+
+ if ( context != NULL ) {
+ free_w( (PVOID)context );
+ }
+
+ if ( buffer32 != NULL ) {
+ free_w( buffer32 );
+ }
+ }
+
+ FREEARGPTR( name32 );
+ FREEARGPTR( parg16 );
+
+ RETURN(ul);
+
+} // WWS32WSAAsyncGetProtoByName
+
+ULONG FASTCALL WWS32WSAAsyncGetProtoByNumber(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWSAASYNCGETPROTOBYNUMBER16 parg16;
+ PWINSOCK_ASYNC_CONTEXT_BLOCK context;
+ PVOID buffer32;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN(0);
+ }
+
+ GETARGPTR( pFrame, sizeof(WSAASYNCGETPROTOBYNUMBER16), parg16 );
+
+ //
+ // Set up locals so we know how to clean up on exit.
+ //
+
+ context = NULL;
+ buffer32 = NULL;
+ ul = 0;
+
+ //
+ // Allocate a context block and 32-bit buffer to use for the request.
+ //
+
+ context = malloc_w( sizeof(*context) );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ buffer32 = malloc_w( MAXGETHOSTSTRUCT );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ //
+ // Fill in entries in the context buffer.
+ //
+
+ context->Buffer32 = buffer32;
+ context->vBuffer16 = parg16->Buffer;
+ context->Buffer16Length = parg16->BufferLength;
+
+ //
+ // Enter a critical section to synchronize access to the context block
+ // and their global list.
+ //
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ context->AsyncTaskHandle32 = (HANDLE) (*wsockapis[WOW_WSAASYNCGETPROTOBYNUMBER].lpfn)(
+ (HWND)HWND32(parg16->hWnd),
+ (parg16->wMsg << 16) |
+ WWS32_MESSAGE_ASYNC_GETPROTO,
+ parg16->Number,
+ buffer32,
+ MAXGETHOSTSTRUCT
+ );
+
+ if ( context->AsyncTaskHandle32 != 0 ) {
+
+ //
+ // The call succeeded so get a 16-bit task handle for this
+ // request and place the context block on the global list. The
+ // resources will be freed by WWS32PostAsyncGetProto.
+ //
+
+ ul = WWS32GetAsyncTaskHandle16( );
+ context->AsyncTaskHandle16 = (HAND16)ul;
+
+ InsertTailList(
+ &WWS32AsyncContextBlockListHead,
+ &context->ContextBlockListEntry
+ );
+ }
+
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+exit:
+
+ if ( ul == 0 ) {
+
+ if ( context != NULL ) {
+ free_w( (PVOID)context );
+ }
+
+ if ( buffer32 != NULL ) {
+ free_w( buffer32 );
+ }
+ }
+
+ FREEARGPTR( parg16 );
+
+ RETURN(ul);
+
+} // WWS32WSAAsyncGetProtoByNumber
+
+
+BOOL
+WWS32PostAsyncGetProto (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ PWINSOCK_ASYNC_CONTEXT_BLOCK context;
+ BOOL ret;
+ PVOID buffer16;
+ DWORD bytesRequired;
+
+ context = WWS32FindAndRemoveAsyncContext( (HANDLE)wParam );
+ ASSERT( context != NULL );
+
+ //
+ // If the call was successful, copy the 32-bit buffer to the
+ // 16-bit buffer specified by the application.
+ //
+
+ if ( WSAGETASYNCERROR( lParam ) == 0 ) {
+
+ //
+ // Copy the 32-bit structure to 16-bit buffer.
+ //
+
+ GETVDMPTR( context->vBuffer16, context->Buffer16Length, buffer16 );
+
+ bytesRequired = CopyProtoent32To16(
+ buffer16,
+ context->vBuffer16,
+ context->Buffer16Length,
+ context->Buffer32
+ );
+
+ //
+ // If the application's buffer was too small, return an error
+ // and information aqbout the buffer size required.
+ //
+
+ if ( bytesRequired > context->Buffer16Length ) {
+ lParam = WSAMAKEASYNCREPLY( (WORD)bytesRequired, WSAENOBUFS );
+ }
+ }
+
+ //
+ // Post the completion message to the 16-bit application.
+ //
+
+ ret = PostMessage(
+ hWnd,
+ Msg >> 16,
+ context->AsyncTaskHandle16,
+ lParam
+ );
+
+ //
+ // Free resources and return.
+ //
+
+ free_w( context->Buffer32 );
+ free_w( (PVOID)context );
+
+ return ret;
+
+} // WWS32PostAsyncGetProto
+
+
+DWORD
+CopyProtoent32To16 (
+ PPROTOENT16 Protoent16,
+ VPPROTOENT16 VProtoent16,
+ int BufferLength,
+ PPROTOENT Protoent32
+ )
+{
+ DWORD requiredBufferLength;
+ DWORD bytesFilled;
+ PCHAR currentLocation = (PCHAR)Protoent16;
+ DWORD aliasCount;
+ DWORD i;
+ VPBYTE *aliases16;
+
+ //
+ // Determine how many bytes are needed to fully copy the structure.
+ //
+
+ requiredBufferLength = BytesInProtoent32( Protoent32 );
+
+ //
+ // Copy over the protoent structure if it fits.
+ //
+
+ bytesFilled = sizeof(*Protoent16);
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ return requiredBufferLength;
+ }
+
+ STOREWORD( Protoent16->p_proto, Protoent32->p_proto );
+ currentLocation = (PCHAR)Protoent16 + bytesFilled;
+
+ //
+ // Count the protocol's aliases and set up an array to hold pointers to
+ // them.
+ //
+
+ for ( aliasCount = 0;
+ Protoent32->p_aliases[aliasCount] != NULL;
+ aliasCount++ );
+
+ bytesFilled += (aliasCount+1) * sizeof(char FAR *);
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ Protoent16->p_aliases = 0;
+ return requiredBufferLength;
+ }
+
+ Protoent16->p_aliases =
+ FIND_16_OFFSET_FROM_32( VProtoent16, Protoent16, currentLocation );
+ aliases16 = (VPBYTE *)currentLocation;
+ currentLocation = (PCHAR)Protoent16 + bytesFilled;
+
+ //
+ // Copy the protocol name if it fits.
+ //
+
+ bytesFilled += strlen( Protoent32->p_name ) + 1;
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ return requiredBufferLength;
+ }
+
+ Protoent16->p_name =
+ FIND_16_OFFSET_FROM_32( VProtoent16, Protoent16, currentLocation );
+
+ RtlMoveMemory( currentLocation, Protoent32->p_name, strlen( Protoent32->p_name ) + 1 );
+ currentLocation = (PCHAR)Protoent16 + bytesFilled;
+
+ //
+ // Start filling in aliases.
+ //
+
+ for ( i = 0; i < aliasCount; i++ ) {
+
+ bytesFilled += strlen( Protoent32->p_aliases[i] ) + 1;
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ STOREDWORD( aliases16[i], 0 );
+ return requiredBufferLength;
+ }
+
+ STOREDWORD(
+ aliases16[i],
+ FIND_16_OFFSET_FROM_32( VProtoent16, Protoent16, currentLocation )
+ );
+
+ RtlMoveMemory(
+ currentLocation,
+ Protoent32->p_aliases[i],
+ strlen( Protoent32->p_aliases[i] ) + 1
+ );
+
+ currentLocation = (PCHAR)Protoent16 + bytesFilled;
+ }
+
+ STOREDWORD( aliases16[i], 0 );
+
+ return requiredBufferLength;
+
+} // CopyProtoent32To16
+
+
+DWORD
+BytesInProtoent32 (
+ PPROTOENT Protoent32
+ )
+{
+ DWORD total;
+ int i;
+
+ total = sizeof(PROTOENT);
+ total += strlen( Protoent32->p_name ) + 1;
+ total += sizeof(char *);
+
+ for ( i = 0; Protoent32->p_aliases[i] != NULL; i++ ) {
+ total += strlen( Protoent32->p_aliases[i] ) + 1 + sizeof(char *);
+ }
+
+ return total;
+
+} // BytesInProtoent32
+
+ULONG FASTCALL WWS32getservbyname(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETSERVBYNAME16 parg16;
+ PSERVENT servent32;
+ PSERVENT16 servent16;
+ PSZ name32;
+ PSZ protocol32;
+ DWORD bytesRequired;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)NULL);
+ }
+
+ GETARGPTR( pFrame, sizeof(GETSERVBYNAME16), parg16 );
+
+ GETVDMPTR( parg16->Name, 32, name32 );
+ GETVDMPTR( parg16->Protocol, 32, protocol32 );
+
+ servent32 = (PSERVENT) (*wsockapis[WOW_GETSERVBYNAME].lpfn)( name32, protocol32 );
+
+ if ( servent32 != NULL ) {
+
+ GETVDMPTR( WWS32vServent, MAXGETHOSTSTRUCT, servent16 );
+ bytesRequired = CopyServent32To16(
+ servent16,
+ WWS32vServent,
+ MAXGETHOSTSTRUCT,
+ servent32
+ );
+ ASSERT( bytesRequired < MAXGETHOSTSTRUCT );
+
+ FLUSHVDMPTR( WWS32vServent, (USHORT) bytesRequired, servent16 );
+ FREEVDMPTR( servent16 );
+ ul = WWS32vServent;
+
+ } else {
+
+ ul = 0;
+ }
+
+ FREEVDMPTR( name32 );
+ FREEVDMPTR( protocol32 );
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+
+} // WWS32getservbyname
+
+ULONG FASTCALL WWS32getservbyport(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETSERVBYPORT16 parg16;
+ PSERVENT servent32;
+ PSERVENT16 servent16;
+ PSZ protocol32;
+ DWORD bytesRequired;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)NULL);
+ }
+
+ GETARGPTR( pFrame, sizeof(GETSERVBYPORT16), parg16 );
+
+ GETVDMPTR( parg16->Protocol, 32, protocol32 );
+
+ servent32 = (PSERVENT) (*wsockapis[WOW_GETSERVBYPORT].lpfn)( parg16->Port, protocol32 );
+
+ if ( servent32 != NULL ) {
+
+ GETVDMPTR( WWS32vServent, MAXGETHOSTSTRUCT, servent16 );
+ bytesRequired = CopyServent32To16(
+ servent16,
+ WWS32vServent,
+ MAXGETHOSTSTRUCT,
+ servent32
+ );
+ ASSERT( bytesRequired < MAXGETHOSTSTRUCT );
+
+ FLUSHVDMPTR( WWS32vServent, (USHORT) bytesRequired, servent16 );
+ FREEVDMPTR( servent16 );
+ ul = WWS32vServent;
+
+ } else {
+
+ ul = 0;
+ }
+
+ FREEVDMPTR( protocol32 );
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+
+} // WWS32getservbyport
+
+ULONG FASTCALL WWS32WSAAsyncGetServByPort(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWSAASYNCGETSERVBYPORT16 parg16;
+ PWINSOCK_ASYNC_CONTEXT_BLOCK context;
+ PVOID buffer32;
+ PSZ proto32;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)0);
+ }
+
+ GETARGPTR( pFrame, sizeof(WSAASYNCGETSERVBYPORT16), parg16 );
+ GETVDMPTR( parg16->Protocol, 32, proto32 );
+
+ //
+ // Set up locals so we know how to clean up on exit.
+ //
+
+ context = NULL;
+ buffer32 = NULL;
+ ul = 0;
+
+ //
+ // Allocate a context block and 32-bit buffer to use for the request.
+ //
+
+ context = malloc_w( sizeof(*context) );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ buffer32 = malloc_w( MAXGETHOSTSTRUCT );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ //
+ // Fill in entries in the context buffer.
+ //
+
+ context->Buffer32 = buffer32;
+ context->vBuffer16 = parg16->Buffer;
+ context->Buffer16Length = parg16->BufferLength;
+
+ //
+ // Enter a critical section to synchronize access to the context block
+ // and their global list.
+ //
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ context->AsyncTaskHandle32 = (HANDLE) (*wsockapis[WOW_WSAASYNCGETSERVBYPORT].lpfn)(
+ (HWND)HWND32(parg16->hWnd),
+ (parg16->wMsg << 16) |
+ WWS32_MESSAGE_ASYNC_GETSERV,
+ parg16->Port,
+ proto32,
+ buffer32,
+ MAXGETHOSTSTRUCT
+ );
+
+ if ( context->AsyncTaskHandle32 != 0 ) {
+
+ //
+ // The call succeeded so get a 16-bit task handle for this
+ // request and place the context block on the global list. The
+ // resources will be freed by WWS32PostAsyncGetServ.
+ //
+
+ ul = WWS32GetAsyncTaskHandle16( );
+ context->AsyncTaskHandle16 = (HAND16)ul;
+
+ InsertTailList(
+ &WWS32AsyncContextBlockListHead,
+ &context->ContextBlockListEntry
+ );
+ }
+
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+exit:
+
+ if ( ul == 0 ) {
+
+ if ( context != NULL ) {
+ free_w( (PVOID)context );
+ }
+
+ if ( buffer32 != NULL ) {
+ free_w( buffer32 );
+ }
+ }
+
+ FREEARGPTR( proto32 );
+ FREEARGPTR( parg16 );
+
+ RETURN(ul);
+
+} // WWS32WSAAsyncGetServByPort
+
+ULONG FASTCALL WWS32WSAAsyncGetServByName(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWSAASYNCGETSERVBYNAME16 parg16;
+ PWINSOCK_ASYNC_CONTEXT_BLOCK context;
+ PVOID buffer32;
+ PSZ name32;
+ PSZ proto32;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)0);
+ }
+
+ GETARGPTR( pFrame, sizeof(WSAASYNCGETSERVBYNAME16), parg16 );
+ GETVDMPTR( parg16->Name, 32, name32 );
+ GETVDMPTR( parg16->Protocol, 32, proto32 );
+
+ //
+ // Set up locals so we know how to clean up on exit.
+ //
+
+ context = NULL;
+ buffer32 = NULL;
+ ul = 0;
+
+ //
+ // Allocate a context block and 32-bit buffer to use for the request.
+ //
+
+ context = malloc_w( sizeof(*context) );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ buffer32 = malloc_w( MAXGETHOSTSTRUCT );
+ if ( context == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ //
+ // Fill in entries in the context buffer.
+ //
+
+ context->Buffer32 = buffer32;
+ context->vBuffer16 = parg16->Buffer;
+ context->Buffer16Length = parg16->BufferLength;
+
+ //
+ // Enter a critical section to synchronize access to the context block
+ // and their global list.
+ //
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ context->AsyncTaskHandle32 = (HANDLE) (*wsockapis[WOW_WSAASYNCGETSERVBYNAME].lpfn)(
+ (HWND)HWND32(parg16->hWnd),
+ (parg16->wMsg << 16) |
+ WWS32_MESSAGE_ASYNC_GETSERV,
+ name32,
+ proto32,
+ buffer32,
+ MAXGETHOSTSTRUCT
+ );
+
+ if ( context->AsyncTaskHandle32 != 0 ) {
+
+ //
+ // The call succeeded so get a 16-bit task handle for this
+ // request and place the context block on the global list. The
+ // resources will be freed by WWS32PostAsyncGetServ.
+ //
+
+ ul = WWS32GetAsyncTaskHandle16( );
+ context->AsyncTaskHandle16 = (HAND16)ul;
+
+ InsertTailList(
+ &WWS32AsyncContextBlockListHead,
+ &context->ContextBlockListEntry
+ );
+ }
+
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+exit:
+
+ if ( ul == 0 ) {
+
+ if ( context != NULL ) {
+ free_w( (PVOID)context );
+ }
+
+ if ( buffer32 != NULL ) {
+ free_w( buffer32 );
+ }
+ }
+
+ FREEARGPTR( proto32 );
+ FREEARGPTR( name32 );
+ FREEARGPTR( parg16 );
+
+ RETURN(ul);
+
+} // WWS32WSAAsyncGetServByName
+
+
+BOOL
+WWS32PostAsyncGetServ (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ PWINSOCK_ASYNC_CONTEXT_BLOCK context;
+ BOOL ret;
+ PVOID buffer16;
+ DWORD bytesRequired;
+
+ context = WWS32FindAndRemoveAsyncContext( (HANDLE)wParam );
+ ASSERT( context != NULL );
+
+ //
+ // If the call was successful, copy the 32-bit buffer to the
+ // 16-bit buffer specified by the application.
+ //
+
+ if ( WSAGETASYNCERROR( lParam ) == 0 ) {
+
+ //
+ // Copy the 32-bit structure to 16-bit buffer.
+ //
+
+ GETVDMPTR( context->vBuffer16, context->Buffer16Length, buffer16 );
+
+ bytesRequired = CopyServent32To16(
+ buffer16,
+ context->vBuffer16,
+ context->Buffer16Length,
+ context->Buffer32
+ );
+
+ //
+ // If the application's buffer was too small, return an error
+ // and information aqbout the buffer size required.
+ //
+
+ if ( bytesRequired > context->Buffer16Length ) {
+ lParam = WSAMAKEASYNCREPLY( (WORD)bytesRequired, WSAENOBUFS );
+ }
+ }
+
+ //
+ // Post the completion message to the 16-bit application.
+ //
+
+ ret = PostMessage(
+ hWnd,
+ Msg >> 16,
+ context->AsyncTaskHandle16,
+ lParam
+ );
+
+ //
+ // Free resources and return.
+ //
+
+ free_w( context->Buffer32 );
+ free_w( (PVOID)context );
+
+ return ret;
+
+} // WWS32PostAsyncGetServ
+
+
+DWORD
+CopyServent32To16 (
+ PSERVENT16 Servent16,
+ VPSERVENT16 VServent16,
+ int BufferLength,
+ PSERVENT Servent32
+ )
+{
+ DWORD requiredBufferLength;
+ DWORD bytesFilled;
+ PCHAR currentLocation = (PCHAR)Servent16;
+ DWORD aliasCount;
+ DWORD i;
+ VPBYTE *aliases16;
+
+ //
+ // Determine how many bytes are needed to fully copy the structure.
+ //
+
+ requiredBufferLength = BytesInServent32( Servent32 );
+
+ //
+ // Copy over the servent structure if it fits.
+ //
+
+ bytesFilled = sizeof(*Servent16);
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ return requiredBufferLength;
+ }
+
+ STOREWORD( Servent16->s_port, Servent32->s_port );
+ currentLocation = (PCHAR)Servent16 + bytesFilled;
+
+ //
+ // Count the service's aliases and set up an array to hold pointers to
+ // them.
+ //
+
+ for ( aliasCount = 0;
+ Servent32->s_aliases[aliasCount] != NULL;
+ aliasCount++ );
+
+ bytesFilled += (aliasCount+1) * sizeof(char FAR *);
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ STOREDWORD( Servent32->s_aliases, 0 );
+ return requiredBufferLength;
+ }
+
+ Servent16->s_aliases =
+ FIND_16_OFFSET_FROM_32( VServent16, Servent16, currentLocation );
+ aliases16 = (VPBYTE *)currentLocation;
+ currentLocation = (PCHAR)Servent16 + bytesFilled;
+
+ //
+ // Copy the service name if it fits.
+ //
+
+ bytesFilled += strlen( Servent32->s_name ) + 1;
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ return requiredBufferLength;
+ }
+
+ Servent16->s_name =
+ FIND_16_OFFSET_FROM_32( VServent16, Servent16, currentLocation );
+
+ RtlMoveMemory( currentLocation, Servent32->s_name, strlen( Servent32->s_name ) + 1 );
+ currentLocation = (PCHAR)Servent16 + bytesFilled;
+
+ //
+ // Copy the protocol name if it fits.
+ //
+
+ bytesFilled += strlen( Servent32->s_proto ) + 1;
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ return requiredBufferLength;
+ }
+
+ Servent16->s_proto =
+ FIND_16_OFFSET_FROM_32( VServent16, Servent16, currentLocation );
+
+ RtlMoveMemory( currentLocation, Servent32->s_proto, strlen( Servent32->s_proto ) + 1 );
+ currentLocation = (PCHAR)Servent16 + bytesFilled;
+
+ //
+ // Start filling in aliases.
+ //
+
+ for ( i = 0; i < aliasCount; i++ ) {
+
+ bytesFilled += strlen( Servent32->s_aliases[i] ) + 1;
+
+ if ( bytesFilled > (DWORD)BufferLength ) {
+ STOREDWORD( aliases16[i], NULL );
+ return requiredBufferLength;
+ }
+
+ STOREDWORD(
+ aliases16[i],
+ FIND_16_OFFSET_FROM_32( VServent16, Servent16, currentLocation )
+ );
+
+ RtlMoveMemory(
+ currentLocation,
+ Servent32->s_aliases[i],
+ strlen( Servent32->s_aliases[i] ) + 1
+ );
+
+ currentLocation = (PCHAR)Servent16 + bytesFilled;
+ }
+
+ STOREDWORD( aliases16[i], NULL );
+
+ return requiredBufferLength;
+
+} // CopyServent32To16
+
+
+DWORD
+BytesInServent32 (
+ IN PSERVENT Servent32
+ )
+{
+ DWORD total;
+ int i;
+
+ total = sizeof(SERVENT);
+ total += strlen( Servent32->s_name ) + 1;
+ total += strlen( Servent32->s_proto ) + 1;
+ total += sizeof(char *);
+
+ for ( i = 0; Servent32->s_aliases[i] != NULL; i++ ) {
+ total += strlen( Servent32->s_aliases[i] ) + 1 + sizeof(char *);
+ }
+
+ return total;
+
+} // BytesInServent32
+
+ULONG FASTCALL WWS32WSACancelAsyncRequest(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWSACANCELASYNCREQUEST16 parg16;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)SOCKET_ERROR);
+ }
+
+ GETARGPTR(pFrame, sizeof(WSACANCELASYNCREQUEST16), parg16);
+
+ //ul = GETWORD16((*wsockapis[WOW_WSACANCELASYNCREQUEST].lpfn)(
+ // ));
+
+ FREEARGPTR(parg16);
+
+ ul = (ULONG) SOCKET_ERROR;
+ SetLastError( WSAEINVAL );
+
+ RETURN(ul);
+
+} // WWS32WSACancelAsyncRequest
+
+
+PWINSOCK_ASYNC_CONTEXT_BLOCK
+WWS32FindAndRemoveAsyncContext (
+ IN HANDLE AsyncTaskHandle32
+ )
+{
+ PWINSOCK_ASYNC_CONTEXT_BLOCK context;
+ PLIST_ENTRY listEntry;
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ //
+ // Walk the global list of async context blocks, looking for
+ // one that matches the specified task handle.
+ //
+
+ for ( listEntry = WWS32AsyncContextBlockListHead.Flink;
+ listEntry != &WWS32AsyncContextBlockListHead;
+ listEntry = listEntry->Flink ) {
+
+ context = CONTAINING_RECORD(
+ listEntry,
+ WINSOCK_ASYNC_CONTEXT_BLOCK,
+ ContextBlockListEntry
+ );
+
+ if ( context->AsyncTaskHandle32 == AsyncTaskHandle32 ) {
+
+ //
+ // Found a match. Remove it from the global list, leave
+ // the critical section, and return the context block.
+ //
+
+ RemoveEntryList( &context->ContextBlockListEntry );
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+ return context;
+ }
+ }
+
+ //
+ // A matching context block was not found on the list.
+ //
+
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+ return NULL;
+
+} // WWS32FindAndRemoveAsyncContext
+
+
+HAND16
+WWS32GetAsyncTaskHandle16 (
+ VOID
+ )
+{
+ HAND16 asyncTaskHandle16;
+
+ // *** this routine *must* be called from within the WWS32 critical
+ // section!
+
+ ASSERT( WWS32AsyncTaskHandleCounter != 0 );
+
+ asyncTaskHandle16 = (HAND16)WWS32AsyncTaskHandleCounter;
+
+ WWS32AsyncTaskHandleCounter++;
+
+ //
+ // 0 is an invalid task handle value; if the counter has wrapped to
+ // zero, set it to 1.
+ //
+
+ if ( WWS32AsyncTaskHandleCounter == 0 ) {
+ WWS32AsyncTaskHandleCounter = 1;
+ }
+
+ return WWS32AsyncTaskHandleCounter;
+
+} // WWS32GetAsyncTaskHandle16
diff --git a/private/mvdm/wow32/wsdynmc.h b/private/mvdm/wow32/wsdynmc.h
new file mode 100644
index 000000000..416613255
--- /dev/null
+++ b/private/mvdm/wow32/wsdynmc.h
@@ -0,0 +1,53 @@
+extern DLLENTRYPOINTS wsockapis[];
+
+#define WOW_WSOCKAPI_COUNT 49
+
+#define WOW_ACCEPT 0
+#define WOW_BIND 1
+#define WOW_CLOSESOCKET 2
+#define WOW_CONNECT 3
+#define WOW_GETPEERNAME 4
+#define WOW_GETSOCKNAME 5
+#define WOW_GETSOCKOPT 6
+#define WOW_HTONL 7
+#define WOW_HTONS 8
+#define WOW_INET_ADDR 9
+#define WOW_INET_NTOA 10
+#define WOW_IOCTLSOCKET 11
+#define WOW_LISTEN 12
+#define WOW_NTOHL 13
+#define WOW_NTOHS 14
+#define WOW_RECV 15
+#define WOW_RECVFROM 16
+#define WOW_SELECT 17
+#define WOW_SEND 18
+#define WOW_SENDTO 19
+#define WOW_SETSOCKOPT 20
+#define WOW_SHUTDOWN 21
+#define WOW_SOCKET 22
+#define WOW_GETHOSTBYADDR 23
+#define WOW_GETHOSTBYNAME 24
+#define WOW_GETPROTOBYNAME 25
+#define WOW_GETPROTOBYNUMBER 26
+#define WOW_GETSERVBYNAME 27
+#define WOW_GETSERVBYPORT 28
+#define WOW_GETHOSTNAME 29
+#define WOW_WSAASYNCSELECT 30
+#define WOW_WSAASYNCGETHOSTBYADDR 31
+#define WOW_WSAASYNCGETHOSTBYNAME 32
+#define WOW_WSAASYNCGETPROTOBYNUMBER 33
+#define WOW_WSAASYNCGETPROTOBYNAME 34
+#define WOW_WSAASYNCGETSERVBYPORT 35
+#define WOW_WSAASYNCGETSERVBYNAME 36
+#define WOW_WSACANCELASYNCREQUEST 37
+#define WOW_WSASETBLOCKINGHOOK 38
+#define WOW_WSAUNBLOCKINGHOOK 39
+#define WOW_WSAGETLASTERROR 40
+#define WOW_WSASETLASTERROR 41
+#define WOW_WSACANCELBLOCKINGCALL 42
+#define WOW_WSAISBLOCKING 43
+#define WOW_WSASTARTUP 44
+#define WOW_WSACLEANUP 45
+#define WOW_WSAFDISSET 46
+#define WOW_WSAPSETPOSTROUTINE 47
+#define WOW_WSARECVEX 48
diff --git a/private/mvdm/wow32/wsext.c b/private/mvdm/wow32/wsext.c
new file mode 100644
index 000000000..5b1645fe7
--- /dev/null
+++ b/private/mvdm/wow32/wsext.c
@@ -0,0 +1,893 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ Wsraw.h
+
+Abstract:
+
+ Support for extended winsock calls for WOW.
+
+Author:
+
+ David Treadwell (davidtr) 02-Oct-1992
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wsdynmc.h"
+
+DLLENTRYPOINTS wsockapis[WOW_WSOCKAPI_COUNT] = {
+ (char *) 1, NULL,
+ (char *) 2, NULL,
+ (char *) 3, NULL,
+ (char *) 4, NULL,
+ (char *) 5, NULL,
+ (char *) 6, NULL,
+ (char *) 7, NULL,
+ (char *) 8, NULL,
+ (char *) 9, NULL,
+ (char *) 10, NULL,
+ (char *) 11, NULL,
+ (char *) 12, NULL,
+ (char *) 13, NULL,
+ (char *) 14, NULL,
+ (char *) 15, NULL,
+ (char *) 16, NULL,
+ (char *) 17, NULL,
+ (char *) 18, NULL,
+ (char *) 19, NULL,
+ (char *) 20, NULL,
+ (char *) 21, NULL,
+ (char *) 22, NULL,
+ (char *) 23, NULL,
+ (char *) 51, NULL,
+ (char *) 52, NULL,
+ (char *) 53, NULL,
+ (char *) 54, NULL,
+ (char *) 55, NULL,
+ (char *) 56, NULL,
+ (char *) 57, NULL,
+ (char *) 101, NULL,
+ (char *) 102, NULL,
+ (char *) 103, NULL,
+ (char *) 104, NULL,
+ (char *) 105, NULL,
+ (char *) 106, NULL,
+ (char *) 107, NULL,
+ (char *) 108, NULL,
+ (char *) 109, NULL,
+ (char *) 110, NULL,
+ (char *) 111, NULL,
+ (char *) 112, NULL,
+ (char *) 113, NULL,
+ (char *) 114, NULL,
+ (char *) 115, NULL,
+ (char *) 116, NULL,
+ (char *) 151, NULL,
+ (char *) 1000, NULL,
+ (char *) 1107, NULL};
+
+
+
+DWORD WWS32TlsSlot = 0xFFFFFFFF;
+RTL_CRITICAL_SECTION WWS32CriticalSection;
+BOOL WWS32Initialized = FALSE;
+LIST_ENTRY WWS32AsyncContextBlockListHead;
+WORD WWS32AsyncTaskHandleCounter;
+DWORD WWS32ThreadSerialNumberCounter;
+HINSTANCE hInstWSOCK32;
+
+
+DWORD
+WWS32CallBackHandler (
+ VOID
+ );
+
+BOOL
+WWS32DefaultBlockingHook (
+ VOID
+ );
+
+/*++
+
+ GENERIC FUNCTION PROTOTYPE:
+ ==========================
+
+ULONG FASTCALL WWS32<function name>(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register P<function name>16 parg16;
+
+ GETARGPTR(pFrame, sizeof(<function name>16), parg16);
+
+ <get any other required pointers into 16 bit space>
+
+ ALLOCVDMPTR
+ GETVDMPTR
+ GETMISCPTR
+ et cetera
+
+ <copy any complex structures from 16 bit -> 32 bit space>
+ <ALWAYS use the FETCHxxx macros>
+
+ ul = GET<return type>16(<function name>(parg16->f1,
+ :
+ :
+ parg16->f<n>);
+
+ <copy any complex structures from 32 -> 16 bit space>
+ <ALWAYS use the STORExxx macros>
+
+ <free any pointers to 16 bit space you previously got>
+
+ <flush any areas of 16 bit memory if they were written to>
+
+ FLUSHVDMPTR
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+NOTE:
+
+ The VDM frame is automatically set up, with all the function parameters
+ available via parg16->f<number>.
+
+ Handles must ALWAYS be mapped for 16 -> 32 -> 16 space via the mapping tables
+ laid out in WALIAS.C.
+
+ Any storage you allocate must be freed (eventually...).
+
+ Further to that - if a thunk which allocates memory fails in the 32 bit call
+ then it must free that memory.
+
+ Also, never update structures in 16 bit land if the 32 bit call fails.
+
+ Be aware that the GETxxxPTR macros return the CURRENT selector-to-flat_memory
+ mapping. Calls to some 32-bit functions may indirectly cause callbacks into
+ 16-bit code. These may cause 16-bit memory to move due to allocations
+ made in 16-bit land. If the 16-bit memory does move, the corresponding 32-bit
+ ptr in WOW32 needs to be refreshed to reflect the NEW selector-to-flat_memory
+ mapping.
+
+--*/
+
+ULONG FASTCALL WWS32WSAAsyncSelect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PWSAASYNCSELECT16 parg16;
+ SOCKET s32;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)SOCKET_ERROR);
+ }
+
+ GETARGPTR(pFrame, sizeof(WSAASYNCSELECT16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ s32 = GetWinsock32( parg16->hSocket );
+
+ if ( s32 == INVALID_SOCKET ) {
+
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOTSOCK );
+ ul = (ULONG)GETWORD16( SOCKET_ERROR );
+
+ } else {
+
+ ul = GETWORD16( (*wsockapis[WOW_WSAASYNCSELECT].lpfn)(
+ s32,
+ (HWND)HWND32(parg16->hWnd),
+ (parg16->wMsg << 16) | WWS32_MESSAGE_ASYNC_SELECT,
+ parg16->lEvent
+ ));
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+
+} // WWS32WSAAsyncSelect
+
+ULONG FASTCALL WWS32WSASetBlockingHook(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ VPWNDPROC vpBlockFunc;
+
+ //FARPROC previousHook;
+ register PWSASETBLOCKINGHOOK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(WSASETBLOCKINGHOOK16), parg16);
+ vpBlockFunc = parg16->lpBlockFunc;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)NULL);
+ }
+
+ if ( (*wsockapis[WOW_WSAISBLOCKING].lpfn)( ) ) {
+ SetLastError( WSAEINPROGRESS );
+ RETURN((ULONG)NULL);
+ }
+
+ ul = WWS32vBlockingHook;
+ WWS32vBlockingHook = vpBlockFunc;
+
+ FREEARGPTR( parg16 );
+
+ RETURN(ul);
+
+} // WWS32WSASetBlockingHook
+
+ULONG FASTCALL WWS32WSAUnhookBlockingHook(PVDMFRAME pFrame)
+{
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)SOCKET_ERROR);
+ }
+
+ if ( (*wsockapis[WOW_WSAISBLOCKING].lpfn) ) {
+ SetLastError( WSAEINPROGRESS );
+ RETURN((ULONG)SOCKET_ERROR);
+ }
+
+ WWS32vBlockingHook = WWS32_DEFAULT_BLOCKING_HOOK;
+
+ RETURN(0);
+
+} // WWS32WSAUnhookBlockingHook
+
+ULONG FASTCALL WWS32WSAGetLastError(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ ul = GETWORD16( (*wsockapis[WOW_WSAGETLASTERROR].lpfn)( ) );
+
+ RETURN(ul);
+
+} // WWS32WSAGetLastError
+
+ULONG FASTCALL WWS32WSASetLastError(PVDMFRAME pFrame)
+{
+ register PWSASETLASTERROR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(WSASETLASTERROR16), parg16);
+
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( FETCHWORD( parg16->Error ) );
+
+ FREEARGPTR(parg16);
+
+ RETURN(0);
+
+} // WWS32WSASetLastError
+
+ULONG FASTCALL WWS32WSACancelBlockingCall(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)SOCKET_ERROR);
+ }
+
+ ul = GETWORD16((*wsockapis[WOW_WSACANCELBLOCKINGCALL].lpfn)( ));
+
+ RETURN(ul);
+
+} // WWS32WSACancelBlockingCall
+
+ULONG FASTCALL WWS32WSAIsBlocking(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)FALSE);
+ }
+
+ ul = GETWORD16((*wsockapis[WOW_WSAISBLOCKING].lpfn)( ));
+
+ RETURN(ul);
+
+} // WWS32WSAIsBlocking
+
+ULONG FASTCALL WWS32WSAStartup(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PWSASTARTUP16 parg16;
+ PWSADATA16 wsaData16;
+ PWINSOCK_THREAD_DATA data;
+ NTSTATUS status;
+ FARPROC previousHook;
+ PSZ description;
+ PSZ systemStatus;
+ WORD versionRequested;
+ VPWSADATA16 vpwsaData16;
+
+ GETARGPTR(pFrame, sizeof(WSASTARTUP16), parg16);
+
+ vpwsaData16 = parg16->lpWSAData;
+
+ versionRequested = INT32(parg16->wVersionRequired);
+
+ //
+ // If winsock has not yet been initialized, initialize data structures
+ // now.
+ //
+
+ if ( !WWS32Initialized ) {
+
+ WSADATA wsaData;
+
+ InitializeListHead( &WWS32AsyncContextBlockListHead );
+ InitializeListHead( &WWS32SocketHandleListHead );
+
+ WWS32AsyncTaskHandleCounter = 1;
+ WWS32SocketHandleCounter = 1;
+ WWS32SocketHandleCounterWrapped = FALSE;
+ WWS32ThreadSerialNumberCounter = 1;
+
+ //
+ // Load WSOCK32.DLL and initialize all the entry points.
+ //
+
+ if (!LoadLibraryAndGetProcAddresses ("WSOCK32.DLL", wsockapis, WOW_WSOCKAPI_COUNT)) {
+ LOGDEBUG (LOG_ALWAYS, ("WOW::WWS32WSAStartup: LoadLibrary failed\n"));
+ ul = GETWORD16(WSAENOBUFS);
+ return (ul);
+ }
+
+ //
+ // Initialize the ntvdm process to the 32-bit Windows Sockets
+ // DLL.
+ //
+
+ ul = (*wsockapis[WOW_WSASTARTUP].lpfn)( MAKEWORD( 1, 1 ), &wsaData );
+ if ( ul != NO_ERROR ) {
+ RETURN(ul);
+ }
+
+ //
+ // Initialize the critical section we'll use for synchronizing
+ // async requests.
+ //
+
+ status = RtlInitializeCriticalSection( &WWS32CriticalSection );
+ if ( !NT_SUCCESS(status) ) {
+ ul = GETWORD16(WSAENOBUFS);
+ RETURN(ul);
+ }
+
+ //
+ // Get a slot in TLS.
+ //
+
+ WWS32TlsSlot = TlsAlloc( );
+ if ( WWS32TlsSlot == 0xFFFFFFFF ) {
+ RtlDeleteCriticalSection( &WWS32CriticalSection );
+ ul = GETWORD16(WSAENOBUFS);
+ RETURN(ul);
+ }
+
+ WWS32Initialized = TRUE;
+ }
+
+ //
+ // Make sure that we're not in a blocking call.
+ //
+
+ if ( (*wsockapis[WOW_WSAISBLOCKING].lpfn)( ) ) {
+ RETURN((ULONG)WSAEINPROGRESS);
+ }
+
+ //
+ // If this thread has not already had a WSAStartup() call, allocate
+ // and initialize per-thread data.
+ //
+
+ if ( !WWS32IsThreadInitialized ) {
+
+ //
+ // We support versions 1.0 and 1.1 of the Windows Sockets
+ // specification. If the requested version is below that, fail.
+ //
+
+ if ( LOBYTE(versionRequested) < 1 ) {
+ ul = WSAVERNOTSUPPORTED;
+ RETURN(ul);
+ }
+
+ //
+ // Allocate space for the per-thread data that we need. Note that
+ // we set the value in the TSL slot regardless of whether we actually
+ // managed to allocate the memory--this is because we want NULL
+ // in the TLS slot if we couldn't properly allocate the storage.
+ //
+
+ data = malloc_w( sizeof(*data) );
+
+ if ( !TlsSetValue( WWS32TlsSlot, (LPVOID)data ) || data == NULL ) {
+
+ ul = GETWORD16(WSAENOBUFS);
+ if ( data != NULL ) {
+ free_w( (PVOID)data );
+ }
+ FREEARGPTR( parg16 );
+ RETURN(ul);
+ }
+
+ //
+ // Initialize the blocking hook.
+ //
+
+ WWS32vBlockingHook = WWS32_DEFAULT_BLOCKING_HOOK;
+
+ //
+ // Allocate the individual data objects we need for this task.
+ //
+
+ data->vIpAddress = GlobalAllocLock16( GMEM_MOVEABLE, 256, NULL );
+ if ( data->vIpAddress == 0 ) {
+ free_w( (PVOID)data );
+ TlsSetValue( WWS32TlsSlot, NULL );
+ FREEARGPTR( parg16 );
+ RETURN(ul);
+ }
+
+ data->vHostent = GlobalAllocLock16( GMEM_MOVEABLE, MAXGETHOSTSTRUCT, NULL );
+ if ( data->vHostent == 0 ) {
+ GlobalUnlockFree16( data->vIpAddress );
+ free_w( (PVOID)data );
+ TlsSetValue( WWS32TlsSlot, NULL );
+ FREEARGPTR( parg16 );
+ RETURN(ul);
+ }
+
+ data->vServent = GlobalAllocLock16( GMEM_MOVEABLE, MAXGETHOSTSTRUCT, NULL );
+ if ( data->vServent == 0 ) {
+ GlobalUnlockFree16( data->vIpAddress );
+ GlobalUnlockFree16( data->vHostent );
+ free_w( (PVOID)data );
+ TlsSetValue( WWS32TlsSlot, NULL );
+ FREEARGPTR( parg16 );
+ RETURN(ul);
+ }
+
+ data->vProtoent = GlobalAllocLock16( GMEM_MOVEABLE, MAXGETHOSTSTRUCT, NULL );
+ if ( data->vProtoent == 0 ) {
+ GlobalUnlockFree16( data->vIpAddress );
+ GlobalUnlockFree16( data->vHostent );
+ GlobalUnlockFree16( data->vServent );
+ free_w( (PVOID)data );
+ TlsSetValue( WWS32TlsSlot, NULL );
+ FREEARGPTR( parg16 );
+ RETURN(ul);
+ }
+
+ //
+ // Initialize other per-thread data.
+ //
+
+ WWS32ThreadSerialNumber = WWS32ThreadSerialNumberCounter++;
+ WWS32ThreadStartupCount = 1;
+
+ //
+ // If they requested version 1.0, give them 1.0. If they
+ // requested anything else (has to be higher than 1.0 due to
+ // above test), then give them 1.1. We only support 1.0
+ // and 1.1. If they can't handle 1.1, they will call
+ // WSAStartup() and fail.
+ //
+
+ if ( versionRequested == 0x0001 ) {
+ WWS32ThreadVersion = 0x0001;
+ } else {
+ WWS32ThreadVersion = 0x0101;
+ }
+
+ //
+ // Set up the blocking hook. We always use this blocking hook,
+ // even for the default case.
+ //
+
+ previousHook = (FARPROC) (*wsockapis[WOW_WSASETBLOCKINGHOOK].lpfn)( (FARPROC)WWS32CallBackHandler );
+
+ //
+ // Set up the routine we'll use in leiu of wsock32.dll posting
+ // messages directly to the application. We need to intervene
+ // on all posts because we need to convert 32-bit arguments to
+ // 16-bit.
+ //
+
+ (*wsockapis[WOW_WSAPSETPOSTROUTINE].lpfn)( WWS32DispatchPostMessage );
+
+ } else {
+
+ //
+ // This thread has already had a WSAStartup() call. Make sure
+ // that they're requesting the same version as before.
+ //
+
+ if ( versionRequested != WWS32ThreadVersion ) {
+ ul = WSAVERNOTSUPPORTED;
+ RETURN(ul);
+ }
+
+ //
+ // Increment the count of WSAStartup() calls for the thread.
+ //
+
+ WWS32ThreadStartupCount++;
+ }
+
+ //
+ // Get a 32-bit pointer to the 16-bit WSADATA structure and
+ // initialize the caller's WSAData structure.
+ //
+
+ GETVDMPTR( vpwsaData16, sizeof(WSADATA16), wsaData16 );
+
+ STOREWORD( wsaData16->wVersion, WWS32ThreadVersion );
+ STOREWORD( wsaData16->wHighVersion, MAKEWORD(1, 1) );
+
+ description = "Windows NT 16-bit Windows Sockets";
+ RtlCopyMemory( wsaData16->szDescription,
+ description,
+ strlen(description) + 1 );
+
+ systemStatus = "Running.";
+ RtlCopyMemory( wsaData16->szSystemStatus,
+ systemStatus,
+ strlen(systemStatus) + 1 );
+
+ STOREWORD( wsaData16->iMaxSockets, 0xFFFF );
+ STOREWORD( wsaData16->iMaxUdpDg, 8096 );
+ STOREDWORD( wsaData16->lpVendorInfo, 0 );
+
+ FLUSHVDMPTR( vpwsaData16, sizeof(WSADATA16), wsaData16 );
+ FREEVDMPTR( wsaData16 );
+
+ FREEARGPTR( parg16 );
+
+ RETURN(ul);
+
+} // WWS32WSAStartup
+
+ULONG FASTCALL WWS32WSACleanup(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)SOCKET_ERROR);
+ }
+
+ if ( (*wsockapis[WOW_WSAISBLOCKING].lpfn)( ) ) {
+ SetLastError( WSAEINPROGRESS );
+ RETURN((ULONG)SOCKET_ERROR);
+ }
+
+ WWS32ThreadStartupCount--;
+
+ if ( WWS32ThreadStartupCount == 0 ) {
+
+ WWS32TaskCleanup( );
+
+ }
+
+ RETURN(ul);
+
+} // WWS32WSACleanup
+
+VOID
+WWS32TaskCleanup(
+ VOID
+ )
+{
+ LIST_ENTRY listHead;
+ PWINSOCK_THREAD_DATA data;
+ PLIST_ENTRY listEntry;
+ PWINSOCK_SOCKET_INFO socketInfo;
+ struct linger lingerInfo;
+ int err;
+
+ //
+ // Get a pointer to the thread's data and set the TLS slot for
+ // this thread to NULL so that we know that the thread is no
+ // longer initialized.
+ //
+
+ data = TlsGetValue( WWS32TlsSlot );
+ ASSERT( data != NULL );
+
+ TlsSetValue( WWS32TlsSlot, NULL );
+
+ //
+ // Free thread data user for the database calls.
+ //
+
+ GlobalUnlockFree16( data->vIpAddress );
+ GlobalUnlockFree16( data->vHostent );
+ GlobalUnlockFree16( data->vServent );
+ GlobalUnlockFree16( data->vProtoent );
+
+ //
+ // Close all sockets that the thread has opened. We first find
+ // all the sockets for this thread, remove them from the global
+ // list, and place them onto a local list. Then we close each
+ // socket. We do this as two steps because we can't hold the
+ // critical section while calling wsock32 in order to avoid
+ // deadlocks.
+ //
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ InitializeListHead( &listHead );
+
+ for ( listEntry = WWS32SocketHandleListHead.Flink;
+ listEntry != &WWS32SocketHandleListHead;
+ listEntry = listEntry->Flink ) {
+
+ socketInfo = CONTAINING_RECORD(
+ listEntry,
+ WINSOCK_SOCKET_INFO,
+ GlobalSocketListEntry
+ );
+
+ if ( socketInfo->ThreadSerialNumber == data->ThreadSerialNumber ) {
+
+ //
+ // The socket was opened by this thread. We need to
+ // first remove the entry from the global list, but
+ // maintain the listEntry local variable so that we can
+ // still walk the list.
+ //
+
+ listEntry = socketInfo->GlobalSocketListEntry.Blink;
+ RemoveEntryList( &socketInfo->GlobalSocketListEntry );
+
+ //
+ // Now insert the entry on our local list.
+ //
+
+ InsertTailList( &listHead, &socketInfo->GlobalSocketListEntry );
+ }
+ }
+
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+ //
+ // Walk through the sockets opened by this thread and close them
+ // abortively.
+ //
+
+ for ( listEntry = listHead.Flink;
+ listEntry != &listHead;
+ listEntry = listEntry->Flink ) {
+
+ //
+ // Close it abortively and free the handle.
+ //
+
+ socketInfo = CONTAINING_RECORD(
+ listEntry,
+ WINSOCK_SOCKET_INFO,
+ GlobalSocketListEntry
+ );
+
+ lingerInfo.l_onoff = 1;
+ lingerInfo.l_linger = 0;
+
+ err = (*wsockapis[WOW_SETSOCKOPT].lpfn)(
+ socketInfo->SocketHandle32,
+ SOL_SOCKET,
+ SO_LINGER,
+ (char *)&lingerInfo,
+ sizeof(lingerInfo)
+ );
+ //ASSERT( err == NO_ERROR );
+
+ err = (*wsockapis[WOW_CLOSESOCKET].lpfn)( socketInfo->SocketHandle32 );
+ ASSERT( err == NO_ERROR );
+
+ //
+ // When we free the handle the socketInfo structure will
+ // also be freed. Set the list pointer to the entry
+ // prior to this one so that we can successfully walk
+ // the list.
+ //
+
+ listEntry = socketInfo->GlobalSocketListEntry.Blink;
+
+ RemoveEntryList( &socketInfo->GlobalSocketListEntry );
+ free_w( (PVOID)socketInfo );
+ }
+
+ //
+ // Set the TLS slot for this thread to NULL so that we know
+ // that the thread is not initialized.
+ //
+
+ err = TlsSetValue( WWS32TlsSlot, NULL );
+ ASSERT( err );
+
+ //
+ // Free the structure that holds thread information.
+ //
+
+ free_w( (PVOID)data );
+
+} // WWS32TaskCleanup
+
+ULONG FASTCALL WWS32__WSAFDIsSet(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register P__WSAFDISSET16 parg16;
+ PFD_SET16 fdSet16;
+ PFD_SET fdSet32;
+
+ if ( !WWS32IsThreadInitialized ) {
+ SetLastError( WSANOTINITIALISED );
+ RETURN((ULONG)FALSE);
+ }
+
+ GETARGPTR( pFrame, sizeof(__WSAFDISSET16), parg16 );
+
+ GETVDMPTR( parg16->Set, sizeof(FD_SET16), fdSet16 );
+
+ fdSet32 = AllocateFdSet32( fdSet16 );
+
+ if ( fdSet32 != NULL ) {
+
+ ConvertFdSet16To32( fdSet16, fdSet32 );
+
+ ul = (*wsockapis[WOW_WSAFDISSET].lpfn)( GetWinsock32( parg16->hSocket ), fdSet32 );
+
+ free_w( (PVOID)fdSet32 );
+
+ } else {
+
+ ul = 0;
+ }
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+
+} // WWS32__WSAFDIsSet
+
+
+PWINSOCK_POST_ROUTINE WWS32PostDispatchTable[] =
+{
+ WWS32PostAsyncSelect,
+ WWS32PostAsyncGetHost,
+ WWS32PostAsyncGetProto,
+ WWS32PostAsyncGetServ
+};
+
+BOOL
+WWS32DispatchPostMessage (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+
+ ASSERT( WWS32PostDispatchTable[WWS32_MESSAGE_ASYNC_SELECT] ==
+ WWS32PostAsyncSelect );
+ ASSERT( WWS32PostDispatchTable[WWS32_MESSAGE_ASYNC_GETHOST] ==
+ WWS32PostAsyncGetHost );
+ ASSERT( WWS32PostDispatchTable[WWS32_MESSAGE_ASYNC_GETPROTO] ==
+ WWS32PostAsyncGetProto );
+ ASSERT( WWS32PostDispatchTable[WWS32_MESSAGE_ASYNC_GETSERV] ==
+ WWS32PostAsyncGetServ );
+ ASSERT( (Msg & 0xFFFF) <= WWS32_MESSAGE_ASYNC_GETSERV );
+
+ //
+ // Call the routine that will handle the message. The low word
+ // of Msg specifies the routine, the high word of Msg is the
+ // 16-bit message that that routine will post.
+ //
+
+ return WWS32PostDispatchTable[Msg & 0xFFFF](
+ hWnd,
+ Msg,
+ wParam,
+ lParam
+ );
+
+} // WWS32DispatchPostMessage
+
+
+BOOL
+WWS32PostAsyncSelect (
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+
+ HAND16 h16;
+
+ h16 = GetWinsock16( wParam, 0 );
+
+ if( h16 == 0 ) {
+ return TRUE;
+ }
+
+ return PostMessage(
+ hWnd,
+ Msg >> 16,
+ h16,
+ lParam
+ );
+
+} // WWS32PostAsyncSelect
+
+
+DWORD
+WWS32CallBackHandler (
+ VOID
+ )
+{
+
+ VPVOID ret;
+
+ //
+ // If the default blocking hook is in force, use it. Otherwise,
+ // call back into the application's blocking hook.
+ //
+
+ if ( WWS32vBlockingHook == WWS32_DEFAULT_BLOCKING_HOOK ) {
+ return WWS32DefaultBlockingHook( );
+ }
+
+ (VOID)CallBack16( RET_WINSOCKBLOCKHOOK, NULL, WWS32vBlockingHook, &ret );
+
+ return ret & 0xFF;
+
+} // WWS32CallBackHandler
+
+
+BOOL
+WWS32DefaultBlockingHook (
+ VOID
+ )
+{
+ MSG msg;
+ BOOLEAN retrievedMessage;
+
+ //
+ // Get the next message for this thread, if any.
+ //
+
+ retrievedMessage = PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
+
+ //
+ // Process the message if we got one.
+ //
+
+ if ( retrievedMessage ) {
+ TranslateMessage( (CONST MSG *)&msg );
+ DispatchMessage( (CONST MSG *)&msg );
+ }
+
+ //
+ // If we got a message, indicate that we want to be called again.
+ //
+
+ return retrievedMessage;
+
+} // WWS32DefaultBlockingHook
diff --git a/private/mvdm/wow32/wshell.c b/private/mvdm/wow32/wshell.c
new file mode 100644
index 000000000..85a75af07
--- /dev/null
+++ b/private/mvdm/wow32/wshell.c
@@ -0,0 +1,1178 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSHELL.C
+ * WOW32 16-bit SHELL API support
+ *
+ * History:
+ * 14-April-1992 Chandan Chauhan (ChandanC)
+ * Created.
+ *
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+#include <winreg.h>
+#include "wowshlp.h"
+
+MODNAME(wshell.c);
+
+LONG
+WOWRegDeleteKey(
+ IN HKEY hKey,
+ IN LPCTSTR lpszSubKey
+ );
+
+#ifndef WIN16_HKEY_CLASSES_ROOT
+#define WIN16_HKEY_CLASSES_ROOT 1
+#endif
+
+#ifndef WIN16_ERROR_SUCCESS
+#define WIN16_ERROR_SUCCESS 0L
+#define WIN16_ERROR_BADDB 1L
+#define WIN16_ERROR_BADKEY 2L
+#define WIN16_ERROR_CANTOPEN 3L
+#define WIN16_ERROR_CANTREAD 4L
+#define WIN16_ERROR_CANTWRITE 5L
+#define WIN16_ERROR_OUTOFMEMORY 6L
+#define WIN16_ERROR_INVALID_PARAMETER 7L
+#define WIN16_ERROR_ACCESS_DENIED 8L
+#endif
+
+ULONG FASTCALL WS32DoEnvironmentSubst(PVDMFRAME pFrame)
+{
+ //
+ // This is an undocumented shell.dll API used by ProgMan
+ // and Norton AntiVirus for Windows (part of Norton
+ // Desktop for Windows), probably among others.
+ // Since it's not in the Win32 shellapi.h, we have a
+ // copy of the prototype here, copied from
+ // \nt\private\windows\shell\library\expenv.c.
+ //
+
+ ULONG ul;
+ register PDOENVIRONMENTSUBST16 parg16;
+ PSZ psz;
+ WORD cch;
+ PSZ pszExpanded;
+ DWORD cchExpanded;
+
+ GETARGPTR(pFrame, sizeof(DOENVIRONMENTSUBST16), parg16);
+ GETPSZPTR(parg16->vpsz, psz);
+ cch = FETCHWORD(parg16->cch);
+
+ LOGDEBUG(0,("WS32DoEnvironmentSubst input: '%s'\n", psz));
+
+ //
+ // DoEnvironmentSubst makes its substitution in an allocated
+ // buffer of cch characters. If the substution is too long
+ // to fit, the original string is left untouched and the
+ // low word of the return is FALSE, the high word is the
+ // value of cch. If it fits, the string is overlaid and
+ // the low word of the return is TRUE, and the high word
+ // is the length (strlen()-style) of the expanded string.
+ //
+
+ if (!(pszExpanded = malloc_w(cch * sizeof(*psz)))) {
+ goto Fail;
+ }
+
+ cchExpanded = ExpandEnvironmentStrings(
+ psz, // source
+ pszExpanded, // dest.
+ cch // dest. size
+ );
+
+ if (cchExpanded <= (DWORD)cch) {
+
+ //
+ // Succeeded, copy expanded string to caller's buffer.
+ // cchExpanded includes null terminator, our return
+ // code doesn't.
+ //
+
+ RtlCopyMemory(psz, pszExpanded, cchExpanded);
+
+ WOW32ASSERT((cchExpanded - 1) == strlen(psz));
+ LOGDEBUG(0,("WS32DoEnvironmentSubst output: '%s'\n", psz));
+
+ FLUSHVDMPTR(parg16->vpsz, (USHORT)cchExpanded, psz);
+ ul = MAKELONG((WORD)(cchExpanded - 1), TRUE);
+
+ } else {
+
+ Fail:
+ ul = MAKELONG((WORD)cch, FALSE);
+ LOGDEBUG(0,("WS32DoEnvironmentSubst failing!!!\n"));
+
+ }
+
+ if (pszExpanded) {
+ free_w(pszExpanded);
+ }
+
+ FREEPSZPTR(psz);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+ULONG FASTCALL WS32RegOpenKey(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PREGOPENKEY16 parg16;
+ HKEY hkResult = 0;
+ HKEY hkey;
+ PSZ psz;
+ PSZ psz1 = NULL;
+ PHKEY lp;
+
+ GETARGPTR(pFrame, sizeof(REGOPENKEY16), parg16);
+ GETPSZPTR(parg16->f2, psz);
+ GETOPTPTR(parg16->f3, 0, lp);
+
+ hkey = (HKEY)FETCHDWORD(parg16->f1);
+ if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
+ hkey = (HKEY)HKEY_CLASSES_ROOT;
+ }
+
+ if (!hkey) {
+
+ if (psz) {
+ psz1 = Remove_Classes (psz);
+ }
+
+
+ ul = RegOpenKey (
+ HKEY_CLASSES_ROOT,
+ psz1,
+ &hkResult
+ );
+
+ if ((psz1) && (psz1 != psz)) {
+ free_w (psz1);
+ }
+
+ }
+ else {
+ ul = RegOpenKey (
+ hkey,
+ psz,
+ &hkResult
+ );
+ }
+
+ STOREDWORD(*lp, hkResult);
+ FLUSHVDMPTR(parg16->f3, 4, lp);
+
+ ul = ConvertToWin31Error(ul);
+
+ FREEOPTPTR(lp);
+ FREEPSZPTR(psz);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WS32RegCreateKey(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PREGCREATEKEY16 parg16;
+ PSZ psz;
+ PSZ psz1 = NULL;
+ HKEY hkResult = 0;
+ HKEY hkey;
+ PHKEY lp;
+
+ GETARGPTR(pFrame, sizeof(REGCREATEKEY16), parg16);
+ GETPSZPTR(parg16->f2, psz);
+ GETOPTPTR(parg16->f3, 0, lp);
+
+ hkey = (HKEY)FETCHDWORD(parg16->f1);
+ if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
+ hkey = (HKEY)HKEY_CLASSES_ROOT;
+ }
+
+ if (!hkey) {
+
+ if (psz) {
+ psz1 = Remove_Classes (psz);
+ }
+
+ ul = RegCreateKey (
+ HKEY_CLASSES_ROOT,
+ psz1,
+ &hkResult
+ );
+
+ if ((psz1) && (psz1 != psz)) {
+ free_w (psz1);
+ }
+
+
+ }
+ else {
+ ul = RegCreateKey (
+ hkey,
+ psz,
+ &hkResult
+ );
+ }
+
+ STOREDWORD(*lp, hkResult);
+ FLUSHVDMPTR(parg16->f3, 4, lp);
+
+ ul = ConvertToWin31Error(ul);
+
+ FREEOPTPTR(lp);
+ FREEPSZPTR(psz);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WS32RegCloseKey(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PREGCLOSEKEY16 parg16;
+ HKEY hkey;
+
+ GETARGPTR(pFrame, sizeof(REGCLOSEKEY16), parg16);
+
+ hkey = (HKEY)FETCHDWORD(parg16->f1);
+ if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
+ hkey = (HKEY)HKEY_CLASSES_ROOT;
+ }
+
+ ul = RegCloseKey (
+ hkey
+ );
+
+ ul = ConvertToWin31Error(ul);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WS32RegDeleteKey(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PREGDELETEKEY16 parg16;
+ HKEY hkey;
+ PSZ psz;
+ PSZ psz1 = NULL;
+
+ GETARGPTR(pFrame, sizeof(REGDELETEKEY16), parg16);
+ GETPSZPTR(parg16->f2, psz);
+
+ hkey = (HKEY)FETCHDWORD(parg16->f1);
+ if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
+ hkey = (HKEY)HKEY_CLASSES_ROOT;
+ }
+
+ //
+ // Fail any attempt to RegDeleteKey(something, NULL),
+ // with ERROR_BADKEY as Win3.1 does.
+ //
+
+ if ((!psz) || (*psz == '\0')) {
+ ul = ERROR_BADKEY;
+ } else {
+
+ if (!hkey) {
+
+ psz1 = Remove_Classes (psz);
+
+ ul = WOWRegDeleteKey (
+ HKEY_CLASSES_ROOT,
+ psz1
+ );
+
+
+ if ((psz1) && (psz1 != psz)) {
+ free_w (psz1);
+ }
+
+ } else {
+
+ ul = WOWRegDeleteKey (
+ hkey,
+ psz
+ );
+ }
+
+ }
+
+ ul = ConvertToWin31Error(ul);
+
+ FREEPSZPTR(psz);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+LONG
+WOWRegDeleteKey(
+ IN HKEY hKey,
+ IN LPCTSTR lpszSubKey
+ )
+
+/*++
+
+Routine Description:
+
+ There is a significant difference between the Win3.1 and Win32
+ behavior of RegDeleteKey when the key in question has subkeys.
+ The Win32 API does not allow you to delete a key with subkeys,
+ while the Win3.1 API deletes a key and all its subkeys.
+
+ This routine is a recursive worker that enumerates the subkeys
+ of a given key, applies itself to each one, then deletes itself.
+
+ It specifically does not attempt to deal rationally with the
+ case where the caller may not have access to some of the subkeys
+ of the key to be deleted. In this case, all the subkeys which
+ the caller can delete will be deleted, but the api will still
+ return ERROR_ACCESS_DENIED.
+
+Arguments:
+
+ hKey - Supplies a handle to an open registry key.
+
+ lpszSubKey - Supplies the name of a subkey which is to be deleted
+ along with all of its subkeys.
+
+Return Value:
+
+ ERROR_SUCCESS - entire subtree successfully deleted.
+
+ ERROR_ACCESS_DENIED - given subkey could not be deleted.
+
+--*/
+
+{
+ DWORD i;
+ HKEY Key;
+ LONG Status;
+ DWORD ClassLength=0;
+ DWORD SubKeys;
+ DWORD MaxSubKey;
+ DWORD MaxClass;
+ DWORD Values;
+ DWORD MaxValueName;
+ DWORD MaxValueData;
+ DWORD SecurityLength;
+ FILETIME LastWriteTime;
+ LPTSTR NameBuffer;
+
+ //
+ // First open the given key so we can enumerate its subkeys
+ //
+ Status = RegOpenKeyEx(hKey,
+ lpszSubKey,
+ 0,
+ KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
+ &Key);
+ if (Status != ERROR_SUCCESS) {
+ //
+ // possibly we have delete access, but not enumerate/query.
+ // So go ahead and try the delete call, but don't worry about
+ // any subkeys. If we have any, the delete will fail anyway.
+ //
+ return(RegDeleteKey(hKey,lpszSubKey));
+ }
+
+ //
+ // Use RegQueryInfoKey to determine how big to allocate the buffer
+ // for the subkey names.
+ //
+ Status = RegQueryInfoKey(Key,
+ NULL,
+ &ClassLength,
+ 0,
+ &SubKeys,
+ &MaxSubKey,
+ &MaxClass,
+ &Values,
+ &MaxValueName,
+ &MaxValueData,
+ &SecurityLength,
+ &LastWriteTime);
+ if ((Status != ERROR_SUCCESS) &&
+ (Status != ERROR_MORE_DATA) &&
+ (Status != ERROR_INSUFFICIENT_BUFFER)) {
+ RegCloseKey(Key);
+ return(Status);
+ }
+
+ NameBuffer = malloc_w(MaxSubKey + 1);
+ if (NameBuffer == NULL) {
+ RegCloseKey(Key);
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ //
+ // Enumerate subkeys and apply ourselves to each one.
+ //
+ i=0;
+ do {
+ Status = RegEnumKey(Key,
+ i,
+ NameBuffer,
+ MaxSubKey+1);
+ if (Status == ERROR_SUCCESS) {
+ Status = WOWRegDeleteKey(Key,NameBuffer);
+ }
+
+ if (Status != ERROR_SUCCESS) {
+ //
+ // Failed to delete the key at the specified index. Increment
+ // the index and keep going. We could probably bail out here,
+ // since the api is going to fail, but we might as well keep
+ // going and delete everything we can.
+ //
+ ++i;
+ }
+
+ } while ( (Status != ERROR_NO_MORE_ITEMS) &&
+ (i < SubKeys) );
+
+ free_w(NameBuffer);
+ RegCloseKey(Key);
+ return(RegDeleteKey(hKey,lpszSubKey));
+
+}
+
+
+
+
+ULONG FASTCALL WS32RegSetValue(PVDMFRAME pFrame)
+{
+ register PREGSETVALUE16 parg16;
+ ULONG ul;
+ CHAR szZero[] = { '0', '\0' };
+ HKEY hkey;
+ PSZ psz2;
+ PSZ psz1 = NULL;
+ LPBYTE lpszData;
+
+ GETARGPTR(pFrame, sizeof(REGSETVALUE16), parg16);
+
+ // Do what Win 3.1 does
+ if(parg16->f3 != REG_SZ) {
+ FREEARGPTR(parg16);
+ return(WIN16_ERROR_INVALID_PARAMETER);
+ }
+
+ GETOPTPTR(parg16->f2, 0, psz2);
+
+ // Windows 3.1 API reference says that cb (f5) is ignored.
+ // Ergo, remove it from this call and use 1 in its place
+ // (1 being the smallest size of a sz string)
+ if(parg16->f4) {
+ GETOPTPTR(parg16->f4, 1, lpszData);
+ }
+
+ // Quattro Pro 6.0 Install passes lpszData == NULL
+ // In Win3.1, if(!lpszData || *lpszData == '\0') the value is set to 0
+ else {
+ lpszData = szZero;
+ }
+
+ hkey = (HKEY)FETCHDWORD(parg16->f1);
+ if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
+ hkey = (HKEY)HKEY_CLASSES_ROOT;
+ }
+
+ if (!hkey) {
+
+ if (psz2) {
+ psz1 = Remove_Classes (psz2);
+ }
+
+ ul = RegSetValue (HKEY_CLASSES_ROOT,
+ psz1,
+ REG_SZ,
+ lpszData,
+ lstrlen(lpszData));
+
+ if ((psz1) && (psz1 != psz2)) {
+ free_w (psz1);
+ }
+ }
+ else {
+
+ ul = RegSetValue (hkey,
+ psz2,
+ REG_SZ,
+ lpszData,
+ lstrlen(lpszData));
+ }
+
+ ul = ConvertToWin31Error(ul);
+
+ FREEOPTPTR(psz2);
+ FREEOPTPTR(lpszData);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WS32RegQueryValue(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PREGQUERYVALUE16 parg16;
+ HKEY hkey;
+ PSZ psz1 = NULL;
+ PSZ psz2;
+ LPBYTE lpszData;
+ LPDWORD lpcbValue;
+ DWORD cbValue;
+#define QUERYBUFFERSIZE 128
+ DWORD cbOriginalValue;
+ BYTE cbBuffer[QUERYBUFFERSIZE];
+ LPBYTE lpByte = NULL;
+ BOOL fAllocated = FALSE;
+
+ GETARGPTR(pFrame, sizeof(REGQUERYVALUE16), parg16);
+ GETOPTPTR(parg16->f2, 0, psz2);
+ GETOPTPTR(parg16->f3, 0, lpszData);
+ GETOPTPTR(parg16->f4, 0, lpcbValue);
+
+ if ( lpcbValue == NULL ) { // Prevent us from dying just in case!
+ FREEOPTPTR(psz2);
+ FREEOPTPTR(lpszData);
+ FREEOPTPTR(lpcbValue);
+ FREEARGPTR(parg16);
+ return( WIN16_ERROR_INVALID_PARAMETER );
+ }
+
+ cbOriginalValue = cbValue = FETCHDWORD(*lpcbValue);
+
+ // Fix MSTOOLBR.DLL unintialized cbValue by forcing it to be less than 64K
+ // Win 3.1 Registry values are always less than 64K.
+ cbOriginalValue &= 0x0000FFFF;
+
+ if ( lpszData == NULL ) {
+ lpByte = NULL;
+ } else {
+ lpByte = cbBuffer;
+
+ if ( cbOriginalValue > QUERYBUFFERSIZE ) {
+ lpByte = malloc_w(cbOriginalValue);
+ if ( lpByte == NULL ) {
+ FREEOPTPTR(psz2);
+ FREEOPTPTR(lpszData);
+ FREEOPTPTR(lpcbValue);
+ FREEARGPTR(parg16);
+ RETURN( WIN16_ERROR_OUTOFMEMORY );
+ }
+ fAllocated = TRUE;
+ }
+ }
+
+ hkey = (HKEY)FETCHDWORD(parg16->f1);
+ if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
+ hkey = (HKEY)HKEY_CLASSES_ROOT;
+ }
+
+ if (!hkey) {
+
+ if (psz2) {
+ psz1 = Remove_Classes (psz2);
+ }
+ hkey = HKEY_CLASSES_ROOT;
+ } else {
+ psz1 = psz2;
+ }
+
+ ul = RegQueryValue (
+ hkey,
+ psz1,
+ lpByte,
+ &cbValue
+ );
+
+ if (ul == ERROR_SUCCESS) {
+ if ( lpszData ) {
+ memcpy( lpszData, lpByte, cbValue );
+ }
+ } else {
+ if ( ul == ERROR_MORE_DATA ) {
+ //
+ // We need to allocate more
+ //
+ if ( fAllocated ) {
+ free_w( lpByte );
+ }
+ lpByte = malloc_w( cbValue );
+ if ( lpByte == NULL ) {
+ if ((psz1) && (psz1 != psz2)) {
+ // If we did some key name copying, then free that buffer
+ free_w (psz1);
+ }
+ FREEOPTPTR(psz2);
+ FREEOPTPTR(lpszData);
+ FREEOPTPTR(lpcbValue);
+ FREEARGPTR(parg16);
+ RETURN(WIN16_ERROR_OUTOFMEMORY);
+ }
+ fAllocated = TRUE;
+
+ ul = RegQueryValue( hkey,
+ psz1,
+ lpByte,
+ &cbValue );
+ cbValue = cbOriginalValue;
+ if ( lpszData ) {
+ memcpy( lpszData, lpByte, cbValue );
+ }
+ }
+ }
+
+ if ((psz1) && (psz1 != psz2)) {
+ // If we did some key name copying, then free that buffer
+ free_w (psz1);
+ }
+
+ if ( fAllocated ) {
+ // If we've allocated memory for the output buffer, then free it
+ free_w (lpByte);
+ }
+
+ STOREDWORD(*lpcbValue, cbValue);
+ FLUSHVDMPTR(parg16->f4, 4, lpcbValue);
+
+ if ( lpszData != NULL ) {
+ FLUSHVDMPTR(parg16->f3, (USHORT)cbValue, lpszData);
+ }
+
+ ul = ConvertToWin31Error(ul);
+
+ FREEOPTPTR(psz2);
+ FREEOPTPTR(lpszData);
+ FREEOPTPTR(lpcbValue);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+ULONG FASTCALL WS32RegEnumKey(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PREGENUMKEY16 parg16;
+ HKEY hkey;
+ LPBYTE lpszName;
+
+ GETARGPTR(pFrame, sizeof(REGENUMKEY16), parg16);
+ GETOPTPTR(parg16->f3, parg16->f4, lpszName);
+
+ hkey = (HKEY)FETCHDWORD(parg16->f1);
+ if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
+ hkey = (HKEY)HKEY_CLASSES_ROOT;
+ }
+
+ ul = RegEnumKey (
+ hkey,
+ parg16->f2,
+ lpszName,
+ parg16->f4
+ );
+
+ FLUSHVDMPTR(parg16->f3, (USHORT)parg16->f4, lpszName);
+
+ ul = ConvertToWin31Error(ul);
+
+ FREEOPTPTR(lpszName);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WS32DragAcceptFiles(PVDMFRAME pFrame)
+{
+ ULONG ul=0;
+ register PDRAGACCEPTFILES16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DRAGACCEPTFILES16), parg16);
+ DragAcceptFiles(HWND32(parg16->f1),(BOOL)parg16->f2);
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+
+ULONG FASTCALL WS32DragQueryFile(PVDMFRAME pFrame)
+{
+ ULONG ul = 0l;
+ register PDRAGQUERYFILE16 parg16;
+ LPSTR lpFile;
+ HANDLE hdfs32;
+
+ GETARGPTR(pFrame, sizeof(DRAGQUERYFILE16), parg16);
+
+ if (hdfs32 = HDROP32(parg16->f1)) {
+ GETOPTPTR(parg16->f3, parg16->f4, lpFile);
+ ul = DragQueryFileAorW (hdfs32, INT32(parg16->f2),
+ lpFile, parg16->f4, TRUE,TRUE);
+
+ if ((lpFile != NULL) && (parg16->f2 != -1)) {
+ FLUSHVDMPTR(parg16->f3, parg16->f4, lpFile);
+ }
+
+ FREEOPTPTR(lpFile);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WS32DragFinish(PVDMFRAME pFrame)
+{
+ register PDRAGFINISH16 parg16;
+ HDROP h32;
+
+ GETARGPTR(pFrame, sizeof(PDRAGFINISH16), parg16);
+
+ //
+ // freehdrop16, frees the alias and returns the corresponding h32
+ //
+
+ if (h32 = FREEHDROP16(parg16->f1)) {
+ DragFinish(h32);
+ }
+
+ FREEARGPTR(parg16);
+
+ return 0;
+}
+
+
+ULONG FASTCALL WS32ShellAbout (PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSHELLABOUT16 parg16;
+ PSZ psz2;
+ PSZ psz3;
+
+ GETARGPTR(pFrame, sizeof(SHELLABOUT16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+ GETPSZPTR(parg16->f3, psz3);
+
+ ul = GETINT16(ShellAbout (
+ HWND32(parg16->f1),
+ psz2,
+ psz3,
+ HICON32(parg16->f4)
+ ));
+
+ FREEPSZPTR(psz2);
+ FREEPSZPTR(psz3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+// NOTE : The return value can be instance handle or the handle of a
+// DDE server. So, take this information into account while debugging
+// the effect of the return value from this API. ChandanC 4/24/92.
+// You would notice that I am treating the return value as HINSTANCE.
+//
+
+ULONG FASTCALL WS32ShellExecute (PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSHELLEXECUTE16 parg16;
+ PSZ psz2;
+ PSZ psz3;
+ PSZ psz4;
+ PSZ psz5;
+
+ GETARGPTR(pFrame, sizeof(SHELLEXECUTE16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+ GETPSZPTR(parg16->f3, psz3);
+ GETPSZPTR(parg16->f4, psz4);
+ GETPSZPTR(parg16->f5, psz5);
+
+ ul = GETHINST16(WOWShellExecute (
+ HWND32(parg16->f1),
+ psz2,
+ psz3,
+ psz4,
+ psz5,
+ parg16->f6,
+ (LPFNWOWSHELLEXECCB) W32ShellExecuteCallBack
+ ));
+
+ FREEPSZPTR(psz2);
+ FREEPSZPTR(psz3);
+ FREEPSZPTR(psz4);
+ FREEPSZPTR(psz5);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+WORD W32ShellExecuteCallBack (LPSZ lpszCmdLine, WORD fuCmdShow)
+{
+ PBYTE lpstr16;
+ PARM16 Parm16;
+ ULONG ul = 0;
+ VPVOID vpstr16;
+
+ UpdateDosCurrentDirectory(DIR_NT_TO_DOS);
+
+ if (vpstr16 = malloc16 (lstrlen(lpszCmdLine)+1)) {
+ GETMISCPTR (vpstr16, lpstr16);
+ if (lpstr16) {
+ lstrcpy (lpstr16, lpszCmdLine);
+
+ Parm16.WndProc.wParam = fuCmdShow;
+ Parm16.WndProc.lParam = vpstr16;
+ CallBack16(RET_WINEXEC, &Parm16, 0, &ul);
+ FREEMISCPTR (lpstr16);
+ }
+
+ free16(vpstr16);
+ }
+
+ return (LOWORD(ul));
+}
+
+
+ULONG FASTCALL WS32FindExecutable (PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PFINDEXECUTABLE16 parg16;
+ PSZ psz1;
+ PSZ psz2;
+ PSZ psz3;
+
+ GETARGPTR(pFrame, sizeof(FINDEXECUTABLE16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+ GETPSZPTR(parg16->f2, psz2);
+ GETPSZPTRNOLOG(parg16->f3, psz3);
+
+ ul = (ULONG) FindExecutable (
+ psz1,
+ psz2,
+ psz3
+ );
+
+ LOGDEBUG(11,(" returns @%08lx: \"%.80s\"\n", FETCHDWORD(parg16->f3), psz3));
+ FLUSHVDMPTR(parg16->f3, strlen(psz3)+1, psz3);
+
+ // This is for success condition.
+
+ if (ul > 32) {
+ ul = GETHINST16 (ul);
+ }
+
+ FREEPSZPTR(psz1);
+ FREEPSZPTR(psz2);
+ FREEPSZPTR(psz3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WS32ExtractIcon (PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PEXTRACTICON16 parg16;
+ PSZ psz;
+ UINT Id;
+
+ GETARGPTR(pFrame, sizeof(EXTRACTICON16), parg16);
+ GETPSZPTR(parg16->f2, psz);
+
+ Id = (parg16->f3 == (WORD)0xffff) ? (UINT)(SHORT)parg16->f3 :
+ (UINT)parg16->f3;
+ ul = (ULONG) ExtractIcon (HMODINST32(parg16->f1), psz, Id);
+
+ // This is for success condition.
+
+ if ((Id != (UINT)(-1)) && ul > 1) {
+ ul = GETHICON16(ul);
+ }
+
+ FREEPSZPTR(psz);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//
+// This routine convert the Win 32 registry error codes to Win 31
+// error codes.
+//
+
+ULONG ConvertToWin31Error(ULONG ul)
+{
+
+ LOGDEBUG(3, ("WOW::ConvertToWin31Error: Ret value from NT = %08lx\n", ul));
+
+ switch (ul) {
+
+ case ERROR_SUCCESS: return(WIN16_ERROR_SUCCESS);
+ case ERROR_BADDB: return(WIN16_ERROR_BADDB);
+ case ERROR_BADKEY: return(WIN16_ERROR_BADKEY);
+ case ERROR_CANTOPEN: return(WIN16_ERROR_CANTOPEN);
+ case ERROR_CANTREAD: return(WIN16_ERROR_CANTREAD);
+ case ERROR_CANTWRITE: return(WIN16_ERROR_CANTWRITE);
+ case ERROR_OUTOFMEMORY: return(WIN16_ERROR_OUTOFMEMORY);
+ case ERROR_INVALID_PARAMETER: return(WIN16_ERROR_INVALID_PARAMETER);
+ case ERROR_EA_ACCESS_DENIED: return(WIN16_ERROR_ACCESS_DENIED);
+ case ERROR_MORE_DATA: return(WIN16_ERROR_INVALID_PARAMETER);
+ case ERROR_FILE_NOT_FOUND: return(WIN16_ERROR_BADKEY);
+ case ERROR_NO_MORE_ITEMS: return(WIN16_ERROR_BADKEY);
+
+ default:
+ LOGDEBUG(3, ("WOW::Registry Error Code unknown =%08lx : returning 8 (WIN16_ERROR_ACCESS_DENIED)\n", ul));
+ return (WIN16_ERROR_ACCESS_DENIED);
+ }
+
+}
+
+LPSZ Remove_Classes (LPSZ psz)
+{
+ LPSZ lpsz;
+ LPSZ lpsz1;
+
+ if (!_stricmp (".classes", psz)) {
+ if (lpsz = malloc_w (1)) {
+ *lpsz = '\0';
+ return (lpsz);
+ }
+ }
+ else {
+ if (*psz) {
+ lpsz = strchr (psz, '\\');
+ if (lpsz) {
+ *lpsz = '\0';
+ if (!_stricmp (".classes", lpsz)) {
+ *lpsz = '\\';
+ if (lpsz1 = malloc_w (strlen(lpsz+1)+1)) {
+ strcpy (lpsz1, (lpsz+1));
+ return (lpsz1);
+ }
+ else {
+ return (0);
+ }
+ }
+ *lpsz = '\\';
+ return (psz);
+ }
+ else {
+ return (psz);
+ }
+ }
+ else {
+ return (psz);
+ }
+ }
+}
+
+
+//****************************************************************************
+// DropFilesHandler -
+// takes either h16 or h32 as input. flInput identifies the type of the
+// handle and other operations to perform. return value varies but in most
+// cases it is the opposite to the 'input type'- ie returns h16 if h32 was
+// input and viceversa.
+// - nanduri
+//****************************************************************************
+
+
+LPDROPALIAS glpDropAlias = NULL;
+
+DWORD DropFilesHandler(HAND16 h16, HANDLE h32, UINT flInput)
+{
+ LPDROPALIAS lpT;
+ LPDROPALIAS lpTprev = (LPDROPALIAS)NULL;
+ DWORD dwRet = 0;
+
+ WOW32ASSERT((h16) || (h32));
+
+ //
+ // Look for the handle
+ //
+ for (lpT = glpDropAlias; lpT != (LPDROPALIAS)NULL; lpT = lpT->lpNext) {
+ if (((flInput & HDROP_H16) && ((lpT->h16 & ~1) == (h16 & ~ 1))) ||
+ ((flInput & HDROP_H32) && lpT->h32 == h32)) {
+ break;
+ }
+ else if (flInput & HDROP_FREEALIAS) {
+ lpTprev = lpT;
+ }
+ }
+
+ //
+ // if not found, create the alias if requested
+ //
+
+ if (lpT == (LPDROPALIAS)NULL && (flInput & HDROP_ALLOCALIAS)) {
+ if (lpT = malloc_w(sizeof(DROPALIAS))) {
+ lpT->h16 = h16;
+ lpT->h32 = h32;
+ lpT->lpNext = glpDropAlias;
+ glpDropAlias = lpT;
+ flInput |= HDROP_COPYDATA;
+ }
+ }
+
+ //
+ // if found - do the necessary operation. all (other) HDROP_* flags
+ // have priority over HDROP_H16 and HDROP_H32 flags.
+ //
+
+ if (lpT) {
+ if (flInput & HDROP_COPYDATA) {
+ if (h32) {
+ dwRet = (DWORD) (lpT->h16 = CopyDropFilesFrom32(h32));
+ } else {
+ dwRet = (DWORD) (lpT->h32 = CopyDropFilesFrom16(h16));
+ }
+ }
+ else if (flInput & HDROP_FREEALIAS) {
+ dwRet = (DWORD)lpT->h32;
+ if (lpTprev) {
+ lpTprev->lpNext = lpT->lpNext;
+ }
+ else {
+ glpDropAlias = lpT->lpNext;
+ }
+ free_w(lpT);
+ }
+ else if (flInput & HDROP_H16) {
+ dwRet = (DWORD)lpT->h32;
+ }
+ else if (flInput & HDROP_H32) {
+ dwRet = (DWORD)lpT->h16;
+ }
+ }
+
+ return (dwRet);
+}
+
+//****************************************************************************
+// CopyDropFilesStruct -
+//
+// returns h16.
+//****************************************************************************
+
+HAND16 CopyDropFilesFrom32(HANDLE h32)
+{
+ UINT cbSize;
+ HAND16 hRet = 0;
+ HAND16 hMem;
+ VPVOID vp;
+
+ //
+ // the allocated 16bit handle and the corresponding 32bit handle
+ // are freed in the shell api 'DragFinish' (if it is called by the app)
+ //
+
+ cbSize = GlobalSize((HANDLE)h32);
+ if (vp = GlobalAllocLock16(GMEM_DDESHARE, cbSize, &hMem)) {
+ LPDROPFILESTRUCT lpdfs32;
+ PDROPFILESTRUCT16 lpdfs16;
+ ULONG uIgnore;
+
+ GETMISCPTR(vp, lpdfs16);
+ if (lpdfs32 = (LPDROPFILESTRUCT)GlobalLock((HANDLE)h32)) {
+ //
+ // pFiles is a byte count to the beginning of the file.
+ //
+ lpdfs16->pFiles = sizeof(DROPFILESTRUCT16);
+ lpdfs16->x = (SHORT) lpdfs32->pt.x;
+ lpdfs16->y = (SHORT) lpdfs32->pt.y;
+ lpdfs16->fNC = lpdfs32->fNC;
+
+ if (lpdfs32->fWide) {
+ RtlUnicodeToMultiByteN(((PCHAR)lpdfs16)+lpdfs16->pFiles,
+ cbSize-lpdfs16->pFiles,
+ &uIgnore,
+ (PWSTR)(((PCHAR)lpdfs32)+lpdfs32->pFiles),
+ cbSize-lpdfs32->pFiles);
+ }
+ else {
+
+ //
+ // Copy the files after each structure.
+ // The offset from the beginning of the structure changes
+ // (since the structures are differenly sized), but we
+ // compensate by changes pFiles above.
+ //
+ RtlCopyMemory(lpdfs16+1, lpdfs32+1,
+ GlobalSize((HANDLE)h32) - sizeof(DROPFILESTRUCT));
+ }
+
+ GlobalUnlock((HANDLE)h32);
+ hRet = hMem;
+ }
+ else {
+ GlobalUnlockFree16(vp);
+ }
+ FREEMISCPTR(lpdfs16);
+ }
+
+ return (hRet);
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* CopyDropFilesFrom16() */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HANDLE CopyDropFilesFrom16(HAND16 h16)
+{
+ HANDLE h32;
+ ULONG cbSize16;
+ UINT cbSize32;
+ VPVOID vp;
+
+ if (vp = GlobalLock16(h16, &cbSize16)) {
+ LPDROPFILESTRUCT lpdfs32;
+ PDROPFILESTRUCT16 lpdfs16;
+
+ GETMISCPTR(vp, lpdfs16);
+
+ cbSize32 = 2*sizeof(TCHAR) + sizeof(DROPFILESTRUCT) +
+ (cbSize16 - sizeof(DROPFILESTRUCT16));
+
+ if (h32 = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
+ cbSize32)){
+
+ lpdfs32 = (LPDROPFILESTRUCT)GlobalLock(h32);
+
+ lpdfs32->pFiles = sizeof(DROPFILESTRUCT);
+ lpdfs32->pt.x = (LONG) lpdfs16->x;
+ lpdfs32->pt.y = (LONG) lpdfs16->y;
+ lpdfs32->fNC = lpdfs16->fNC;
+ lpdfs32->fWide = FALSE;
+
+ RtlCopyMemory(lpdfs32+1, lpdfs16+1,
+ cbSize16 - sizeof(DROPFILESTRUCT16));
+
+ GlobalUnlock(h32);
+ }
+
+ FREEMISCPTR(lpdfs16);
+ GlobalUnlock16(h16);
+ }
+
+ return(h32);
+
+}
diff --git a/private/mvdm/wow32/wshell.h b/private/mvdm/wow32/wshell.h
new file mode 100644
index 000000000..025521e95
--- /dev/null
+++ b/private/mvdm/wow32/wshell.h
@@ -0,0 +1,51 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSHELL.H
+ * WOW32 16-bit SHELL API support
+ *
+ * History:
+ * Created 14-April-1992 by Chandan Chauhan (ChandanC)
+--*/
+
+ULONG FASTCALL WS32DoEnvironmentSubst(PVDMFRAME pFrame);
+ULONG FASTCALL WS32RegOpenKey(PVDMFRAME pFrame);
+ULONG FASTCALL WS32RegCreateKey(PVDMFRAME pFrame);
+ULONG FASTCALL WS32RegCloseKey(PVDMFRAME pFrame);
+ULONG FASTCALL WS32RegDeleteKey(PVDMFRAME pFrame);
+ULONG FASTCALL WS32RegSetValue(PVDMFRAME pFrame);
+ULONG FASTCALL WS32RegQueryValue(PVDMFRAME pFrame);
+ULONG FASTCALL WS32RegEnumKey(PVDMFRAME pFrame);
+ULONG FASTCALL WS32DragAcceptFiles(PVDMFRAME pFrame);
+ULONG FASTCALL WS32DragQueryFile(PVDMFRAME pFrame);
+ULONG FASTCALL WS32DragFinish (PVDMFRAME pFrame);
+ULONG FASTCALL WS32DragQueryPoint (PVDMFRAME pFrame);
+ULONG FASTCALL WS32ShellAbout (PVDMFRAME pFrame);
+ULONG FASTCALL WS32ShellExecute (PVDMFRAME pFrame);
+ULONG FASTCALL WS32FindExecutable (PVDMFRAME pFrame);
+ULONG FASTCALL WS32ExtractIcon (PVDMFRAME pFrame);
+
+ULONG ConvertToWin31Error(ULONG ul);
+LPSZ Remove_Classes (LPSZ psz);
+
+WORD W32ShellExecuteCallBack (LPSZ lpszCmdLine, WORD fuCmdShow);
+
+typedef struct _DROPALIAS {
+ struct _DROPALIAS FAR *lpNext;
+ HAND32 h32;
+ HAND16 h16;
+} DROPALIAS, *LPDROPALIAS;
+
+#define HDROP_H16 0x0001
+#define HDROP_H32 0x0002
+#define HDROP_FREEALIAS 0x0004
+#define HDROP_ALLOCALIAS 0x0008
+#define HDROP_COPYDATA 0x0010
+
+HAND16 CopyDropFilesFrom32(HANDLE h32);
+HANDLE CopyDropFilesFrom16(HAND16 h16);
+DWORD DropFilesHandler(HAND16 h16, HANDLE h32, UINT flInput);
+
diff --git a/private/mvdm/wow32/wshltbl.h b/private/mvdm/wow32/wshltbl.h
new file mode 100644
index 000000000..9b38c4e9e
--- /dev/null
+++ b/private/mvdm/wow32/wshltbl.h
@@ -0,0 +1,25 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSHLTBL.H
+ * WOW32 16-bit SHELL API tables
+ *
+ * History:
+ * Created 14-April-1992 by Chandan Chauhan (ChandanC)
+ *
+--*/
+
+
+
+/* SHELL dispatch table
+ */
+extern W32 aw32Shell[];
+
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iShellMax;
+#endif
diff --git a/private/mvdm/wow32/wshtbl2.h b/private/mvdm/wow32/wshtbl2.h
new file mode 100644
index 000000000..52f300fac
--- /dev/null
+++ b/private/mvdm/wow32/wshtbl2.h
@@ -0,0 +1,138 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSHTBL2.h
+ * WOW32 16-bit SHELL API tables
+ *
+ * History:
+ * Created 14-April-1992 by Chandan Chauhan (ChandanC)
+--*/
+
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_SHELL, 0)},
+ {W32FUN(WS32RegOpenKey, "RegOpenKey", MOD_SHELL, sizeof(REGOPENKEY16))},
+ {W32FUN(WS32RegCreateKey, "RegCreateKey", MOD_SHELL, sizeof(REGCREATEKEY16))},
+ {W32FUN(WS32RegCloseKey, "RegCloseKey", MOD_SHELL, sizeof(REGCLOSEKEY16))},
+ {W32FUN(WS32RegDeleteKey, "RegDeleteKey", MOD_SHELL, sizeof(REGDELETEKEY16))},
+ {W32FUN(WS32RegSetValue, "RegSetValue", MOD_SHELL, sizeof(REGSETVALUE16))},
+ {W32FUN(WS32RegQueryValue, "RegQueryValue", MOD_SHELL, sizeof(REGQUERYVALUE16))},
+ {W32FUN(WS32RegEnumKey, "RegEnumKey", MOD_SHELL, sizeof(REGENUMKEY16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(WS32DragAcceptFiles, "DragAcceptFiles", MOD_SHELL, sizeof(DRAGACCEPTFILES16))},
+
+ /*** 0010 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(WS32DragQueryFile, "DragQueryFile", MOD_SHELL, sizeof(DRAGQUERYFILE16))},
+ {W32FUN(WS32DragFinish, "DragFinish", MOD_SHELL, sizeof(DRAGFINISH16))},
+ {W32FUN(LOCALAPI, "DragQueryPoint", MOD_SHELL, sizeof(DRAGQUERYPOINT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+
+ /*** 0020 ***/
+ {W32FUN(WS32ShellExecute, "ShellExecute", MOD_SHELL, sizeof(SHELLEXECUTE16))},
+ {W32FUN(WS32FindExecutable, "FindExecutable", MOD_SHELL, sizeof(FINDEXECUTABLE16))},
+ {W32FUN(WS32ShellAbout, "ShellAbout", MOD_SHELL, sizeof(SHELLABOUT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+
+ /*** 0030 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "WCI", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ABOUTDLGPROC", MOD_SHELL, 0)},
+ {W32FUN(WS32ExtractIcon, "ExtractIcon", MOD_SHELL, sizeof(EXTRACTICON16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ExtractAssociatedIcon",MOD_SHELL, sizeof(EXTRACTASSOCIATEDICON16))},
+ {W32FUN(WS32DoEnvironmentSubst, "DoEnvironmentSubst", MOD_SHELL, sizeof(DOENVIRONMENTSUBST16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "FINDENVIRONMENTSTRING",MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "INTERNALEXTRACTICON", MOD_SHELL, 0)},
+
+ /*** 0040 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+
+ /*** 0050 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+
+ /*** 0060 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+
+ /*** 0070 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+
+ /*** 0080 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+
+ /*** 0090 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_SHELL, 0)},
+
+ /*** 0100 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "HERETHARBETYGARS", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "FINDEXEDLGPROC", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "REGISTERSHELLHOOK", MOD_SHELL, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SHELLHOOKPROC", MOD_SHELL, 0)},
+
diff --git a/private/mvdm/wow32/wsman.c b/private/mvdm/wow32/wsman.c
new file mode 100644
index 000000000..b54fcf99e
--- /dev/null
+++ b/private/mvdm/wow32/wsman.c
@@ -0,0 +1,25 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSMAN.C
+ * WOW32 16-bit Sound API support (manually-coded thunks)
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wsman.c);
+
+ULONG FASTCALL WS32DoBeep(PVDMFRAME pFrame)
+{
+ UNREFERENCED_PARAMETER(pFrame);
+ return (ULONG)MessageBeep(0);
+}
+
diff --git a/private/mvdm/wow32/wsman.h b/private/mvdm/wow32/wsman.h
new file mode 100644
index 000000000..ac75608ab
--- /dev/null
+++ b/private/mvdm/wow32/wsman.h
@@ -0,0 +1,20 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSMAN.H
+ * WOW32 16-bit Sound API support (manually-coded thunks)
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* Sound thunks
+ */
+
+
+ULONG FASTCALL WS32DoBeep(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wsocktbl.h b/private/mvdm/wow32/wsocktbl.h
new file mode 100644
index 000000000..183ea8d80
--- /dev/null
+++ b/private/mvdm/wow32/wsocktbl.h
@@ -0,0 +1,71 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSOCKTBL.H
+ * WOW32 16-bit Winsock API tables
+ *
+ * History:
+ * Created 02-Oct-1992 by David Treadwell (davidtr)
+--*/
+
+
+
+/* Winsock dispatch table
+ */
+extern W32 aw32Winsock[];
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iWinsockMax;
+#endif
+
+ULONG FASTCALL WWS32accept(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32bind(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32closesocket(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32connect(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32getpeername(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32getsockname(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32getsockopt(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32htonl(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32htons(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32inet_addr(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32inet_ntoa(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32ioctlsocket(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32listen(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32ntohl(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32ntohs(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32recv(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32recvfrom(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32select(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32send(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32sendto(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32setsockopt(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32shutdown(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32socket(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32gethostbyaddr(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32gethostbyname(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32getprotobyname(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32getprotobynumber(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32getservbyname(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32getservbyport(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32gethostname(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAAsyncSelect(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAAsyncGetHostByAddr(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAAsyncGetHostByName(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAAsyncGetProtoByNumber(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAAsyncGetProtoByName(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAAsyncGetServByPort(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAAsyncGetServByName(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSACancelAsyncRequest(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSASetBlockingHook(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAUnhookBlockingHook(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAGetLastError(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSASetLastError(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSACancelBlockingCall(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAIsBlocking(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSAStartup(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32WSACleanup(PVDMFRAME pFrame);
+ULONG FASTCALL WWS32__WSAFDIsSet(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wspool.c b/private/mvdm/wow32/wspool.c
new file mode 100644
index 000000000..35abab8a2
--- /dev/null
+++ b/private/mvdm/wow32/wspool.c
@@ -0,0 +1,326 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSPOOL.C
+ * WOW32 printer spooler support routines
+ *
+ * These routines help a Win 3.0 task to use the print spooler apis. These
+ * apis were exposed by DDK in Win 3.1.
+ *
+ * History:
+ * Created 1-July-1993 by Chandan Chauhan (ChandanC)
+ *
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+#include <winspool.h>
+
+extern WORD gUser16hInstance;
+
+MODNAME(wspool.c);
+
+LPDEVMODE GetDefaultDevMode32(LPSTR szDriver)
+{
+ LONG cbDevMode;
+ LPDEVMODE lpDevMode = NULL;
+
+ if (szDriver != NULL) {
+
+ if (!(*spoolerapis[WOW_EXTDEVICEMODE].lpfn)) {
+ if (!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
+ goto LeaveGetDefaultDevMode32;
+ }
+ }
+
+ if ((cbDevMode = (*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(NULL, NULL, NULL, szDriver, NULL, NULL, NULL, 0)) > 0) {
+ if ((lpDevMode = (LPDEVMODE) malloc_w(cbDevMode)) != NULL) {
+ if ((*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(NULL, NULL, lpDevMode, szDriver, NULL, NULL, NULL, DM_COPY) != IDOK) {
+ free_w(lpDevMode);
+ lpDevMode = NULL;
+ }
+ }
+ }
+
+LeaveGetDefaultDevMode32:
+
+ if (!lpDevMode) {
+ LOGDEBUG(0,("WOW::GetDefaultDevMode32: Unable to get default DevMode\n"));
+ }
+ }
+
+ return(lpDevMode);
+}
+
+ULONG FASTCALL WG32OpenJob (PVDMFRAME pFrame)
+{
+ PSZ psz1;
+ PSZ psz2;
+ CHAR szDriver[40];
+ ULONG ul=0;
+ DOC_INFO_1 DocInfo1;
+ HANDLE hnd;
+ register POPENJOB16 parg16;
+ PRINTER_DEFAULTS PrinterDefault;
+ PPRINTER_DEFAULTS pPrinterDefault = NULL;
+
+ GETARGPTR(pFrame, sizeof(OPENJOB16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+ GETPSZPTR(parg16->f2, psz2);
+
+ if (!(*spoolerapis[WOW_OpenPrinterA].lpfn)) {
+ if (!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
+ return (0);
+ }
+ }
+
+ if (GetDriverName(psz1, szDriver)) {
+ if ((PrinterDefault.pDevMode = GetDefaultDevMode32(szDriver)) != NULL) {
+ PrinterDefault.pDatatype = NULL;
+ PrinterDefault.DesiredAccess = 0;
+ pPrinterDefault = &PrinterDefault;
+ }
+
+ if ((*spoolerapis[WOW_OpenPrinterA].lpfn) (szDriver, &hnd, pPrinterDefault)) {
+
+ DocInfo1.pDocName = psz2;
+ DocInfo1.pOutputFile = psz1;
+ DocInfo1.pDatatype = NULL;
+
+ if (ul = (*spoolerapis[WOW_StartDocPrinterA].lpfn) (hnd, 1, (LPBYTE)&DocInfo1)) {
+ ul = GetPrn16(hnd);
+ }
+ else {
+ ul = GetLastError();
+ }
+
+ }
+ else {
+ ul = GetLastError();
+ }
+ }
+
+ LOGDEBUG(0,("WOW::WG32OpenJob: ul = %x\n", ul));
+
+ if (pPrinterDefault) {
+ free_w(PrinterDefault.pDevMode);
+ }
+
+ FREEPSZPTR(psz1);
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32StartSpoolPage (PVDMFRAME pFrame)
+{
+ ULONG ul=0;
+ register PSTARTSPOOLPAGE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(STARTSPOOLPAGE16), parg16);
+
+ if (!(ul = (*spoolerapis[WOW_StartPagePrinter].lpfn) (Prn32(parg16->f1)))) {
+ ul = GetLastError();
+ }
+
+ LOGDEBUG(0,("WOW::WG32StartSpoolPage: ul = %x\n", ul));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32EndSpoolPage (PVDMFRAME pFrame)
+{
+ ULONG ul=0;
+ register PENDSPOOLPAGE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENDSPOOLPAGE16), parg16);
+
+ if (!(ul = (*spoolerapis[WOW_EndPagePrinter].lpfn) (Prn32(parg16->f1)))) {
+ ul = GetLastError();
+ }
+
+ LOGDEBUG(0,("WOW::WG32EndSpoolPage: ul = %x\n", ul));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32CloseJob (PVDMFRAME pFrame)
+{
+ ULONG ul=0;
+ register PCLOSEJOB16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CLOSEJOB16), parg16);
+
+ if (!(ul = (*spoolerapis[WOW_EndDocPrinter].lpfn) (Prn32(parg16->f1)))) {
+
+ ul = GetLastError();
+ }
+
+ if (!(ul = (*spoolerapis[WOW_ClosePrinter].lpfn) (Prn32(parg16->f1)))) {
+ ul = GetLastError();
+ }
+
+ if (ul) {
+ FreePrn(parg16->f1);
+ }
+
+ LOGDEBUG(0,("WOW::WG32CloseJob: ul = %x\n", ul));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32WriteSpool (PVDMFRAME pFrame)
+{
+ DWORD dwWritten;
+ ULONG ul=0;
+ register PWRITESPOOL16 parg16;
+ LPVOID pBuf;
+
+ GETARGPTR(pFrame, sizeof(WRITESPOOL16), parg16);
+ GETMISCPTR (parg16->f2, pBuf);
+
+ if (ul = (*spoolerapis[WOW_WritePrinter].lpfn) (Prn32(parg16->f1), pBuf,
+ FETCHWORD(parg16->f3), &dwWritten)) {
+ ul = FETCHWORD(parg16->f3);
+ }
+ else {
+ ul = GetLastError();
+ }
+
+ LOGDEBUG(0,("WOW::WG32WriteSpool: ul = %x\n", ul));
+
+ FREEMISCPTR(pBuf);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WG32DeleteJob (PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PDELETEJOB16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DELETEJOB16), parg16);
+
+ if (!(ul = (*spoolerapis[WOW_DeletePrinter].lpfn) (Prn32(parg16->f1)))) {
+ ul = GetLastError();
+ }
+
+ LOGDEBUG(0,("WOW::WG32DeleteJob: ul = %x\n", ul));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+WORD GetPrn16(HANDLE h32)
+{
+ HANDLE hnd;
+ HAND16 h16 = 0;
+ VPVOID vp;
+ LPBYTE lpMem16;
+
+ hnd = LocalAlloc16(LMEM_MOVEABLE, sizeof(HANDLE), (HANDLE) gUser16hInstance);
+
+ vp = LocalLock16(hnd);
+
+ if (vp) {
+ GETMISCPTR (vp, lpMem16);
+ if (lpMem16) {
+ *((PDWORD16)lpMem16) = (DWORD) h32;
+ FREEMISCPTR(lpMem16);
+ LocalUnlock16(hnd);
+ }
+ }
+ else {
+ LOGDEBUG (0, ("WOW::GETPRN16: Can't allocate a 16 bit handle\n"));
+ }
+
+ return (LOWORD(hnd));
+}
+
+
+HANDLE Prn32(WORD h16)
+{
+ VPVOID vp;
+ HANDLE h32;
+ LPBYTE lpMem16;
+
+ vp = LocalLock16 ((HANDLE) MAKELONG(h16, gUser16hInstance));
+ if (vp) {
+ GETMISCPTR (vp, lpMem16);
+
+ if (lpMem16) {
+ h32 = (HANDLE) *((PDWORD16)lpMem16);
+ FREEMISCPTR(lpMem16);
+ }
+ LocalUnlock16 ((HANDLE) MAKELONG(h16, gUser16hInstance));
+ }
+
+ return (h32);
+}
+
+
+VOID FreePrn (WORD h16)
+{
+ LocalFree16 ((HANDLE) MAKELONG(h16, gUser16hInstance));
+}
+
+
+BOOL GetDriverName (char *psz, char *szDriver)
+{
+ CHAR szAllDevices[1024];
+ CHAR *szNextDevice;
+ CHAR szPrinter[64];
+ CHAR *szOutput;
+
+ GetProfileString ("devices", NULL, "", szAllDevices, sizeof(szAllDevices));
+ szNextDevice = szAllDevices;
+
+ LOGDEBUG(6,("WOW::GetDriverName: szAllDevices = %s\n", szAllDevices));
+
+ while (*szNextDevice) {
+ GetProfileString ("devices", szNextDevice, "", szPrinter, sizeof(szPrinter));
+ if (*szPrinter) {
+ if (szOutput = strchr (szPrinter, ',')) {
+ szOutput++;
+ while (*szOutput == ' ') {
+ szOutput++;
+ }
+
+ if (!_stricmp(psz, szOutput)) {
+ break;
+ }
+ }
+ }
+
+ if (szNextDevice = strchr (szNextDevice, '\0')) {
+ szNextDevice++;
+ }
+ else {
+ szNextDevice = "";
+ break;
+ }
+ }
+
+ if (*szNextDevice) {
+ LOGDEBUG(0,("WOW::GetDriverName: szNextDevice = %s\n", szNextDevice));
+
+ if (lstrcpy (szDriver, szNextDevice)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/private/mvdm/wow32/wspool.h b/private/mvdm/wow32/wspool.h
new file mode 100644
index 000000000..0b43fbe35
--- /dev/null
+++ b/private/mvdm/wow32/wspool.h
@@ -0,0 +1,63 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSPOOL.H
+ * WOW32 printer spooler support routines
+ *
+ * These routines help a Win 3.0 task to use the print spooler apis. These
+ * apis were exposed by DDK in Win 3.1.
+ *
+ * History:
+ * Created 1-July-1993 by Chandan Chauhan (ChandanC)
+ *
+--*/
+
+ULONG FASTCALL WG32OpenJob (PVDMFRAME pFrame);
+ULONG FASTCALL WG32StartSpoolPage (PVDMFRAME pFrame);
+ULONG FASTCALL WG32EndSpoolPage (PVDMFRAME pFrame);
+ULONG FASTCALL WG32CloseJob (PVDMFRAME pFrame);
+ULONG FASTCALL WG32WriteSpool (PVDMFRAME pFrame);
+ULONG FASTCALL WG32DeleteJob (PVDMFRAME pFrame);
+
+typedef struct _DLLENTRYPOINTS {
+ char *name;
+ ULONG (*lpfn)();
+} DLLENTRYPOINTS;
+
+extern DLLENTRYPOINTS spoolerapis[];
+
+#define WOW_SPOOLERAPI_COUNT 15
+
+#define WOW_EXTDEVICEMODE 0
+#define WOW_DEVICEMODE 1
+#define WOW_DEVICECAPABILITIES 2
+#define WOW_OpenPrinterA 3
+#define WOW_StartDocPrinterA 4
+#define WOW_StartPagePrinter 5
+#define WOW_EndPagePrinter 6
+#define WOW_EndDocPrinter 7
+#define WOW_ClosePrinter 8
+#define WOW_WritePrinter 9
+#define WOW_DeletePrinter 10
+#define WOW_GetPrinterDriverDirectory 11
+#define WOW_AddPrinter 12
+#define WOW_AddPrinterDriver 13
+#define WOW_AddPortEx 14
+
+
+WORD GetPrn16(HANDLE h32);
+HANDLE Prn32(WORD h16);
+VOID FreePrn (WORD h16);
+
+BOOL GetDriverName (char *psz, char *szDriver);
+
+BOOL LoadLibraryAndGetProcAddresses(char *name, DLLENTRYPOINTS *p, int i);
+
+#ifdef i386
+HINSTANCE SafeLoadLibrary(char *name);
+#else
+#define SafeLoadLibrary(name) LoadLibrary(name)
+#endif
diff --git a/private/mvdm/wow32/wsraw.c b/private/mvdm/wow32/wsraw.c
new file mode 100644
index 000000000..d59f227fd
--- /dev/null
+++ b/private/mvdm/wow32/wsraw.c
@@ -0,0 +1,2290 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ Wsraw.h
+
+Abstract:
+
+ Support for raw winsock calls for WOW.
+
+Author:
+
+ David Treadwell (davidtr) 02-Oct-1992
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include "wsdynmc.h"
+
+LIST_ENTRY WWS32SocketHandleListHead;
+WORD WWS32SocketHandleCounter;
+BOOL WWS32SocketHandleCounterWrapped;
+
+//
+// The (PCHAR) casts in the following macro force the compiler to assume
+// only BYTE alignment.
+//
+
+#define SockCopyMemory(d,s,l) RtlCopyMemory( (PCHAR)(d), (PCHAR)(s), (l) )
+
+
+#define WSEXIT_IF_NOT_INTIALIZED() \
+ if(!WWS32IsThreadInitialized) { \
+ SetLastError(WSANOTINITIALISED); \
+ RETURN((ULONG)SOCKET_ERROR); \
+ }
+
+
+int SocketOption16To32(IN WORD SocketOption16);
+
+DWORD WSGetWinsock32(IN HAND16 h16,
+ OUT PULONG pul);
+
+BOOL WSThunkAddrBufAndLen(IN PSOCKADDR fastSockaddr,
+ IN VPSOCKADDR vpSockAddr16,
+ IN VPWORD vpwAddrLen16,
+ OUT PINT addressLength,
+ OUT PINT *pAddressLength,
+ OUT PSOCKADDR *realSockaddr);
+
+VOID WSUnThunkAddrBufAndLen(IN ULONG ret,
+ IN VPWORD vpwAddrLen16,
+ IN VPSOCKADDR vpSockAddr16,
+ IN INT addressLength,
+ IN PSOCKADDR fastSockaddr,
+ IN PSOCKADDR realSockaddr);
+
+BOOL WSThunkAddrBuf(IN INT addressLength,
+ IN VPSOCKADDR vpSockAddr16,
+ IN PSOCKADDR fastSockaddr,
+ OUT PSOCKADDR *realSockaddr);
+
+VOID WSUnThunkAddrBuf(IN PSOCKADDR fastSockaddr,
+ IN PSOCKADDR realSockaddr);
+
+BOOL WSThunkRecvBuffer(IN INT BufferLength,
+ IN VPBYTE vpBuf16,
+ OUT PBYTE *buffer);
+
+VOID WSUnthunkRecvBuffer(IN INT cBytes,
+ IN INT BufferLength,
+ IN VPBYTE vpBuf16,
+ IN PBYTE buffer);
+
+BOOL WSThunkSendBuffer(IN INT BufferLength,
+ IN VPBYTE vpBuf16,
+ OUT PBYTE *buffer);
+
+VOID WSUnthunkSendBuffer(IN PBYTE buffer);
+
+
+
+
+/*++
+
+ GENERIC FUNCTION PROTOTYPE:
+ ==========================
+
+ULONG FASTCALL WWS32<function name>(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register P<function name>16 parg16;
+
+ GETARGPTR(pFrame, sizeof(<function name>16), parg16);
+
+ <get any other required pointers into 16 bit space>
+
+ ALLOCVDMPTR
+ GETVDMPTR
+ GETMISCPTR
+ et cetera
+
+ <copy any complex structures from 16 bit -> 32 bit space>
+ <ALWAYS use the FETCHxxx macros>
+
+ ul = GET<return type>16(<function name>(parg16->f1,
+ :
+ :
+ parg16->f<n>);
+
+ <copy any complex structures from 32 -> 16 bit space>
+ <ALWAYS use the STORExxx macros>
+
+ <free any pointers to 16 bit space you previously got>
+
+ <flush any areas of 16 bit memory if they were written to>
+
+ FLUSHVDMPTR
+
+ FREEARGPTR( parg16 );
+ RETURN( ul );
+}
+
+NOTE:
+
+ The VDM frame is automatically set up, with all the function parameters
+ available via parg16->f<number>.
+
+ Handles must ALWAYS be mapped for 16 -> 32 -> 16 space via the mapping tables
+ laid out in WALIAS.C.
+
+ Any storage you allocate must be freed (eventually...).
+
+ Further to that - if a thunk which allocates memory fails in the 32 bit call
+ then it must free that memory.
+
+ Also, never update structures in 16 bit land if the 32 bit call fails.
+
+ Be aware that the GETxxxPTR macros return the CURRENT selector-to-flat_memory
+ mapping. Calls to some 32-bit functions may indirectly cause callbacks into
+ 16-bit code. These may cause 16-bit memory to move due to allocations
+ made in 16-bit land. If the 16-bit memory does move, the corresponding 32-bit
+ ptr in WOW32 needs to be refreshed to reflect the NEW selector-to-flat_memory
+ mapping.
+
+--*/
+
+
+ULONG FASTCALL WWS32accept(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PACCEPT16 parg16;
+ SOCKET s32;
+ SOCKET news32;
+ HSOCKET16 news16;
+ INT addressLength;
+ PINT pAddressLength;
+ SOCKADDR fastSockaddr;
+ PSOCKADDR realSockaddr;
+ VPWORD vpwAddrLen16;
+ VPSOCKADDR vpSockAddr16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PACCEPT16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ vpwAddrLen16 = (VPWORD)FETCHDWORD(parg16->AddressLength);
+ vpSockAddr16 = (VPSOCKADDR)FETCHDWORD(parg16->Address);
+
+ // Thunk the 16-bit Address name and length buffers
+ if(!WSThunkAddrBufAndLen(&fastSockaddr,
+ vpSockAddr16,
+ vpwAddrLen16,
+ &addressLength,
+ &pAddressLength,
+ &realSockaddr)) {
+ goto exit;
+ }
+
+ // call the 32-bit API
+ news32 = (*wsockapis[WOW_ACCEPT].lpfn)( s32, realSockaddr, pAddressLength);
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ // Un-Thunk the 16-bit Address name and length buffers
+ WSUnThunkAddrBufAndLen((ULONG)news32,
+ vpwAddrLen16,
+ vpSockAddr16,
+ addressLength,
+ &fastSockaddr,
+ realSockaddr);
+
+ //
+ // If the call succeeded, alias the 32-bit socket handle we just
+ // obtained into a 16-bit handle.
+ //
+
+ if ( news32 != INVALID_SOCKET ) {
+
+ news16 = GetWinsock16( news32, 0 );
+
+ if ( news16 == 0 ) {
+
+ (*wsockapis[WOW_CLOSESOCKET].lpfn)( news32 );
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+
+ goto exit;
+ }
+
+ ul = news16;
+
+ }
+
+exit:
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32accept
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32bind(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PBIND16 parg16;
+ SOCKET s32;
+ SOCKADDR fastSockaddr;
+ PSOCKADDR realSockaddr;
+ INT addressLength;
+ VPSOCKADDR vpSockAddr16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PBIND16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ vpSockAddr16 = (VPSOCKADDR)FETCHDWORD(parg16->Address);
+
+ addressLength = INT32(parg16->AddressLength);
+
+ // Thunk the 16-bit address buffer
+ if(!WSThunkAddrBuf(addressLength,
+ vpSockAddr16,
+ &fastSockaddr,
+ &realSockaddr)) {
+ goto exit;
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_BIND].lpfn)(s32,
+ realSockaddr,
+ addressLength));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ // Un-Thunk the 16-bit address buffer
+ WSUnThunkAddrBuf(&fastSockaddr, realSockaddr);
+
+exit:
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32bind
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32closesocket(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PCLOSESOCKET16 parg16;
+ SOCKET s32;
+ HSOCKET16 hSocket16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(CLOSESOCKET16), parg16);
+
+ hSocket16 = (HSOCKET16)FETCHWORD(parg16->hSocket);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(hSocket16, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_CLOSESOCKET].lpfn)( s32 ) );
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+
+exit:
+ //
+ // Free the space in the alias table.
+ //
+
+ FreeWinsock16( hSocket16 );
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32closesocket
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32connect(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PCONNECT16 parg16;
+ SOCKET s32;
+ SOCKADDR fastSockaddr;
+ PSOCKADDR realSockaddr;
+ INT addressLength;
+ VPSOCKADDR vpSockAddr16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PCONNECT16), parg16);
+
+ vpSockAddr16 = (VPSOCKADDR)FETCHDWORD(parg16->Address);
+ addressLength = INT32(parg16->AddressLength);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ // Thunk the 16-bit address buffer
+ if(!WSThunkAddrBuf(addressLength,
+ vpSockAddr16,
+ &fastSockaddr,
+ &realSockaddr)) {
+ goto exit;
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_CONNECT].lpfn)(s32,
+ realSockaddr,
+ addressLength));
+
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ // Un-Thunk the 16-bit address buffer
+ WSUnThunkAddrBuf(&fastSockaddr, realSockaddr);
+
+exit:
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32connect
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32getpeername(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PGETPEERNAME16 parg16;
+ SOCKET s32;
+ INT addressLength;
+ PINT pAddressLength;
+ SOCKADDR fastSockaddr;
+ PSOCKADDR realSockaddr;
+ VPWORD vpwAddrLen16;
+ VPSOCKADDR vpSockAddr16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PGETPEERNAME16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ vpSockAddr16 = (VPSOCKADDR)FETCHDWORD(parg16->Address);
+ vpwAddrLen16 = (VPWORD)FETCHDWORD(parg16->AddressLength);
+
+ // Thunk the 16-bit Address name and length buffers
+ if(!WSThunkAddrBufAndLen(&fastSockaddr,
+ vpSockAddr16,
+ vpwAddrLen16,
+ &addressLength,
+ &pAddressLength,
+ &realSockaddr)) {
+ goto exit;
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_GETPEERNAME].lpfn)(s32,
+ realSockaddr,
+ pAddressLength));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ // Un-Thunk the 16-bit Address name and length buffers
+ WSUnThunkAddrBufAndLen(ul,
+ vpwAddrLen16,
+ vpSockAddr16,
+ addressLength,
+ &fastSockaddr,
+ realSockaddr);
+
+exit:
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32getpeername
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32getsockname(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PGETSOCKNAME16 parg16;
+ SOCKET s32;
+ INT addressLength;
+ PINT pAddressLength;
+ SOCKADDR fastSockaddr;
+ PSOCKADDR realSockaddr;
+ VPWORD vpwAddrLen16;
+ VPSOCKADDR vpSockAddr16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PGETSOCKNAME16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ vpSockAddr16 = (VPSOCKADDR)FETCHDWORD(parg16->Address);
+ vpwAddrLen16 = (VPWORD)FETCHDWORD(parg16->AddressLength);
+
+ // Thunk the 16-bit Address name and length buffers
+ if(!WSThunkAddrBufAndLen(&fastSockaddr,
+ vpSockAddr16,
+ vpwAddrLen16,
+ &addressLength,
+ &pAddressLength,
+ &realSockaddr)) {
+ goto exit;
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_GETSOCKNAME].lpfn)( s32, realSockaddr, pAddressLength ) );
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ // Un-Thunk the 16-bit Address name and length buffers
+ WSUnThunkAddrBufAndLen(ul,
+ vpwAddrLen16,
+ vpSockAddr16,
+ addressLength,
+ &fastSockaddr,
+ realSockaddr);
+
+exit:
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32getsockname
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32getsockopt(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PGETSOCKOPT16 parg16;
+ SOCKET s32;
+ WORD UNALIGNED *optionLength16;
+ WORD actualOptionLength16;
+ PBYTE optionValue16;
+ DWORD optionLength32;
+ PBYTE optionValue32;
+ VPWORD vpwOptLen16;
+ VPBYTE vpwOptVal16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PGETSOCKOPT16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ vpwOptLen16 = (VPWORD)FETCHDWORD(parg16->OptionLength);
+ vpwOptVal16 = (VPBYTE)FETCHDWORD(parg16->OptionValue);
+ GETVDMPTR( vpwOptLen16, sizeof(WORD), optionLength16 );
+ GETVDMPTR( vpwOptVal16, FETCHWORD(*optionLength16), optionValue16 );
+
+ if ( FETCHWORD(*optionLength16) < sizeof(WORD) ) {
+ FREEVDMPTR( optionLength16 );
+ FREEVDMPTR( optionValue16 );
+ FREEARGPTR( parg16 );
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAEFAULT );
+ ul = (ULONG)GETWORD16(SOCKET_ERROR );
+ RETURN( ul );
+ } else if ( FETCHWORD(*optionLength16) < sizeof(DWORD) ) {
+ optionLength32 = sizeof(DWORD);
+ } else {
+ optionLength32 = FETCHWORD(*optionLength16);
+ }
+
+ optionValue32 = malloc_w(optionLength32);
+
+ if ( optionValue32 == NULL ) {
+ FREEVDMPTR( optionLength16 );
+ FREEVDMPTR( optionValue16 );
+ FREEARGPTR( parg16 );
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ ul = (ULONG)GETWORD16(SOCKET_ERROR );
+ RETURN( ul );
+ }
+
+ SockCopyMemory( optionValue32, optionValue16, optionLength32 );
+
+ ul = GETWORD16( (*wsockapis[WOW_GETSOCKOPT].lpfn)(
+ s32,
+ parg16->Level,
+ SocketOption16To32( parg16->OptionName ),
+ (char *)optionValue32,
+ (int *)&optionLength32));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+ FREEVDMPTR(optionLength16);
+ FREEVDMPTR(optionValue16);
+
+ if ( ul == NO_ERROR ) {
+ GETVDMPTR( vpwOptLen16, sizeof(WORD), optionLength16 );
+ GETVDMPTR( vpwOptVal16, FETCHWORD(*optionLength16), optionValue16 );
+
+ actualOptionLength16 = (WORD) min(optionLength32, FETCHWORD(*optionLength16));
+
+ RtlMoveMemory( optionValue16, optionValue32, actualOptionLength16 );
+
+ STOREWORD(*optionLength16, actualOptionLength16);
+
+ FLUSHVDMPTR( vpwOptLen16, sizeof(parg16->OptionLength), optionLength16 );
+ FLUSHVDMPTR( vpwOptVal16, actualOptionLength16, optionValue16 );
+ }
+
+ FREEVDMPTR( optionLength16 );
+ FREEVDMPTR( optionValue16 );
+
+exit:
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32getsockopt
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32htonl(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PHTONL16 parg16;
+
+ GETARGPTR(pFrame, sizeof(HTONL16), parg16);
+
+ ul = (*wsockapis[WOW_HTONL].lpfn)( parg16->HostLong );
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32htonl
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32htons(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PHTONS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(HTONS16), parg16);
+
+ ul = GETWORD16( (*wsockapis[WOW_HTONS].lpfn)( parg16->HostShort ) );
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32htons
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32inet_addr(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PINET_ADDR16 parg16;
+ PSZ addressString;
+ CHAR szAddrStr[32];
+ register PINET_ADDR16 realParg16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(INET_ADDR16), parg16);
+
+ realParg16 = parg16;
+
+ GETVDMPTR( parg16->cp, 1, addressString );
+ strcpy(szAddrStr, addressString);
+ FREEVDMPTR( addressString );
+
+ //
+ // If the thread is version 1.0 of Windows Sockets, play special
+ // stack games to return a struct in_addr.
+ //
+
+ if ( WWS32IsThreadVersion10 ) {
+
+ PDWORD inAddr16;
+ ULONG inAddr32;
+
+ ul = *((PWORD)parg16);
+ ul |= pFrame->wAppDS << 16;
+
+ parg16 = (PINET_ADDR16)( (PCHAR)parg16 + 2 );
+
+ inAddr32 = (*wsockapis[WOW_INET_ADDR].lpfn)( szAddrStr );
+
+ ASSERT( sizeof(IN_ADDR) == sizeof(DWORD) );
+ GETVDMPTR( ul, sizeof(DWORD), inAddr16 );
+ STOREDWORD( *inAddr16, inAddr32 );
+ FLUSHVDMPTR( ul, sizeof(DWORD), inAddr16 );
+ FREEVDMPTR( inAddr16 );
+
+ } else {
+ ul = (*wsockapis[WOW_INET_ADDR].lpfn)( szAddrStr );
+ }
+
+ FREEARGPTR( realParg16 );
+
+ RETURN( ul );
+
+} // WWS32inet_addr
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32inet_ntoa(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PINET_NTOA16 parg16;
+ PSZ ipAddress;
+ PSZ ipAddress16;
+ IN_ADDR in32;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(INET_NTOA16), parg16);
+
+ in32.s_addr = parg16->in;
+
+ ipAddress = (PSZ) (*wsockapis[WOW_INET_NTOA].lpfn)( in32 );
+
+ if ( ipAddress != NULL ) {
+ GETVDMPTR( WWS32vIpAddress, strlen( ipAddress )+1, ipAddress16 );
+ strcpy( ipAddress16, ipAddress );
+ FLUSHVDMPTR( WWS32vIpAddress, strlen( ipAddress )+1, ipAddress16 );
+ FREEVDMPTR( ipAddress16 );
+ ul = WWS32vIpAddress;
+ } else {
+ ul = 0;
+ }
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32inet_ntoa
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32ioctlsocket(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PIOCTLSOCKET16 parg16;
+ SOCKET s32;
+ PDWORD argument16;
+ DWORD argument32;
+ DWORD command;
+ VPDWORD vpdwArg16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(IOCTLSOCKET16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ vpdwArg16 = (VPDWORD)FETCHDWORD(parg16->Argument);
+ GETVDMPTR( vpdwArg16, sizeof(*argument16), argument16 );
+
+ //
+ // Translate the command value as necessary.
+ //
+
+ switch ( FETCHDWORD( parg16->Command ) & IOCPARM_MASK ) {
+
+ case 127:
+ command = FIONREAD;
+ break;
+
+ case 126:
+ command = FIONBIO;
+ break;
+
+ case 125:
+ command = FIOASYNC;
+ break;
+
+ case 0:
+ command = SIOCSHIWAT;
+ break;
+
+ case 1:
+ command = SIOCGHIWAT;
+ break;
+
+ case 2:
+ command = SIOCSLOWAT;
+ break;
+
+ case 3:
+ command = SIOCGLOWAT;
+ break;
+
+ case 7:
+ command = SIOCATMARK;
+ break;
+
+ default:
+ command = 0;
+ break;
+ }
+
+ argument32 = FETCHDWORD( *argument16 );
+
+ ul = GETWORD16( (*wsockapis[WOW_IOCTLSOCKET].lpfn)(s32,
+ command,
+ &argument32));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR( parg16 );
+
+ GETVDMPTR( vpdwArg16, sizeof(*argument16), argument16 );
+ STOREDWORD( *argument16, argument32 );
+ FLUSHVDMPTR( vpdwArg16, sizeof(*argument16), argument16 );
+ FREEVDMPTR( argument16 );
+
+exit:
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32ioctlsocket
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32listen(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLISTEN16 parg16;
+ SOCKET s32;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PLISTEN6), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+
+ ul = GETWORD16( (*wsockapis[WOW_LISTEN].lpfn)( s32, parg16->Backlog ) );
+
+exit:
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32listen
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32ntohl(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PNTOHL16 parg16;
+
+ GETARGPTR(pFrame, sizeof(NTOHL16), parg16);
+
+ ul = (*wsockapis[WOW_NTOHL].lpfn)( parg16->NetLong );
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32ntohl
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32ntohs(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PNTOHS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(NTOHS16), parg16);
+
+ ul = GETWORD16( (*wsockapis[WOW_NTOHS].lpfn)( parg16->NetShort ) );
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32ntohs
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32recv(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PRECV16 parg16;
+ SOCKET s32;
+ PBYTE buffer;
+ INT BufferLength;
+ VPBYTE vpBuf16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PRECV16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ BufferLength = INT32(parg16->BufferLength);
+ vpBuf16 = (VPBYTE)FETCHDWORD(parg16->Buffer);
+
+ // Thunk the 16-bit recv buffer
+ if(!WSThunkRecvBuffer(BufferLength, vpBuf16, &buffer)) {
+ goto exit;
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_RECV].lpfn)(s32,
+ buffer,
+ BufferLength,
+ parg16->Flags));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ // Un-Thunk the 16-bit recv buffer
+ WSUnthunkRecvBuffer((INT)ul, BufferLength, vpBuf16, buffer);
+
+exit:
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32recv
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32recvfrom(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PRECVFROM16 parg16;
+ SOCKET s32;
+ INT addressLength;
+ PINT pAddressLength;
+ SOCKADDR fastSockaddr;
+ PSOCKADDR realSockaddr;
+ PBYTE buffer;
+ INT BufferLength;
+ VPBYTE vpBuf16;
+ VPWORD vpwAddrLen16;
+ VPSOCKADDR vpSockAddr16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PRECVFROM16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ vpwAddrLen16 = (VPWORD)FETCHDWORD(parg16->AddressLength);
+ vpSockAddr16 = (VPSOCKADDR)FETCHDWORD(parg16->Address);
+ BufferLength = INT32(parg16->BufferLength);
+ vpBuf16 = (VPBYTE)parg16->Buffer;
+
+ // Thunk the 16-bit Address name and length buffers
+ if(!WSThunkAddrBufAndLen(&fastSockaddr,
+ vpSockAddr16,
+ vpwAddrLen16,
+ &addressLength,
+ &pAddressLength,
+ &realSockaddr)) {
+ goto exit;
+ }
+
+ // Thunk the 16-bit recv buffer
+ if(!WSThunkRecvBuffer(BufferLength, vpBuf16, &buffer)) {
+ goto exit;
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_RECVFROM].lpfn)(s32,
+ buffer,
+ BufferLength,
+ parg16->Flags,
+ realSockaddr,
+ pAddressLength));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ // Un-Thunk the 16-bit Address name and length buffers
+ WSUnThunkAddrBufAndLen(ul,
+ vpwAddrLen16,
+ vpSockAddr16,
+ addressLength,
+ &fastSockaddr,
+ realSockaddr);
+
+ // Un-Thunk the 16-bit recv buffer
+ WSUnthunkRecvBuffer((INT)ul, BufferLength, vpBuf16, buffer);
+
+
+exit:
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32recvfrom
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32select(PVDMFRAME pFrame)
+{
+ ULONG ul = (ULONG)GETWORD16( SOCKET_ERROR );
+ register PSELECT16 parg16;
+ PFD_SET readfds32 = NULL;
+ PFD_SET writefds32 = NULL;
+ PFD_SET exceptfds32 = NULL;
+ PFD_SET16 readfds16;
+ PFD_SET16 writefds16;
+ PFD_SET16 exceptfds16;
+ struct timeval timeout32;
+ struct timeval *ptimeout32;
+ PTIMEVAL16 timeout16;
+ INT err;
+ VPFD_SET16 vpreadfds16;
+ VPFD_SET16 vpwritefds16;
+ VPFD_SET16 vpexceptfds16;
+ VPTIMEVAL16 vptimeout16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR( pFrame, sizeof(PSELECT16), parg16 );
+
+ //
+ // Get 16-bit pointers.
+ //
+ // !!! This sizeof(FD_SET16) here and below is wrong if the app is
+ // using more than FDSETSIZE handles!!!
+
+ vpreadfds16 = parg16->Readfds;
+ vpwritefds16 = parg16->Writefds;
+ vpexceptfds16 = parg16->Exceptfds;
+ vptimeout16 = parg16->Timeout;
+ GETOPTPTR(vpreadfds16, sizeof(FD_SET16), readfds16);
+ GETOPTPTR(vpwritefds16, sizeof(FD_SET16), writefds16);
+ GETOPTPTR(vpexceptfds16, sizeof(FD_SET16), exceptfds16);
+ GETOPTPTR(vptimeout16, sizeof(TIMEVAL16), timeout16);
+
+ //
+ // Translate readfds.
+ //
+
+ if ( readfds16 != NULL ) {
+
+ readfds32 = AllocateFdSet32( readfds16 );
+ if ( readfds32 == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ err = ConvertFdSet16To32( readfds16, readfds32 );
+ if ( err != 0 ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( err );
+ goto exit;
+ }
+
+ }
+
+ //
+ // Translate writefds.
+ //
+
+ if ( writefds16 != NULL ) {
+
+ writefds32 = AllocateFdSet32( writefds16 );
+ if ( writefds32 == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ err = ConvertFdSet16To32( writefds16, writefds32 );
+ if ( err != 0 ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( err );
+ goto exit;
+ }
+
+ }
+
+ //
+ // Translate exceptfds.
+ //
+
+ if ( exceptfds16 != NULL ) {
+
+ exceptfds32 = AllocateFdSet32( exceptfds16 );
+ if ( exceptfds32 == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ goto exit;
+ }
+
+ err = ConvertFdSet16To32( exceptfds16, exceptfds32 );
+ if ( err != 0 ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( err );
+ goto exit;
+ }
+
+ }
+
+ //
+ // Translate the timeout.
+ //
+
+ if ( timeout16 == NULL ) {
+ ptimeout32 = NULL;
+ } else {
+ timeout32.tv_sec = FETCHDWORD( timeout16->tv_sec );
+ timeout32.tv_usec = FETCHDWORD( timeout16->tv_usec );
+ ptimeout32 = &timeout32;
+ }
+
+ //
+ // Call the 32-bit select function.
+ //
+
+ ul = GETWORD16( (*wsockapis[WOW_SELECT].lpfn)(0,
+ readfds32,
+ writefds32,
+ exceptfds32,
+ ptimeout32));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+ FREEOPTPTR(readfds16);
+ FREEOPTPTR(writefds16);
+ FREEOPTPTR(exceptfds16);
+ FREEOPTPTR(timeout16);
+
+ //
+ // Copy 32-bit readfds back to the 16-bit readfds.
+ //
+ if ( readfds32 != NULL ) {
+ GETOPTPTR(vpreadfds16, sizeof(FD_SET16), readfds16);
+ ConvertFdSet32To16( readfds32, readfds16 );
+ FLUSHVDMPTR(vpreadfds16, sizeof(FD_SET16), readfds16);
+ }
+
+ //
+ // Copy 32-bit writefds back to the 16-bit writefds.
+ //
+
+ if ( writefds32 != NULL ) {
+ GETOPTPTR(vpwritefds16, sizeof(FD_SET16), writefds16);
+ ConvertFdSet32To16( writefds32, writefds16 );
+ FLUSHVDMPTR(vpwritefds16, sizeof(FD_SET16), writefds16);
+ }
+
+ //
+ // Copy 32-bit exceptfds back to the 16-bit exceptfds.
+ //
+
+ if ( exceptfds32 != NULL ) {
+ GETOPTPTR(vpexceptfds16, sizeof(FD_SET16), exceptfds16);
+ ConvertFdSet32To16( exceptfds32, exceptfds16 );
+ FLUSHVDMPTR(vpexceptfds16, sizeof(FD_SET16), exceptfds16);
+ }
+
+exit:
+
+ FREEOPTPTR( readfds16 );
+ FREEOPTPTR( writefds16 );
+ FREEOPTPTR( exceptfds16 );
+
+ if ( readfds32 != NULL ) {
+ free_w((PVOID)readfds32);
+ }
+ if ( writefds32 != NULL ) {
+ free_w((PVOID)writefds32);
+ }
+ if ( exceptfds32 != NULL ) {
+ free_w((PVOID)exceptfds32);
+ }
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32select
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32send(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PSEND16 parg16;
+ SOCKET s32;
+ INT BufferLength;
+ PBYTE buffer;
+ VPBYTE vpBuf16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PSEND16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ BufferLength = INT32(parg16->BufferLength);
+ vpBuf16 = FETCHDWORD(parg16->Buffer);
+
+ // Thunk the 16-bit send buffer
+ if(!WSThunkSendBuffer(BufferLength, vpBuf16, &buffer)) {
+ goto exit;
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_SEND].lpfn)(s32,
+ buffer,
+ BufferLength,
+ parg16->Flags));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ // Un-Thunk the 16-bit send buffer
+ WSUnthunkSendBuffer(buffer);
+
+exit:
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32send
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32sendto(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PSENDTO16 parg16;
+ SOCKET s32;
+ PBYTE buffer;
+ SOCKADDR fastSockaddr;
+ PSOCKADDR realSockaddr;
+ INT addressLength;
+ INT BufferLength;
+ VPSOCKADDR vpSockAddr16;
+ VPBYTE vpBuf16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PSENDTO16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ addressLength = INT32(parg16->AddressLength);
+ vpSockAddr16 = (VPSOCKADDR)FETCHDWORD(parg16->Address);
+ BufferLength = INT32(parg16->BufferLength);
+ vpBuf16 = (VPBYTE)FETCHDWORD(parg16->Buffer);
+
+ // Thunk the 16-bit Address buffer
+ if(!WSThunkAddrBuf(addressLength,
+ vpSockAddr16,
+ &fastSockaddr,
+ &realSockaddr)) {
+ goto exit;
+ }
+
+ // Thunk the 16-bit send buffer
+ if(!WSThunkSendBuffer(BufferLength, vpBuf16, &buffer)) {
+ goto exit;
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_SENDTO].lpfn)(s32,
+ buffer,
+ BufferLength,
+ parg16->Flags,
+ realSockaddr,
+ addressLength));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ // Un-Thunk the 16-bit address buffer
+ WSUnThunkAddrBuf(&fastSockaddr, realSockaddr);
+
+ // Un-Thunk the 16-bit send buffer
+ WSUnthunkSendBuffer(buffer);
+
+exit:
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32sendto
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32setsockopt(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PSETSOCKOPT16 parg16;
+ SOCKET s32;
+ PBYTE optionValue16;
+ PBYTE optionValue32;
+ DWORD optionLength32;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PSETSOCKOPT16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ GETVDMPTR( parg16->OptionValue, parg16->OptionLength, optionValue16 );
+
+ if ( parg16->OptionLength < sizeof(DWORD) ) {
+ optionLength32 = sizeof(DWORD);
+ } else {
+ optionLength32 = parg16->OptionLength;
+ }
+
+ optionValue32 = malloc_w(optionLength32);
+ if ( optionValue32 == NULL ) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ ul = (ULONG)GETWORD16( SOCKET_ERROR );
+ FREEVDMPTR( optionValue16 );
+ FREEARGPTR( parg16 );
+ RETURN( ul );
+ }
+
+ RtlZeroMemory( optionValue32, optionLength32 );
+ RtlMoveMemory( optionValue32, optionValue16, parg16->OptionLength );
+
+ ul = GETWORD16( (*wsockapis[WOW_SETSOCKOPT].lpfn)(
+ s32,
+ parg16->Level,
+ SocketOption16To32( parg16->OptionName ),
+ optionValue32,
+ optionLength32));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+ FREEVDMPTR( optionValue16 );
+
+ free_w(optionValue32);
+
+exit:
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32setsockopt
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32shutdown(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PSHUTDOWN16 parg16;
+ SOCKET s32;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(PBIND16), parg16);
+
+ //
+ // Find the 32-bit socket handle.
+ //
+
+ if((s32 = WSGetWinsock32(parg16->hSocket, &ul)) == INVALID_SOCKET) {
+ goto exit;
+ }
+
+ ul = GETWORD16( (*wsockapis[WOW_SHUTDOWN].lpfn)( s32, parg16->How ) );
+
+exit:
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32shutdown
+
+
+
+
+
+
+
+
+
+
+ULONG FASTCALL WWS32socket(PVDMFRAME pFrame)
+{
+ ULONG ul = GETWORD16(INVALID_SOCKET);
+ register PSOCKET16 parg16;
+ SOCKET s32;
+ HSOCKET16 s16;
+
+ WSEXIT_IF_NOT_INTIALIZED();
+
+ GETARGPTR(pFrame, sizeof(SOCKET16), parg16);
+
+ s32 = (*wsockapis[WOW_SOCKET].lpfn)(INT32(parg16->AddressFamily),
+ INT32(parg16->Type),
+ INT32(parg16->Protocol));
+
+ // Note: 16-bit callbacks resulting from above function
+ // call may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ //
+ // If the call succeeded, alias the 32-bit socket handle we just
+ // obtained into a 16-bit handle.
+ //
+
+ if ( s32 != INVALID_SOCKET ) {
+
+ s16 = GetWinsock16( s32, 0 );
+
+ ul = s16;
+
+ if ( s16 == 0 ) {
+ (*wsockapis[WOW_CLOSESOCKET].lpfn)( s32 );
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOBUFS );
+ ul = GETWORD16( INVALID_SOCKET );
+ }
+
+ } else {
+
+ ul = GETWORD16( INVALID_SOCKET );
+ }
+
+ FREEARGPTR( parg16 );
+
+ RETURN( ul );
+
+} // WWS32socket
+
+
+
+
+
+
+
+
+
+
+//
+// Routines for converting between 16- and 32-bit FD_SET structures.
+//
+
+PFD_SET AllocateFdSet32(IN PFD_SET16 FdSet16)
+{
+ int bytes = 4 + (FETCHWORD(FdSet16->fd_count) * sizeof(SOCKET));
+
+ return (PFD_SET)( malloc_w(bytes) );
+
+} // AlloacteFdSet32
+
+
+
+
+
+
+
+
+
+INT ConvertFdSet16To32(IN PFD_SET16 FdSet16,
+ IN PFD_SET FdSet32)
+{
+ int i;
+
+ FdSet32->fd_count = UINT32( FdSet16->fd_count );
+
+ for ( i = 0; i < (int)FdSet32->fd_count; i++ ) {
+
+ FdSet32->fd_array[i] = GetWinsock32( FdSet16->fd_array[i] );
+ if ( FdSet32->fd_array[i] == INVALID_SOCKET ) {
+ return WSAENOTSOCK;
+ }
+ }
+
+ return 0;
+
+} // ConvertFdSet16To32
+
+
+
+
+
+
+
+
+VOID ConvertFdSet32To16(IN PFD_SET FdSet32,
+ IN PFD_SET16 FdSet16)
+{
+ int i;
+
+ STOREWORD( FdSet16->fd_count, GETWORD16( FdSet32->fd_count ) );
+
+ for ( i = 0; i < FdSet16->fd_count; i++ ) {
+
+ HSOCKET16 s16;
+
+ s16 = GetWinsock16( FdSet32->fd_array[i], 0 );
+
+ STOREWORD( FdSet16->fd_array[i], s16 );
+ }
+
+} // ConvertFdSet32To16
+
+
+
+
+
+
+
+
+
+
+//
+// Routines for aliasing 32-bit socket handles to 16-bit handles.
+//
+
+PWINSOCK_SOCKET_INFO FindSocketInfo16(IN SOCKET h32,
+ IN HAND16 h16)
+{
+ PLIST_ENTRY listEntry;
+ PWINSOCK_SOCKET_INFO socketInfo;
+
+ //
+ // It is the responsibility of the caller of this routine to enter
+ // the critical section that protects the global socket list.
+ //
+
+ for ( listEntry = WWS32SocketHandleListHead.Flink;
+ listEntry != &WWS32SocketHandleListHead;
+ listEntry = listEntry->Flink ) {
+
+ socketInfo = CONTAINING_RECORD(listEntry,
+ WINSOCK_SOCKET_INFO,
+ GlobalSocketListEntry);
+
+ if ( socketInfo->SocketHandle32 == h32 ||
+ socketInfo->SocketHandle16 == h16 ) {
+ return socketInfo;
+ }
+ }
+
+ return NULL;
+
+} // FindSocketInfo16
+
+
+
+
+
+
+
+
+HAND16 AllocateUnique16BitHandle(VOID)
+{
+
+ PLIST_ENTRY listEntry;
+ PWINSOCK_SOCKET_INFO socketInfo;
+ HAND16 h16;
+ WORD i;
+
+ //
+ // This function assumes it is called with the WWS32CriticalSection
+ // lock held!
+ //
+
+ //
+ // If the socket list is empty, then we can reset our socket handle
+ // counter because we know there are no active sockets. We'll only
+ // do this if the handle counter is above some value (just pulled
+ // out of the air) so that handles are not reused too quickly.
+ // (Frequent handle reuse can confuse poorly written 16-bit apps.)
+ //
+
+ if( ( WWS32SocketHandleCounter > 255 ) &&
+ IsListEmpty( &WWS32SocketHandleListHead ) ) {
+
+ WWS32SocketHandleCounter = 1;
+ WWS32SocketHandleCounterWrapped = FALSE;
+
+ }
+
+ //
+ // If the socket handle counter has not wrapped around,
+ // then we can quickly return a unique handle.
+ //
+
+ if( !WWS32SocketHandleCounterWrapped ) {
+
+ h16 = (HAND16)WWS32SocketHandleCounter++;
+
+ if( WWS32SocketHandleCounter == 0xFFFF ) {
+
+ WWS32SocketHandleCounter = 1;
+ WWS32SocketHandleCounterWrapped = TRUE;
+
+ }
+
+ ASSERT( h16 != 0 );
+ return h16;
+
+ }
+
+ //
+ // There are active sockets, and the socket handle counter has
+ // wrapped, so we'll need to perform a painful search for a unique
+ // handle. We'll put a cap on the maximum number of times through
+ // this search loop so that, if all handles from 1 to 0xFFFE are
+ // in use, we won't search forever for something we'll never find.
+ //
+
+ for( i = 1 ; i <= 0xFFFE ; i++ ) {
+
+ h16 = (HAND16)WWS32SocketHandleCounter++;
+
+ if( WWS32SocketHandleCounter == 0xFFFF ) {
+
+ WWS32SocketHandleCounter = 1;
+
+ }
+
+ for ( listEntry = WWS32SocketHandleListHead.Flink;
+ listEntry != &WWS32SocketHandleListHead;
+ listEntry = listEntry->Flink ) {
+
+ socketInfo = CONTAINING_RECORD(
+ listEntry,
+ WINSOCK_SOCKET_INFO,
+ GlobalSocketListEntry
+ );
+
+ if( socketInfo->SocketHandle16 == h16 ) {
+
+ break;
+
+ }
+
+ }
+
+ //
+ // If listEntry == &WWS32SocketHandleListHead, then we have
+ // scanned the entire list and found no match. This is good,
+ // and we'll just return the current handle. Otherwise, there
+ // was a collision, so we'll get another potential handle and
+ // rescan the list.
+ //
+
+ if( listEntry == &WWS32SocketHandleListHead ) {
+
+ ASSERT( h16 != 0 );
+ return h16;
+
+ }
+
+ }
+
+ //
+ // If we made it this far, then there were no unique handles
+ // available. Bad news.
+ //
+
+ return 0;
+
+} // AllocateUnique16BitHandle
+
+
+
+
+
+
+
+
+
+HAND16 GetWinsock16(IN INT h32,
+ IN INT iClass)
+{
+ PWINSOCK_SOCKET_INFO socketInfo;
+ HAND16 h16;
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ //
+ // If the handle is already in the list, use it.
+ //
+
+ socketInfo = FindSocketInfo16( h32, 0 );
+
+ if ( socketInfo != NULL ) {
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+ return socketInfo->SocketHandle16;
+ }
+
+ //
+ // If this thread has not yet been initialized, then we cannot
+ // create the new socket data. This should only happen if a 16-bit
+ // app closes a socket while an async connect is outstanding.
+ //
+
+ if( !WWS32IsThreadInitialized ) {
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+ return 0;
+ }
+
+ //
+ // The handle is not in use. Create a new entry in the list.
+ //
+
+ h16 = AllocateUnique16BitHandle();
+ if( h16 == 0 ) {
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+ return 0;
+ }
+
+ socketInfo = malloc_w(sizeof(*socketInfo));
+ if ( socketInfo == NULL ) {
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+ return 0;
+ }
+
+ socketInfo->SocketHandle16 = h16;
+ socketInfo->SocketHandle32 = h32;
+ socketInfo->ThreadSerialNumber = WWS32ThreadSerialNumber;
+
+ InsertTailList( &WWS32SocketHandleListHead, &socketInfo->GlobalSocketListEntry );
+
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+ ASSERT( h16 != 0 );
+ return h16;
+
+} // GetWinsock16
+
+
+
+
+
+
+
+
+VOID FreeWinsock16(IN HAND16 h16)
+{
+ PWINSOCK_SOCKET_INFO socketInfo;
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ socketInfo = FindSocketInfo16( INVALID_SOCKET, h16 );
+
+ if ( socketInfo == NULL ) {
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+ return;
+ }
+
+ RemoveEntryList( &socketInfo->GlobalSocketListEntry );
+ free_w((PVOID)socketInfo);
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+ return;
+
+} // FreeWinsock16
+
+
+
+
+
+
+
+
+DWORD GetWinsock32(IN HAND16 h16)
+{
+ PWINSOCK_SOCKET_INFO socketInfo;
+ SOCKET socket32;
+
+ RtlEnterCriticalSection( &WWS32CriticalSection );
+
+ socketInfo = FindSocketInfo16( INVALID_SOCKET, h16 );
+
+ if ( socketInfo == NULL ) {
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+ return INVALID_SOCKET;
+ }
+
+ //
+ // Store the socket handle in an aytumatic before leaving the critical
+ // section in case the socketInfo structure is about to be freed.
+ //
+
+ socket32 = socketInfo->SocketHandle32;
+
+ RtlLeaveCriticalSection( &WWS32CriticalSection );
+
+ return socket32;
+
+} // GetWinsock32
+
+
+
+
+
+
+
+
+int SocketOption16To32(IN WORD SocketOption16)
+{
+
+ if ( SocketOption16 == 0xFF7F ) {
+ return SO_DONTLINGER;
+ }
+
+ return (int)SocketOption16;
+
+} // SocketOption16To32
+
+
+
+
+
+
+
+
+
+DWORD WSGetWinsock32 (IN HAND16 h16,
+ OUT PULONG pul)
+{
+
+ DWORD s32;
+
+
+ s32 = GetWinsock32(h16);
+
+ if(s32 == INVALID_SOCKET) {
+
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)(WSAENOTSOCK);
+ *pul = (ULONG)GETWORD16(SOCKET_ERROR);
+
+ }
+
+ return(s32);
+
+}
+
+
+
+
+
+
+
+
+BOOL WSThunkAddrBufAndLen(IN PSOCKADDR fastSockaddr,
+ IN VPSOCKADDR vpSockAddr16,
+ IN VPWORD vpwAddrLen16,
+ OUT PINT addressLength,
+ OUT PINT *pAddressLength,
+ OUT PSOCKADDR *realSockaddr)
+{
+ PWORD addressLength16;
+ PSOCKADDR Sockaddr;
+
+ GETVDMPTR(vpwAddrLen16, sizeof(*addressLength16), addressLength16);
+ GETVDMPTR(vpSockAddr16, *addressLength16, Sockaddr);
+
+ if(Sockaddr) {
+ *realSockaddr = fastSockaddr;
+ }
+ else {
+ *realSockaddr = NULL;
+ }
+
+ if (addressLength16 == NULL) {
+
+ *pAddressLength = NULL;
+
+ } else {
+
+ *addressLength = INT32(*addressLength16);
+ *pAddressLength = addressLength;
+
+ if(*addressLength > sizeof(SOCKADDR)) {
+
+ *realSockaddr = malloc_w(*addressLength);
+
+ if(*realSockaddr == NULL) {
+
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)(WSAENOBUFS);
+ return(FALSE);
+
+ }
+ }
+ }
+
+ FREEVDMPTR(Sockaddr);
+ FREEVDMPTR(addressLength16);
+ return(TRUE);
+}
+
+
+
+
+
+
+
+
+
+VOID WSUnThunkAddrBufAndLen(IN ULONG ret,
+ IN VPWORD vpwAddrLen16,
+ IN VPSOCKADDR vpSockAddr16,
+ IN INT addressLength,
+ IN PSOCKADDR fastSockaddr,
+ IN PSOCKADDR realSockaddr)
+{
+ PWORD addressLength16;
+ PSOCKADDR Sockaddr;
+
+ GETVDMPTR(vpwAddrLen16, sizeof(*addressLength16), addressLength16);
+ if((ret != SOCKET_ERROR) && addressLength16) {
+ STOREWORD(*addressLength16, addressLength);
+ FLUSHVDMPTR(vpwAddrLen16, sizeof(WORD), addressLength16);
+
+ GETVDMPTR(vpSockAddr16, addressLength, Sockaddr);
+ if(Sockaddr) {
+
+ // don't copy back to the 16-bit address buffer if it's too small
+ if(addressLength <= *addressLength16) {
+ SockCopyMemory(Sockaddr, realSockaddr, addressLength);
+ FLUSHVDMPTR(vpSockAddr16, addressLength, Sockaddr);
+ }
+ }
+ }
+
+ if( (realSockaddr) && (realSockaddr != fastSockaddr) ) {
+
+ free_w(realSockaddr);
+
+ }
+
+ FREEVDMPTR(addressLength16);
+ FREEVDMPTR(Sockaddr);
+}
+
+
+
+
+
+
+
+
+BOOL WSThunkAddrBuf(IN INT addressLength,
+ IN VPSOCKADDR vpSockAddr16,
+ IN PSOCKADDR fastSockaddr,
+ OUT PSOCKADDR *realSockaddr)
+{
+ PSOCKADDR Sockaddr;
+
+ GETVDMPTR(vpSockAddr16, addressLength, Sockaddr);
+
+ if(Sockaddr) {
+
+
+ if(addressLength <= sizeof(SOCKADDR)) {
+ *realSockaddr = fastSockaddr;
+ }
+ else {
+
+ *realSockaddr = malloc_w(addressLength);
+
+ if(*realSockaddr == NULL) {
+
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)(WSAENOBUFS);
+ FREEVDMPTR(Sockaddr);
+ return(FALSE);
+
+ }
+ }
+
+ SockCopyMemory(*realSockaddr, Sockaddr, addressLength);
+ }
+ else {
+ *realSockaddr = NULL;
+ }
+
+ FREEVDMPTR(Sockaddr);
+ return(TRUE);
+
+}
+
+
+
+
+
+
+
+
+VOID WSUnThunkAddrBuf(IN PSOCKADDR fastSockaddr,
+ IN PSOCKADDR realSockaddr)
+{
+ if( (realSockaddr) && (realSockaddr != fastSockaddr) ) {
+
+ free_w(realSockaddr);
+
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+BOOL WSThunkRecvBuffer(IN INT BufferLength,
+ IN VPBYTE vpBuf16,
+ OUT PBYTE *buffer)
+{
+ PBYTE lpBuf16;
+
+ GETVDMPTR(vpBuf16, BufferLength, lpBuf16);
+
+ if(lpBuf16) {
+
+ *buffer = malloc_w(BufferLength);
+
+ if(*buffer == NULL) {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)(WSAENOBUFS);
+ return(FALSE);
+ }
+ }
+ else {
+ *buffer = NULL;
+ }
+
+ return(TRUE);
+
+}
+
+
+
+
+
+
+
+
+VOID WSUnthunkRecvBuffer(IN INT cBytes,
+ IN INT BufferLength,
+ IN VPBYTE vpBuf16,
+ IN PBYTE buffer)
+{
+ PBYTE lpBuf16;
+
+ GETVDMPTR(vpBuf16, BufferLength, lpBuf16);
+
+ if(buffer) {
+
+ if( (cBytes > 0) && lpBuf16 ) {
+ SockCopyMemory(lpBuf16, buffer, cBytes);
+ FLUSHVDMPTR(vpBuf16, cBytes, lpBuf16);
+ }
+
+ free_w(buffer);
+
+ }
+
+ FREEVDMPTR(lpBuf16);
+
+}
+
+
+
+
+
+
+BOOL WSThunkSendBuffer(IN INT BufferLength,
+ IN VPBYTE vpBuf16,
+ OUT PBYTE *buffer)
+{
+ PBYTE lpBuf16;
+
+ GETVDMPTR(vpBuf16, BufferLength, lpBuf16);
+
+ if(lpBuf16) {
+
+ *buffer = malloc_w(BufferLength);
+
+ if(*buffer) {
+ SockCopyMemory(*buffer, lpBuf16, BufferLength);
+ }
+ else {
+ (*wsockapis[WOW_WSASETLASTERROR].lpfn)(WSAENOBUFS);
+ return(FALSE);
+ }
+
+ FREEVDMPTR(lpBuf16);
+ }
+ else {
+ *buffer = NULL;
+ }
+
+ return(TRUE);
+
+}
+
+
+
+
+
+
+VOID WSUnthunkSendBuffer(IN PBYTE buffer)
+{
+
+ if(buffer) {
+ free_w(buffer);
+ }
+}
diff --git a/private/mvdm/wow32/wstbl.h b/private/mvdm/wow32/wstbl.h
new file mode 100644
index 000000000..937cd0eea
--- /dev/null
+++ b/private/mvdm/wow32/wstbl.h
@@ -0,0 +1,23 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSTBL.H
+ * WOW32 16-bit Sound API tables
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* Sound dispatch table
+ */
+extern W32 aw32Sound[];
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iSoundMax;
+#endif
diff --git a/private/mvdm/wow32/wstbl2.h b/private/mvdm/wow32/wstbl2.h
new file mode 100644
index 000000000..7cbde9a05
--- /dev/null
+++ b/private/mvdm/wow32/wstbl2.h
@@ -0,0 +1,34 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSTBL2.h
+ * WOW32 16-bit Sound API tables
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "OPENSOUND", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "CLOSESOUND", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETVOICEQUEUESIZE", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETVOICENOTE", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETVOICEACCENT", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETVOICEENVELOPE", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETSOUNDNOISE", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETVOICESOUND", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "STARTSOUND", MOD_SOUND, 0)},
+
+ /*** 0010 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "STOPSOUND", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "WAITSOUNDSTATE", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SYNCALLVOICES", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "COUNTVOICENOTES", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETTHRESHOLDEVENT", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETTHRESHOLDSTATUS",MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETVOICETHRESHOLD", MOD_SOUND, 0)},
+ {W32FUN(WS32DoBeep, "DOBEEP", MOD_SOUND, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "MYOPENSOUND", MOD_SOUND, 0)},
diff --git a/private/mvdm/wow32/wstruc.c b/private/mvdm/wow32/wstruc.c
new file mode 100644
index 000000000..fb09a12d2
--- /dev/null
+++ b/private/mvdm/wow32/wstruc.c
@@ -0,0 +1,1681 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSTRUC.C
+ * WOW32 16-bit structure conversion support
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * Wrote DDE data conversion routines, etc Chandan CHauhan (ChandanC)
+ *
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+#include "wowshlp.h"
+
+MODNAME(wstruc.c);
+
+
+/* Structure copying functions
+ *
+ * For input structures, there are GETxxxx16 macros; for output structures
+ * there are PUTxxxx16 macros. Most or all of these macros will simply call
+ * the corresponding function below. Nothing magical here....
+ */
+
+VOID getstr16(VPSZ vpszSrc, LPSZ lpszDst, INT cb)
+{
+ PSZ pszSrc;
+
+ if (cb == 0)
+ return;
+
+ if (cb != -1)
+ GETVDMPTR(vpszSrc, cb, pszSrc);
+ else {
+ GETPSZPTR(vpszSrc, pszSrc);
+ cb = strlen(pszSrc)+1;
+ }
+
+ RtlCopyMemory(lpszDst, pszSrc, cb);
+
+ FREEVDMPTR(pszSrc);
+
+ RETURN(NOTHING);
+}
+
+
+VOID putstr16(VPSZ vpszDst, LPCSTR lpszSrc, INT cb)
+{
+ PSZ pszDst;
+
+ if (cb == 0)
+ return;
+
+ if (cb == -1)
+ cb = strlen(lpszSrc)+1;
+
+ GETVDMPTR(vpszDst, cb, pszDst);
+
+ RtlCopyMemory(pszDst, lpszSrc, cb);
+
+ FLUSHVDMPTR(vpszDst, cb, pszDst);
+ FREEVDMPTR(pszDst);
+
+ RETURN(NOTHING);
+}
+
+
+LPRECT getrect16(VPRECT16 vpRect, LPRECT lpRect)
+{
+ register PRECT16 pRect16;
+
+ // Some APIs (eg, InvalidateRect) have OPTIONAL input pointers -JTP
+ if (vpRect) {
+
+ GETVDMPTR(vpRect, sizeof(RECT16), pRect16);
+
+ lpRect->left = FETCHSHORT(pRect16->left);
+ lpRect->top = FETCHSHORT(pRect16->top);
+ lpRect->right = FETCHSHORT(pRect16->right);
+ lpRect->bottom = FETCHSHORT(pRect16->bottom);
+
+ FREEVDMPTR(pRect16);
+ return lpRect;
+ }
+ RETURN(NULL);
+}
+
+
+VOID putrect16(VPRECT16 vpRect, LPRECT lpRect)
+{
+ register PRECT16 pRect16;
+
+ // Some APIs (ScrollDC may be the only one) have OPTIONAL output pointers
+ if (vpRect) {
+
+ GETVDMPTR(vpRect, sizeof(RECT16), pRect16);
+
+ STORESHORT(pRect16->left, (SHORT)lpRect->left);
+ STORESHORT(pRect16->top, (SHORT)lpRect->top);
+ STORESHORT(pRect16->right, (SHORT)lpRect->right);
+ STORESHORT(pRect16->bottom, (SHORT)lpRect->bottom);
+
+ FLUSHVDMPTR(vpRect, sizeof(RECT16), pRect16);
+ FREEVDMPTR(pRect16);
+ }
+}
+
+
+VOID getpoint16(VPPOINT16 vpPoint, INT c, LPPOINT lpPoint)
+{
+ register PPOINT16 pPoint16;
+
+ // The assumption here is that no APIs have OPTIONAL POINT pointers
+ // (regardless of whether they're input or output) -JTP
+ WOW32ASSERT(vpPoint);
+
+ if (lpPoint) {
+ GETVDMPTR(vpPoint, sizeof(POINT16), pPoint16);
+
+ while (c--) {
+ lpPoint->x = pPoint16->x;
+ lpPoint->y = pPoint16->y;
+ lpPoint++;
+ pPoint16++; // ZOWIE Batman, you wouldn't be able to increment
+ } // this pointer if FREEVDMPTR wasn't a no-op! -JTP
+
+ FREEVDMPTR(pPoint16);
+ }
+}
+
+
+VOID putpoint16(VPPOINT16 vpPoint, INT c, LPPOINT lpPoint)
+{
+ INT cb;
+ PPOINT16 pPoint16ptr;
+ register PPOINT16 pPoint16;
+
+ // The assumption here is that no APIs have OPTIONAL POINT pointers
+ // (regardless of whether they're input or output) -JTP
+ WOW32ASSERT(vpPoint);
+
+ if (lpPoint) {
+
+ GETVDMPTR(vpPoint, sizeof(POINT16), pPoint16);
+
+ cb = c;
+ pPoint16ptr = pPoint16;
+ while (c--) {
+ if (lpPoint->x > (LONG)0x7fff)
+ pPoint16->x = (SHORT)0x7fff;
+ else if (lpPoint->x < (LONG)0xffff8000)
+ pPoint16->x = (SHORT)0x8000;
+ else
+ pPoint16->x = (SHORT)lpPoint->x;
+
+ if (lpPoint->y > (LONG)0x7fff)
+ pPoint16->y = (SHORT)0x7fff;
+ else if (lpPoint->y < (LONG)0xffff8000)
+ pPoint16->y = (SHORT)0x8000;
+ else
+ pPoint16->y = (SHORT)lpPoint->y;
+
+ lpPoint++;
+ pPoint16++;
+ }
+
+ FLUSHVDMPTR(vpPoint, cb*sizeof(POINT16), pPoint16ptr);
+ FREEVDMPTR(pPoint16ptr);
+ }
+}
+
+
+
+VOID getintarray16(VPINT16 vpInt, INT c, LPINT lpInt)
+{
+ INT i;
+ register INT16 *pInt16;
+
+ if (lpInt && GETVDMPTR(vpInt, sizeof(INT16)*c, pInt16)) {
+ for (i=0; i < c; i++) {
+ lpInt[i] = FETCHSHORT(pInt16[i]);
+ }
+ }
+ FREEVDMPTR(pInt16);
+}
+
+
+//
+// getuintarray16
+//
+// copies an array of 16-bit unsigned words to an array of 32-bit unsigned
+// words. the pointer to 32-bit array must be freed by the caller.
+//
+
+VOID getuintarray16(VPWORD vp, INT c, PUINT pu)
+{
+ register WORD *pW16;
+
+ if (pu && GETVDMPTR(vp, sizeof(WORD)*c, pW16)) {
+ while (c--) {
+ pu[c] = FETCHWORD(pW16[c]);
+ }
+ FREEVDMPTR(pW16);
+ }
+}
+
+
+VOID putintarray16(VPINT16 vpInt, INT c, LPINT lpInt)
+{
+ INT i;
+ register INT16 *pInt16;
+
+ if (lpInt && GETVDMPTR(vpInt, sizeof(INT16)*c, pInt16)) {
+ for (i=0; i < c; i++) {
+ STOREWORD(pInt16[i], lpInt[i]);
+ }
+ FLUSHVDMPTR(vpInt, sizeof(INT16)*c, pInt16);
+ FREEVDMPTR(pInt16);
+ }
+}
+
+
+VOID putkerningpairs16(VPKERNINGPAIR16 vpKrn, UINT c, LPKERNINGPAIR lpKrn)
+{
+ UINT i;
+ register PKERNINGPAIR16 pKrn16;
+
+ WOW32ASSERT(vpKrn);
+
+ GETVDMPTR(vpKrn, sizeof(KERNINGPAIR16), pKrn16);
+
+ for (i=0; i < c; i++) {
+ pKrn16[i].wFirst = (WORD) lpKrn[i].wFirst;
+ pKrn16[i].wSecond = (WORD) lpKrn[i].wSecond;
+ pKrn16[i].iKernAmount = (INT16) lpKrn[i].iKernAmount;
+ }
+
+ FLUSHVDMPTR(vpKrn, sizeof(KERNINGPAIR16), pKrn16);
+ FREEVDMPTR(pKrn16);
+}
+
+
+
+
+// Fill in a 32 bit DRAWITEMSTRUCT from a 16 bit one
+VOID getdrawitem16(VPDRAWITEMSTRUCT16 vpDI16, LPDRAWITEMSTRUCT lpDI)
+{
+ register PDRAWITEMSTRUCT16 pDI16;
+
+ GETVDMPTR(vpDI16, sizeof(DRAWITEMSTRUCT16), pDI16);
+
+ lpDI->CtlType = FETCHWORD(pDI16->CtlType);
+ lpDI->CtlID = FETCHWORD(pDI16->CtlID);
+ if ((SHORT)(lpDI->itemID = FETCHWORD(pDI16->itemID)) == -1) {
+ lpDI->itemID = (UINT)-1;
+ }
+ lpDI->itemAction = FETCHWORD(pDI16->itemAction);
+ lpDI->itemState = FETCHWORD(pDI16->itemState);
+ lpDI->hwndItem = HWND32(FETCHWORD(pDI16->hwndItem));
+ lpDI->hDC = HDC32(FETCHWORD(pDI16->hDC));
+ lpDI->rcItem.left = (SHORT)pDI16->rcItem.left;
+ lpDI->rcItem.top = (SHORT)pDI16->rcItem.top;
+ lpDI->rcItem.right = (SHORT)pDI16->rcItem.right;
+ lpDI->rcItem.bottom = (SHORT)pDI16->rcItem.bottom;
+ lpDI->itemData = FETCHDWORD(pDI16->itemData);
+
+ FREEVDMPTR(pDI16);
+ return;
+}
+
+
+// Fill in a 16 bit DRAWITEMSTRUCT from a 32 bit one
+VOID putdrawitem16(VPDRAWITEMSTRUCT16 vpDI16, LPDRAWITEMSTRUCT lpDI)
+{
+ register PDRAWITEMSTRUCT16 pDI16;
+
+ GETVDMPTR(vpDI16, sizeof(DRAWITEMSTRUCT16), pDI16);
+
+ STOREWORD(pDI16->CtlType, lpDI->CtlType);
+ STOREWORD(pDI16->CtlID, lpDI->CtlID);
+ STOREWORD(pDI16->itemID, lpDI->itemID);
+ STOREWORD(pDI16->itemAction, lpDI->itemAction);
+ STOREWORD(pDI16->itemState, lpDI->itemState);
+ STOREWORD(pDI16->hwndItem, GETHWND16(lpDI->hwndItem));
+ STOREWORD(pDI16->hDC, GETHDC16(lpDI->hDC));
+ pDI16->rcItem.left = (SHORT)lpDI->rcItem.left;
+ pDI16->rcItem.top = (SHORT)lpDI->rcItem.top;
+ pDI16->rcItem.right = (SHORT)lpDI->rcItem.right;
+ pDI16->rcItem.bottom = (SHORT)lpDI->rcItem.bottom;
+ STOREDWORD(pDI16->itemData, lpDI->itemData);
+
+ FREEVDMPTR(pDI16);
+ return;
+}
+
+#ifdef NOTUSED
+//
+// Allocate and fill a 32bit DropFileStruct based on a 16bit one.
+// 16 bit structure is not freed.
+//
+BOOL getdropfilestruct16(HAND16 hand16, PHANDLE phand32)
+{
+ PDROPFILESTRUCT16 lpdfs16;
+ LPDROPFILESTRUCT lpdfs32;
+ VPVOID vp;
+ INT cb;
+
+ vp = GlobalLock16(hand16, &cb);
+
+ if (vp) {
+
+ GETMISCPTR(vp, lpdfs16);
+
+ *phand32 = GlobalAlloc(GMEM_DDESHARE,
+ cb-sizeof(DROPFILESTRUCT16)+
+ sizeof(DROPFILESTRUCT));
+
+ if (*phand32) {
+
+ lpdfs32 = GlobalLock(*phand32);
+
+ lpdfs32->pFiles = sizeof(DROPFILESTRUCT);
+ lpdfs32->pt.x = lpdfs16->x;
+ lpdfs32->pt.y = lpdfs16->y;
+ lpdfs32->fNC = lpdfs16->fNC;
+ lpdfs32->fWide = FALSE;
+
+ RtlCopyMemory((LPBYTE)lpdfs32+lpdfs32->pFiles,
+ (LPBYTE)lpdfs16+lpdfs16->pFiles,
+ cb-sizeof(DROPFILESTRUCT16));
+
+ FREEMISCPTR(lpdfs16);
+ GlobalUnlock16(hand16);
+
+ GlobalUnlock(*phand32);
+
+ return TRUE;
+
+ } else {
+
+ FREEMISCPTR(lpdfs16);
+ GlobalUnlock16(hand16);
+
+ return FALSE;
+ }
+ } else {
+ *phand32 = NULL;
+ }
+
+ return FALSE;
+}
+
+#endif
+
+
+INT GetBMI16Size(PVPVOID vpbmi16, WORD fuColorUse, LPDWORD lpdwClrUsed)
+{
+ int nHdrSize;
+ int nEntSize;
+ int nEntries;
+ int nBitCount;
+ int nClrUsed = 0;
+ register PBITMAPINFOHEADER16 pbmi16;
+
+ GETVDMPTR(vpbmi16, sizeof(BITMAPINFO16), pbmi16);
+
+ nHdrSize = (int) FETCHDWORD(pbmi16->biSize);
+
+ if ( fuColorUse == DIB_RGB_COLORS ) {
+ nEntSize = sizeof(RGBQUAD);
+ if ( nHdrSize == sizeof(BITMAPCOREHEADER) ) {
+ nEntSize = sizeof(RGBTRIPLE);
+ }
+ }
+ else {
+ nEntSize = sizeof(USHORT);
+ }
+
+ if( nHdrSize == sizeof(BITMAPINFOHEADER) ) {
+ nBitCount = FETCHWORD (pbmi16->biBitCount);
+ nClrUsed = FETCHDWORD(pbmi16->biClrUsed);
+ *lpdwClrUsed = nClrUsed;
+ }
+ else {
+ nBitCount = FETCHWORD(((LPBITMAPCOREHEADER)pbmi16)->bcBitCount);
+ *lpdwClrUsed = 0;
+ }
+
+/* the following block of code should be this:
+ *
+ * if ( nBitCount >= 9 ) { // this is how Win3.1 code says == 24
+ * nEntries = 1;
+ * }
+ * else if ( dwClrUsed ) {
+ * nEntries = dwClrUsed;
+ * }
+ * else {
+ * nEntries = 1 << nBitCount;
+ * }
+ *
+ * but due to the fact that many apps don't initialize the biBitCount &
+ * biClrUsed fields (especially biClrUsed) we have to do the following
+ * sanity checking instead. a-craigj
+ */
+
+ if ( nBitCount <= 8 ) {
+ nEntries = 1 << nBitCount;
+
+ // for selected apps ? What apps will be broken by this ?
+ if (nClrUsed > 0 && nClrUsed < nEntries)
+ nEntries = nClrUsed;
+ }
+ else if (( nBitCount == 16 ) || ( nBitCount == 32)) {
+ nEntries = 3;
+ }
+ // everything else including (nBitCount == 24)
+ else {
+ nEntries = 0;
+ }
+
+ // if this asserts it's an app bug
+ // Changed assert to warning at Craig's request - DaveHart
+#ifdef DEBUG
+ if (!(nEntries > 1) && !(nBitCount == 24)) {
+ LOGDEBUG(LOG_ALWAYS, ("WOW::GetBMI16Size:bad BitCount:a-craigj\n"));
+ }
+#endif
+
+ // this will never be true for a CORE type DIB
+ if(*lpdwClrUsed > (DWORD)nEntries) {
+ *lpdwClrUsed = nEntries;
+ }
+
+ FREEVDMPTR(pbmi16);
+
+ return ( nHdrSize + (nEntries * nEntSize) );
+}
+
+
+
+INT GetBMI32Size(LPBITMAPINFO lpbmi32, WORD fuColorUse)
+{
+ int nHdrSize;
+ int nEntSize;
+ int nEntries;
+ int nBitCount;
+ DWORD dwClrUsed;
+
+ nHdrSize = (int)((LPBITMAPINFOHEADER)lpbmi32)->biSize;
+
+ if ( fuColorUse == DIB_RGB_COLORS ) {
+ nEntSize = sizeof(RGBQUAD);
+ if ( nHdrSize == sizeof(BITMAPCOREHEADER) ) {
+ nEntSize = sizeof(RGBTRIPLE);
+ }
+ }
+ else {
+ nEntSize = sizeof(USHORT);
+ }
+
+ if( nHdrSize == sizeof(BITMAPINFOHEADER) ) {
+ nBitCount = ((LPBITMAPINFOHEADER)lpbmi32)->biBitCount;
+ dwClrUsed = ((LPBITMAPINFOHEADER)lpbmi32)->biClrUsed;
+ }
+ else {
+ nBitCount = (int)((LPBITMAPCOREHEADER)lpbmi32)->bcBitCount;
+ dwClrUsed = 0;
+ }
+
+ nEntries = 0;
+ if ( nBitCount < 9 ) {
+ if((nBitCount == 4) || (nBitCount == 8) || (nBitCount == 1)) {
+ nEntries = 1 << nBitCount;
+ }
+ else if (( nBitCount == 16 ) || ( nBitCount == 32)) {
+ nEntries = 3;
+ }
+ // if this asserts it's an app bug -- we'll try to salvage things
+ WOW32ASSERTMSG((nEntries > 1),
+ ("WOW::GetBMI32Size:bad BitCount:a-craigj\n"));
+
+ // sanity check for apps (lots) that don't init the dwClrUsed field
+ if(dwClrUsed) {
+ nEntries = (int)min((DWORD)nEntries, dwClrUsed);
+ }
+ }
+
+ return ( nHdrSize + (nEntries * nEntSize) );
+}
+
+
+
+LPBITMAPINFO CopyBMI16ToBMI32(PVPVOID vpbmi16, LPBITMAPINFO lpbmi32, WORD fuColorUse)
+{
+ INT nbmiSize = 0;
+ DWORD dwClrUsed;
+ register LPVOID pbmi16;
+
+ if(vpbmi16) {
+
+ if((nbmiSize = GetBMI16Size(vpbmi16, fuColorUse, &dwClrUsed)) != 0) {
+
+ GETVDMPTR(vpbmi16, nbmiSize, pbmi16);
+
+ // We can't trust the size we get since apps don't fill in the
+ // structure correctly so we do a try except around the copy
+ // to the 32 bit structure. That way if we go off the end of
+ // memory it doesn't matter, we continue going. - mattfe june 93
+
+ try {
+ RtlCopyMemory ((VOID *)lpbmi32, (CONST VOID *)pbmi16, nbmiSize);
+ } except (TRUE) {
+ // Continue if we wen't off the end of 16 bit memory
+ }
+
+ // patch color use field in 32-bit BMIH
+ // INFO headers only - CORE headers will have dwClrUsed == 0
+ if(dwClrUsed) {
+ ((LPBITMAPINFOHEADER)lpbmi32)->biClrUsed = dwClrUsed;
+ }
+
+ FREEVDMPTR(pbmi16);
+
+ return (lpbmi32);
+ }
+ }
+
+ return (NULL);
+}
+
+
+
+LPBITMAPINFOHEADER CopyBMIH16ToBMIH32(PVPVOID vpbmih16, LPBITMAPINFOHEADER lpbmih32)
+{
+ DWORD dwHeaderSize = 0L;
+ register PBITMAPINFOHEADER16 pbmih16;
+
+ if(vpbmih16) {
+
+ GETVDMPTR(vpbmih16, sizeof(BITMAPINFOHEADER16), pbmih16);
+
+ dwHeaderSize = FETCHDWORD(pbmih16->biSize);
+
+ RtlCopyMemory((VOID *)lpbmih32,(CONST VOID *)pbmih16,(int)dwHeaderSize);
+
+ FREEVDMPTR(pbmih16);
+
+ return(lpbmih32);
+
+ }
+
+ return(NULL);
+}
+
+
+
+// Fill in a 32 bit MEASUREITEMSTRUCT from a 16 bit one
+VOID getmeasureitem16(VPMEASUREITEMSTRUCT16 vpMI16, LPMEASUREITEMSTRUCT lpMI, HWND16 hwnd16 )
+{
+ register PMEASUREITEMSTRUCT16 pMI16;
+ DWORD dw;
+ BOOL fHasStrings;
+
+ GETVDMPTR(vpMI16, sizeof(MEASUREITEMSTRUCT16), pMI16);
+
+ lpMI->CtlType = FETCHWORD(pMI16->CtlType);
+ lpMI->CtlID = FETCHWORD(pMI16->CtlID);
+ lpMI->itemID = FETCHWORD(pMI16->itemID);
+ lpMI->itemWidth = FETCHWORD(pMI16->itemWidth);
+ lpMI->itemHeight = FETCHWORD(pMI16->itemHeight);
+
+ fHasStrings = FALSE;
+ if ( lpMI->CtlType == ODT_COMBOBOX ) {
+ dw = GetWindowLong( GetDlgItem(HWND32(hwnd16),lpMI->CtlID), GWL_STYLE );
+ fHasStrings = (dw & CBS_HASSTRINGS);
+ }
+ if ( lpMI->CtlType == ODT_LISTBOX ) {
+ dw = GetWindowLong( GetDlgItem(HWND32(hwnd16),lpMI->CtlID), GWL_STYLE );
+ fHasStrings = (dw & LBS_HASSTRINGS);
+ }
+
+ if ( fHasStrings ) {
+ GETPSZPTR(pMI16->itemData, (PVOID)lpMI->itemData);
+ } else {
+ lpMI->itemData = FETCHDWORD(pMI16->itemData);
+ }
+
+ FREEVDMPTR(pMI16);
+ return;
+}
+
+// Fill in a 16 bit MEASUREITEMSTRUCT from a 32 bit one
+VOID putmeasureitem16(VPMEASUREITEMSTRUCT16 vpMI16, LPMEASUREITEMSTRUCT lpMI)
+{
+ register PMEASUREITEMSTRUCT16 pMI16;
+
+ GETVDMPTR(vpMI16, sizeof(MEASUREITEMSTRUCT16), pMI16);
+
+ STOREWORD(pMI16->CtlType, lpMI->CtlType);
+ STOREWORD(pMI16->CtlID, lpMI->CtlID);
+ STOREWORD(pMI16->itemID, lpMI->itemID);
+ STOREWORD(pMI16->itemWidth, lpMI->itemWidth);
+ STOREWORD(pMI16->itemHeight, lpMI->itemHeight);
+ STOREDWORD(pMI16->itemData, lpMI->itemData);
+
+ FREEVDMPTR(pMI16);
+ return;
+}
+
+
+// Fill in a 32 bit DELETEITEMSTRUCT from a 16 bit one
+VOID getdeleteitem16(VPDELETEITEMSTRUCT16 vpDI16, LPDELETEITEMSTRUCT lpDI)
+{
+ register PDELETEITEMSTRUCT16 pDI16;
+
+ GETVDMPTR(vpDI16, sizeof(DELETEITEMSTRUCT16), pDI16);
+
+ lpDI->CtlType = FETCHWORD(pDI16->CtlType);
+ lpDI->CtlID = FETCHWORD(pDI16->CtlID);
+ lpDI->itemID = FETCHWORD(pDI16->itemID);
+ lpDI->hwndItem = HWND32(FETCHWORD(pDI16->hwndItem));
+ lpDI->itemData = FETCHDWORD(pDI16->itemData);
+
+ FREEVDMPTR(pDI16);
+ return;
+}
+
+
+
+// Fill in a 16 bit DELETEITEMSTRUCT from a 32 bit one
+VOID putdeleteitem16(VPDELETEITEMSTRUCT16 vpDI16, LPDELETEITEMSTRUCT lpDI)
+{
+ register PDELETEITEMSTRUCT16 pDI16;
+
+ GETVDMPTR(vpDI16, sizeof(DELETEITEMSTRUCT16), pDI16);
+
+ STOREWORD(pDI16->CtlType, lpDI->CtlType);
+ STOREWORD(pDI16->CtlID, lpDI->CtlID);
+ STOREWORD(pDI16->itemID, lpDI->itemID);
+ STOREWORD(pDI16->hwndItem, GETHWND16(lpDI->hwndItem));
+
+ FLUSHVDMPTR(vpDI16, sizeof(DELETEITEMSTRUCT16), pDI16);
+ FREEVDMPTR(pDI16);
+ return;
+}
+
+
+// Fill in a 32 bit COMPAREITEMSTRUCT from a 16 bit one
+VOID getcompareitem16(VPCOMPAREITEMSTRUCT16 vpCI16, LPCOMPAREITEMSTRUCT lpCI)
+{
+ register PCOMPAREITEMSTRUCT16 pCI16;
+
+ GETVDMPTR(vpCI16, sizeof(COMPAREITEMSTRUCT16), pCI16);
+
+ lpCI->CtlType = FETCHWORD (pCI16->CtlType);
+ lpCI->CtlID = FETCHWORD (pCI16->CtlID);
+ lpCI->hwndItem = HWND32(pCI16->hwndItem);
+ lpCI->itemID1 = FETCHWORD (pCI16->itemID1);
+ lpCI->itemID2 = FETCHWORD (pCI16->itemID2);
+ lpCI->itemData1 = FETCHDWORD(pCI16->itemData1);
+ lpCI->itemData2 = FETCHDWORD(pCI16->itemData2);
+
+ FREEVDMPTR(pCI16);
+ return;
+}
+
+// Fill in a 16 bit COMPAREITEMSTRUCT from a 32 bit one
+VOID putcompareitem16(VPCOMPAREITEMSTRUCT16 vpCI16, LPCOMPAREITEMSTRUCT lpCI)
+{
+ register PCOMPAREITEMSTRUCT16 pCI16;
+
+ GETVDMPTR(vpCI16, sizeof(COMPAREITEMSTRUCT16), pCI16);
+
+ STOREWORD (pCI16->CtlType, (lpCI)->CtlType);
+ STOREWORD (pCI16->CtlID, (lpCI)->CtlID);
+ STOREWORD (pCI16->hwndItem, GETHWND16((lpCI)->hwndItem));
+ STOREWORD (pCI16->itemID1, (lpCI)->itemID1);
+ STOREWORD (pCI16->itemID2, (lpCI)->itemID2);
+ STOREDWORD(pCI16->itemData1, (lpCI)->itemData1);
+ STOREDWORD(pCI16->itemData2, (lpCI)->itemData2);
+
+ FLUSHVDMPTR(vpCI16, sizeof(COMPAREITEMSTRUCT16), pCI16);
+ FREEVDMPTR(pCI16);
+ return;
+}
+
+// NOTE: The below two routines are useful to changing a simple 16-bit message
+// into a 32-bit message and vice-versa. The routines take into account only
+// those messages which can be returned from GetMessage(), or passed to
+// DispatchMessage(), etc. Normally these are only input messages (all other
+// messages are sent rather than posted. This type of message has been
+// extended to include DDE messages (they are posted too) and WM_TIMER messages.
+// If you question this ability, please talk with me. -BobDay
+// These routines should only be called from these routines:
+// CallMsgFilter
+// DispatchMessage
+// GetMessage
+// IsDialogMessage
+// TranslateAccelerator
+// TranslateMDISysAccel
+// TranslateMessage
+// PeekMessage
+// WM32GetDlgCode
+// ThunkWMMsg16
+// Don't call them from any other function!
+//
+// WARNING: May cause 16-bit memory movement, invalidating flat pointers.
+
+// Fill in a 32 bit MSG from a 16 bit one
+// See NOTE above!
+VOID getmsg16(VPMSG16 vpmsg16, LPMSG lpmsg, LPMSGPARAMEX lpmpex)
+{
+ register PMSG16 pmsg16;
+ UINT message;
+ HWND16 hwnd16;
+ WPARAM wParam;
+ LPARAM lParam;
+ WPARAM uParam;
+
+ GETVDMPTR(vpmsg16, sizeof(MSG16), pmsg16);
+
+ hwnd16 = FETCHWORD(pmsg16->hwnd);
+ message = FETCHWORD(pmsg16->message);
+ wParam = FETCHWORD(pmsg16->wParam);
+ lParam = FETCHLONG(pmsg16->lParam);
+ uParam = INT32(wParam); // default thunking - sign extend
+
+#ifdef DEBUG
+ if (HIWORD(wParam) &&
+ !(message==WM_TIMER || message==WM_COMMAND || message==WM_DROPFILES ||
+ (message >= WM_DDE_FIRST && message <= WM_DDE_LAST))) {
+
+ LOGDEBUG(LOG_ALWAYS,("WOW: getmsg16 - losing HIWORD(wParam)!"));
+ WOW32ASSERT(FALSE);
+ }
+#endif
+
+ if ( message == WM_TIMER ) {
+ HAND16 htask16;
+ PTMR ptmr;
+ WORD wIDEvent;
+
+ htask16 = CURRENTPTD()->htask16;
+ wIDEvent = wParam;
+
+ ptmr = FindTimer16( hwnd16, htask16, wIDEvent );
+
+ if ( !ptmr ) {
+ LOGDEBUG(LOG_TRACE,(" getmsg16 WARNING: cannot find timer %04x\n", wIDEvent));
+ } else {
+ uParam = (WPARAM)wIDEvent; // wParam is unsigned word
+ lParam = ptmr->dwTimerProc32; // 32-bit proc or NULL
+ }
+
+ } else if (message == WM_SYSCOMMAND || message == WM_COMMAND || message == WM_DROPFILES ||
+ ( message >= WM_DDE_FIRST && message <= WM_DDE_LAST )) {
+ HWND hwnd32;
+
+ lpmpex->Parm16.WndProc.hwnd = hwnd16;
+ lpmpex->Parm16.WndProc.wMsg = message;
+ lpmpex->Parm16.WndProc.wParam = wParam;
+ lpmpex->Parm16.WndProc.lParam = lParam;
+ lpmpex->iMsgThunkClass = WOWCLASS_WIN16;
+
+ hwnd32 = ThunkMsg16(lpmpex);
+ // memory may have moved
+ FREEVDMPTR(pmsg16);
+ GETVDMPTR(vpmsg16, sizeof(MSG16), pmsg16);
+
+ lParam = lpmpex->lParam;
+ lpmsg->hwnd = hwnd32;
+ lpmsg->message = lpmpex->uMsg;
+ lpmsg->wParam = lpmpex->uParam;
+
+ if (message == WM_DDE_INITIATE) {
+ LOGDEBUG(LOG_ALWAYS,("WOW::getmsg16:*** ERROR: saw WM_DDE_INITIATE message %04x\n", message));
+ WI32DDEDeleteInitiator((HAND16) FETCHWORD(pmsg16->wParam));
+ }
+ goto finish_up;
+
+ }
+
+ lpmsg->hwnd = HWND32(hwnd16);
+ lpmsg->message = message;
+ lpmsg->wParam = uParam;
+finish_up:
+ lpmsg->lParam = lParam;
+ lpmsg->time = FETCHLONG(pmsg16->time);
+ lpmsg->pt.x = FETCHSHORT(pmsg16->pt.x);
+ lpmsg->pt.y = FETCHSHORT(pmsg16->pt.y);
+
+ FREEVDMPTR(pmsg16);
+ return;
+}
+
+/*
+ * Int 16 state key state bits (in order of Int 16 flags)
+ */
+BYTE abStateVK[] = { VK_RSHIFT,
+ VK_LSHIFT,
+ VK_CONTROL,
+ VK_MENU} ;
+
+/*
+ * Int 16 state key toggle bits (in order of Int 16 flags)
+ */
+BYTE abToggleVK[] = { VK_SCROLL,
+ VK_NUMLOCK,
+ VK_CAPITAL,
+ VK_INSERT};
+
+// Updates the Int16 bios shift key state info
+// (uses "synchronous" key state)
+// GetKeyState is a very fast call (GetAsyncKeyState is not)
+void UpdateInt16State(void)
+{
+ BYTE bInt16State = 0;
+ LPBYTE lpbInt16Data;
+ int iBit;
+
+ /*
+ * Get the toggled keys and OR in their toggle state
+ */
+ for( iBit = sizeof(abToggleVK)/sizeof(abToggleVK[0])-1;
+ iBit >= 0; iBit--) {
+ bInt16State = bInt16State << 1;
+ if (GetKeyState(abToggleVK[iBit]) & 1)
+ bInt16State |= 1;
+ }
+
+ /*
+ * Get the state keys and OR in their current state
+ */
+ for( iBit = sizeof(abStateVK)/sizeof(abStateVK[0])-1;
+ iBit >= 0; iBit--) {
+ bInt16State = bInt16State << 1;
+ if (GetKeyState(abStateVK[iBit]) & 0x8000)
+ bInt16State |= 1;
+ }
+
+ // Int 16 keyboard state is at 40:17
+ //
+ // We need to update this address with the current state of
+ // the keyboard buffer.
+ lpbInt16Data = (LPBYTE)GetRModeVDMPointer(0x400017);
+ *lpbInt16Data = bInt16State;
+
+}
+
+// Fill in a 16 bit MSG from a 32 bit one
+// See NOTE above!
+ULONG putmsg16(VPMSG16 vpmsg16, LPMSG lpmsg)
+{
+ register PMSG16 pmsg16;
+ UINT message;
+ WPARAM wParam;
+ LPARAM lParam;
+ WM32MSGPARAMEX wm32mpex;
+ ULONG ulReturn;
+
+ message = lpmsg->message;
+ wParam = lpmsg->wParam;
+ lParam = lpmsg->lParam;
+
+ if (message == WM_TIMER) {
+ PTMR ptmr;
+
+ ptmr = FindTimer32((HWND16)(GETHWND16(lpmsg->hwnd)), (DWORD)wParam);
+
+ if ( !ptmr ) {
+ LOGDEBUG(LOG_TRACE,(" putmsg16 ERROR: cannot find timer %08x\n", lpmsg->wParam));
+ } else {
+ lParam = ptmr->vpfnTimerProc; // 16-bit address or NULL
+ }
+ }
+ else if ((message == WM_COMMAND) ||
+ (message >= WM_DDE_FIRST && message <= WM_DDE_LAST) ||
+ (message == WM_DROPFILES)) {
+
+ WORD wParamNew = (WORD)wParam;
+ LONG lParamNew = (LONG)lParam;
+
+ wm32mpex.Parm16.WndProc.wParam = (WORD)wParam;
+ wm32mpex.Parm16.WndProc.lParam = (LONG)lParam;
+ wm32mpex.fThunk = THUNKMSG;
+ wm32mpex.hwnd = lpmsg->hwnd;
+ wm32mpex.uMsg = message;
+ wm32mpex.uParam = wParam;
+ wm32mpex.lParam = lParam;
+ wm32mpex.pww = (PWW)NULL;
+ wm32mpex.fFree = FALSE;
+ wm32mpex.lpfnM32 = aw32Msg[message].lpfnM32;
+ ulReturn = (wm32mpex.lpfnM32)(&wm32mpex);
+
+ if (ulReturn) {
+ wParam = (WPARAM) wm32mpex.Parm16.WndProc.wParam;
+ lParam = (LPARAM) wm32mpex.Parm16.WndProc.lParam;
+ }
+ else {
+ if ((message == WM_DDE_DATA) || (message == WM_DDE_POKE)) {
+ wParam = (WPARAM) wm32mpex.Parm16.WndProc.wParam;
+ lParam = (LPARAM) wm32mpex.Parm16.WndProc.lParam;
+ }
+ }
+ } else if (message >= WM_KEYFIRST && message <= WM_KEYLAST) {
+ UpdateInt16State();
+ }
+
+ GETVDMPTR(vpmsg16, sizeof(MSG16), pmsg16);
+
+ STOREWORD(pmsg16->hwnd, GETHWND16(lpmsg->hwnd));
+ STOREWORD(pmsg16->message, message);
+ STOREWORD(pmsg16->wParam, wParam);
+ STORELONG(pmsg16->lParam, lParam);
+ STORELONG(pmsg16->time, lpmsg->time);
+ STOREWORD(pmsg16->pt.x, lpmsg->pt.x);
+ STOREWORD(pmsg16->pt.y, lpmsg->pt.y);
+
+ FLUSHVDMPTR(vpmsg16, sizeof(MSG16), pmsg16);
+ FREEVDMPTR(pmsg16);
+ return (ulReturn);
+}
+
+// Fill in a 32 bit LOGFONT from a 16 bit LOGFONT
+VOID getlogfont16(VPLOGFONT16 vplf, LPLOGFONT lplf)
+{
+ register PLOGFONT16 plf16;
+ // PBYTE p1, p2;
+
+ // The assumption here is that no APIs have OPTIONAL LOGFONT pointers
+ WOW32ASSERT(vplf);
+
+ GETVDMPTR(vplf, sizeof(LOGFONT16), plf16);
+
+ lplf->lfHeight = FETCHSHORT(plf16->lfHeight);
+ lplf->lfWidth = FETCHSHORT(plf16->lfWidth);
+ lplf->lfEscapement = FETCHSHORT(plf16->lfEscapement);
+ lplf->lfOrientation = FETCHSHORT(plf16->lfOrientation);
+ lplf->lfWeight = FETCHSHORT(plf16->lfWeight);
+ lplf->lfItalic = plf16->lfItalic;
+ lplf->lfUnderline = plf16->lfUnderline;
+ lplf->lfStrikeOut = plf16->lfStrikeOut;
+ lplf->lfCharSet = plf16->lfCharSet;
+ lplf->lfOutPrecision = plf16->lfOutPrecision;
+ lplf->lfClipPrecision = plf16->lfClipPrecision;
+ lplf->lfQuality = plf16->lfQuality;
+ lplf->lfPitchAndFamily = plf16->lfPitchAndFamily;
+
+#if 0
+ //
+ // can't do it this way, an app can have an unitialized lfFaceName
+ // that's a looong stream of non-null chars, in which case we blow
+ // out our stack.
+ //
+
+ p1 = lplf->lfFaceName;
+ p2 = plf16->lfFaceName;
+
+ while (*p1++ = *p2++);
+#else
+
+#if (LF_FACESIZE != 32)
+#error Win16/Win32 LF_FACESIZE constants differ
+#endif
+
+ strncpy(lplf->lfFaceName, (const char *)plf16->lfFaceName, LF_FACESIZE);
+
+#endif
+
+
+// if (*p2) {
+// i = 0;
+// while ((i < LF_FACESIZE) && (*p2)) {
+// *p1++ = *p2++;
+// i++;
+// }
+// *p1 = *p2;
+//
+// } else {
+// lstrcpy(lplf->lfFaceName, "System");
+// }
+
+ FREEVDMPTR(plf16);
+}
+
+
+// Fill in a 16 bit LOGFONT from a 32 bit LOGFONT
+VOID putlogfont16(VPLOGFONT16 vplf, INT cb, LPLOGFONT lplf)
+{
+ register PLOGFONT16 plf16;
+ PBYTE p1, p2;
+ INT cbCopied;
+
+ // The assumption here is that no APIs have OPTIONAL LOGFONT pointers
+ WOW32ASSERT(vplf);
+
+ GETVDMPTR(vplf, sizeof(LOGFONT16), plf16);
+
+ switch (cb)
+ {
+ default:
+ plf16->lfPitchAndFamily = lplf->lfPitchAndFamily;
+ case 17:
+ plf16->lfQuality = lplf->lfQuality;
+ case 16:
+ plf16->lfClipPrecision = lplf->lfClipPrecision;
+ case 15:
+ plf16->lfOutPrecision = lplf->lfOutPrecision;
+ case 14:
+ plf16->lfCharSet = lplf->lfCharSet;
+ case 13:
+ plf16->lfStrikeOut = lplf->lfStrikeOut;
+ case 12:
+ plf16->lfUnderline = lplf->lfUnderline;
+ case 11:
+ plf16->lfItalic = lplf->lfItalic;
+ case 10:
+ STORESHORT(plf16->lfWeight, lplf->lfWeight);
+ case 9:
+ case 8:
+ STORESHORT(plf16->lfOrientation,lplf->lfOrientation);
+ case 7:
+ case 6:
+ STORESHORT(plf16->lfEscapement, lplf->lfEscapement);
+ case 5:
+ case 4:
+ STORESHORT(plf16->lfWidth, lplf->lfWidth);
+ case 3:
+ case 2:
+ STORESHORT(plf16->lfHeight, lplf->lfHeight);
+ case 1:
+ break;
+ }
+
+ p1 = lplf->lfFaceName;
+ p2 = (PBYTE)plf16->lfFaceName;
+ cbCopied = 18;
+
+ while ((++cbCopied <= cb) && (*p2++ = *p1++));
+
+ FLUSHVDMPTR(vplf, sizeof(LOGFONT16), plf16);
+ FREEVDMPTR(plf16);
+}
+
+
+// Fill in a 16 bit ENUMLOGFONT from a 32 bit ENUMLOGFONT
+VOID putenumlogfont16(VPENUMLOGFONT16 vpelf, LPENUMLOGFONT lpelf)
+{
+ register PENUMLOGFONT16 pelf16;
+ PBYTE p1, p2;
+
+ // The assumption here is that no APIs have OPTIONAL ENUMLOGFONT pointers
+ WOW32ASSERT(vpelf);
+
+ GETVDMPTR(vpelf, sizeof(ENUMLOGFONT16), pelf16);
+
+ STORESHORT(pelf16->elfLogFont.lfHeight, lpelf->elfLogFont.lfHeight);
+ STORESHORT(pelf16->elfLogFont.lfWidth, lpelf->elfLogFont.lfWidth);
+ STORESHORT(pelf16->elfLogFont.lfEscapement, lpelf->elfLogFont.lfEscapement);
+ STORESHORT(pelf16->elfLogFont.lfOrientation,lpelf->elfLogFont.lfOrientation);
+ STORESHORT(pelf16->elfLogFont.lfWeight, lpelf->elfLogFont.lfWeight);
+ pelf16->elfLogFont.lfItalic = lpelf->elfLogFont.lfItalic;
+ pelf16->elfLogFont.lfUnderline = lpelf->elfLogFont.lfUnderline;
+ pelf16->elfLogFont.lfStrikeOut = lpelf->elfLogFont.lfStrikeOut;
+ pelf16->elfLogFont.lfCharSet = lpelf->elfLogFont.lfCharSet;
+ pelf16->elfLogFont.lfOutPrecision = lpelf->elfLogFont.lfOutPrecision;
+ pelf16->elfLogFont.lfClipPrecision = lpelf->elfLogFont.lfClipPrecision;
+ pelf16->elfLogFont.lfQuality = lpelf->elfLogFont.lfQuality;
+ pelf16->elfLogFont.lfPitchAndFamily = lpelf->elfLogFont.lfPitchAndFamily;
+
+ p1 = lpelf->elfLogFont.lfFaceName;
+ p2 = (PBYTE)pelf16->elfLogFont.lfFaceName;
+
+ while ((*p2++ = *p1++) != '\0');
+
+ p1 = lpelf->elfFullName;
+ p2 = (PBYTE)pelf16->elfFullName;
+
+ while ((*p2++ = *p1++) != '\0');
+
+ p1 = lpelf->elfStyle;
+ p2 = (PBYTE)pelf16->elfStyle;
+
+ while ((*p2++ = *p1++) != '\0');
+
+ FLUSHVDMPTR(vpelf, sizeof(ENUMLOGFONT16), pelf16);
+ FREEVDMPTR(pelf16);
+}
+
+
+VOID puttextmetric16(VPTEXTMETRIC16 vptm, LPTEXTMETRIC lptm)
+{
+ register PTEXTMETRIC16 ptm16;
+
+ // The assumption here is that no APIs have OPTIONAL TEXTMETRIC pointers
+ WOW32ASSERT(vptm);
+
+ GETVDMPTR(vptm, sizeof(TEXTMETRIC16), ptm16);
+
+ STORESHORT(ptm16->tmHeight, (lptm)->tmHeight);
+ STORESHORT(ptm16->tmAscent, (lptm)->tmAscent);
+ STORESHORT(ptm16->tmDescent, (lptm)->tmDescent);
+ STORESHORT(ptm16->tmInternalLeading,(lptm)->tmInternalLeading);
+ STORESHORT(ptm16->tmExternalLeading,(lptm)->tmExternalLeading);
+ STORESHORT(ptm16->tmAveCharWidth, (lptm)->tmAveCharWidth);
+ STORESHORT(ptm16->tmMaxCharWidth, (lptm)->tmMaxCharWidth);
+ STORESHORT(ptm16->tmWeight, (lptm)->tmWeight);
+ ptm16->tmItalic = (lptm)->tmItalic;
+ ptm16->tmUnderlined = (lptm)->tmUnderlined;
+ ptm16->tmStruckOut = (lptm)->tmStruckOut;
+ ptm16->tmFirstChar = (lptm)->tmFirstChar;
+ ptm16->tmLastChar = (lptm)->tmLastChar;
+ ptm16->tmDefaultChar = (lptm)->tmDefaultChar;
+ ptm16->tmBreakChar = (lptm)->tmBreakChar;
+ ptm16->tmPitchAndFamily = (lptm)->tmPitchAndFamily;
+ ptm16->tmCharSet = (lptm)->tmCharSet;
+ STORESHORT(ptm16->tmOverhang, (lptm)->tmOverhang);
+ STORESHORT(ptm16->tmDigitizedAspectX,(lptm)->tmDigitizedAspectX);
+ STORESHORT(ptm16->tmDigitizedAspectY,(lptm)->tmDigitizedAspectY);
+
+ FLUSHVDMPTR(vptm, sizeof(TEXTMETRIC16), ptm16);
+ FREEVDMPTR(ptm16);
+}
+
+
+VOID putnewtextmetric16(VPNEWTEXTMETRIC16 vpntm, LPNEWTEXTMETRIC lpntm)
+{
+ register PNEWTEXTMETRIC16 pntm16;
+
+ // The assumption here is that no APIs have OPTIONAL TEXTMETRIC pointers
+ WOW32ASSERT(vpntm);
+
+ GETVDMPTR(vpntm, sizeof(NEWTEXTMETRIC16), pntm16);
+
+ STORESHORT(pntm16->tmHeight, (lpntm)->tmHeight);
+ STORESHORT(pntm16->tmAscent, (lpntm)->tmAscent);
+ STORESHORT(pntm16->tmDescent, (lpntm)->tmDescent);
+ STORESHORT(pntm16->tmInternalLeading, (lpntm)->tmInternalLeading);
+ STORESHORT(pntm16->tmExternalLeading, (lpntm)->tmExternalLeading);
+ STORESHORT(pntm16->tmAveCharWidth, (lpntm)->tmAveCharWidth);
+ STORESHORT(pntm16->tmMaxCharWidth, (lpntm)->tmMaxCharWidth);
+ STORESHORT(pntm16->tmWeight, (lpntm)->tmWeight);
+
+ pntm16->tmItalic = (lpntm)->tmItalic;
+ pntm16->tmUnderlined = (lpntm)->tmUnderlined;
+ pntm16->tmStruckOut = (lpntm)->tmStruckOut;
+ pntm16->tmFirstChar = (lpntm)->tmFirstChar;
+ pntm16->tmLastChar = (lpntm)->tmLastChar;
+ pntm16->tmDefaultChar = (lpntm)->tmDefaultChar;
+ pntm16->tmBreakChar = (lpntm)->tmBreakChar;
+ pntm16->tmPitchAndFamily = (lpntm)->tmPitchAndFamily;
+ pntm16->tmCharSet = (lpntm)->tmCharSet;
+
+ STORESHORT(pntm16->tmOverhang, (lpntm)->tmOverhang);
+ STORESHORT(pntm16->tmDigitizedAspectX, (lpntm)->tmDigitizedAspectX);
+ STORESHORT(pntm16->tmDigitizedAspectY, (lpntm)->tmDigitizedAspectY);
+
+ STOREDWORD(pntm16->ntmFlags, (lpntm)->ntmFlags);
+ STOREWORD( pntm16->ntmSizeEM, (WORD)((lpntm)->ntmSizeEM));
+ STOREWORD( pntm16->ntmCellHeight, (WORD)((lpntm)->ntmCellHeight));
+ STOREWORD( pntm16->ntmAvgWidth, (WORD)((lpntm)->ntmAvgWidth));
+
+ FLUSHVDMPTR(vpntm, sizeof(NEWTEXTMETRIC16), pntm16);
+ FREEVDMPTR(pntm16);
+}
+
+VOID putoutlinetextmetric16(VPOUTLINETEXTMETRIC16 vpotm, INT cb, LPOUTLINETEXTMETRIC lpotm)
+{
+ register POUTLINETEXTMETRIC16 potm16;
+ OUTLINETEXTMETRIC16 otm16;
+ int count;
+
+ GETVDMPTR(vpotm, cb, potm16);
+
+ otm16.otmSize = (WORD)lpotm->otmSize;
+
+ /*
+ ** Copy the TEXTMETRIC structure
+ */
+ otm16.otmTextMetrics.tmHeight = (SHORT)lpotm->otmTextMetrics.tmHeight;
+ otm16.otmTextMetrics.tmAscent = (SHORT)lpotm->otmTextMetrics.tmAscent;
+ otm16.otmTextMetrics.tmDescent = (SHORT)lpotm->otmTextMetrics.tmDescent;
+ otm16.otmTextMetrics.tmInternalLeading = (SHORT)lpotm->otmTextMetrics.tmInternalLeading;
+ otm16.otmTextMetrics.tmExternalLeading = (SHORT)lpotm->otmTextMetrics.tmExternalLeading;
+ otm16.otmTextMetrics.tmAveCharWidth = (SHORT)lpotm->otmTextMetrics.tmAveCharWidth;
+ otm16.otmTextMetrics.tmMaxCharWidth = (SHORT)lpotm->otmTextMetrics.tmMaxCharWidth;
+ otm16.otmTextMetrics.tmWeight = (SHORT)lpotm->otmTextMetrics.tmWeight;
+ otm16.otmTextMetrics.tmItalic = lpotm->otmTextMetrics.tmItalic;
+ otm16.otmTextMetrics.tmUnderlined = lpotm->otmTextMetrics.tmUnderlined;
+ otm16.otmTextMetrics.tmStruckOut = lpotm->otmTextMetrics.tmStruckOut;
+ otm16.otmTextMetrics.tmFirstChar = lpotm->otmTextMetrics.tmFirstChar;
+ otm16.otmTextMetrics.tmLastChar = lpotm->otmTextMetrics.tmLastChar;
+ otm16.otmTextMetrics.tmDefaultChar = lpotm->otmTextMetrics.tmDefaultChar;
+ otm16.otmTextMetrics.tmBreakChar = lpotm->otmTextMetrics.tmBreakChar;
+ otm16.otmTextMetrics.tmPitchAndFamily = lpotm->otmTextMetrics.tmPitchAndFamily;
+ otm16.otmTextMetrics.tmCharSet = lpotm->otmTextMetrics.tmCharSet;
+ otm16.otmTextMetrics.tmOverhang = (SHORT)lpotm->otmTextMetrics.tmOverhang;
+ otm16.otmTextMetrics.tmDigitizedAspectX = (SHORT)lpotm->otmTextMetrics.tmDigitizedAspectX;
+ otm16.otmTextMetrics.tmDigitizedAspectY = (SHORT)lpotm->otmTextMetrics.tmDigitizedAspectY;
+
+ otm16.otmFiller = lpotm->otmFiller;
+
+ /*
+ ** Panose
+ */
+ otm16.otmPanoseNumber.bFamilyType = lpotm->otmPanoseNumber.bFamilyType;
+ otm16.otmPanoseNumber.bSerifStyle = lpotm->otmPanoseNumber.bSerifStyle;
+ otm16.otmPanoseNumber.bWeight = lpotm->otmPanoseNumber.bWeight;
+ otm16.otmPanoseNumber.bProportion = lpotm->otmPanoseNumber.bProportion;
+ otm16.otmPanoseNumber.bContrast = lpotm->otmPanoseNumber.bContrast;
+ otm16.otmPanoseNumber.bStrokeVariation = lpotm->otmPanoseNumber.bStrokeVariation;
+ otm16.otmPanoseNumber.bArmStyle = lpotm->otmPanoseNumber.bArmStyle;
+ otm16.otmPanoseNumber.bMidline = lpotm->otmPanoseNumber.bMidline;
+ otm16.otmPanoseNumber.bXHeight = lpotm->otmPanoseNumber.bXHeight;
+
+ otm16.otmfsSelection = (WORD)lpotm->otmfsSelection;
+ otm16.otmfsType = (WORD)lpotm->otmfsType;
+ otm16.otmsCharSlopeRise = (SHORT)lpotm->otmsCharSlopeRise;
+ otm16.otmsCharSlopeRun = (SHORT)lpotm->otmsCharSlopeRun;
+ otm16.otmItalicAngle = (SHORT)lpotm->otmItalicAngle;
+ otm16.otmEMSquare = (WORD)lpotm->otmEMSquare;
+ otm16.otmAscent = (SHORT)lpotm->otmAscent;
+ otm16.otmDescent = (SHORT)lpotm->otmDescent;
+ otm16.otmLineGap = (WORD)lpotm->otmLineGap;
+
+ otm16.otmsCapEmHeight = (WORD)lpotm->otmsCapEmHeight;
+ otm16.otmsXHeight = (WORD)lpotm->otmsXHeight;
+
+ /*
+ ** Font Box Rectangle (ZOWIE!, I sure wish I could use putrect16 but alas!)
+ */
+ otm16.otmrcFontBox.left = (SHORT)lpotm->otmrcFontBox.left;
+ otm16.otmrcFontBox.top = (SHORT)lpotm->otmrcFontBox.top;
+ otm16.otmrcFontBox.right = (SHORT)lpotm->otmrcFontBox.right;
+ otm16.otmrcFontBox.bottom = (SHORT)lpotm->otmrcFontBox.bottom;
+
+ otm16.otmMacAscent = (SHORT)lpotm->otmMacAscent;
+ otm16.otmMacDescent = (SHORT)lpotm->otmMacDescent;
+
+ otm16.otmMacLineGap = (WORD)lpotm->otmMacLineGap;
+ otm16.otmusMinimumPPEM = (WORD)lpotm->otmusMinimumPPEM;
+
+ otm16.otmptSubscriptSize.x = (SHORT)lpotm->otmptSubscriptSize.x;
+ otm16.otmptSubscriptSize.y = (SHORT)lpotm->otmptSubscriptSize.y;
+
+ otm16.otmptSubscriptOffset.x = (SHORT)lpotm->otmptSubscriptOffset.x;
+ otm16.otmptSubscriptOffset.y = (SHORT)lpotm->otmptSubscriptOffset.y;
+
+ otm16.otmptSuperscriptSize.x = (SHORT)lpotm->otmptSuperscriptSize.x;
+ otm16.otmptSuperscriptSize.y = (SHORT)lpotm->otmptSuperscriptSize.y;
+
+ otm16.otmptSuperscriptOffset.x = (SHORT)lpotm->otmptSuperscriptOffset.x;
+ otm16.otmptSuperscriptOffset.y = (SHORT)lpotm->otmptSuperscriptOffset.y;
+
+ otm16.otmsStrikeoutSize = (WORD)lpotm->otmsStrikeoutSize;
+ otm16.otmsStrikeoutPosition = (SHORT)lpotm->otmsStrikeoutPosition;
+
+ otm16.otmsUnderscorePosition = (SHORT)lpotm->otmsUnderscorePosition;
+ otm16.otmsUnderscoreSize = (SHORT)lpotm->otmsUnderscoreSize;
+
+ otm16.otmpFamilyName = (WORD) (lpotm->otmpFamilyName -
+ sizeof(OUTLINETEXTMETRIC) + sizeof(OUTLINETEXTMETRIC16));
+
+ otm16.otmpFaceName = (WORD) (lpotm->otmpFaceName -
+ sizeof(OUTLINETEXTMETRIC) + sizeof(OUTLINETEXTMETRIC16));
+
+ otm16.otmpStyleName = (WORD) (lpotm->otmpStyleName -
+ sizeof(OUTLINETEXTMETRIC) + sizeof(OUTLINETEXTMETRIC16));
+
+ otm16.otmpFullName = (WORD) (lpotm->otmpFullName -
+ sizeof(OUTLINETEXTMETRIC) + sizeof(OUTLINETEXTMETRIC16));
+
+ count = sizeof(OUTLINETEXTMETRIC16);
+ if ( cb <= count ) {
+ count = cb;
+ } else {
+ /*
+ ** Copy the rest of the buffer (strings, etc.) over verbatim.
+ */
+ RtlCopyMemory( (LPSTR)potm16 + sizeof(OUTLINETEXTMETRIC16),
+ (LPSTR)lpotm + sizeof(OUTLINETEXTMETRIC),
+ cb - sizeof(OUTLINETEXTMETRIC16) );
+ }
+
+ /*
+ ** Now really copy it (the structure portion) into the 16-bit memory
+ */
+ RtlCopyMemory((VOID *)potm16, (CONST VOID *)&otm16, count );
+
+ FLUSHVDMPTR(vpotm, cb, potm16);
+ FREEVDMPTR(potm16);
+}
+
+VOID getlogpalette16(VPLOGPALETTE16 vplp, LPLOGPALETTE lplp)
+{
+ INT i,j;
+ register PLOGPALETTE16 plp16;
+
+ GETVDMPTR(vplp, sizeof(LOGPALETTE16), plp16);
+
+ if( lplp ) {
+ lplp->palVersion = FETCHWORD(plp16->palVersion);
+ lplp->palNumEntries = FETCHWORD(plp16->palNumEntries);
+ j = (INT) FETCHWORD(plp16->palNumEntries);
+
+ for (i=0; i<j; i++) {
+ lplp->palPalEntry[i].peRed = plp16->palPalEntry[i].peRed;
+ lplp->palPalEntry[i].peGreen = plp16->palPalEntry[i].peGreen;
+ lplp->palPalEntry[i].peBlue = plp16->palPalEntry[i].peBlue;
+ lplp->palPalEntry[i].peFlags = plp16->palPalEntry[i].peFlags;
+ }
+ }
+
+ FREEVDMPTR(plp16);
+}
+
+
+VOID getpaletteentry16(VPPALETTEENTRY16 vppe, INT c, LPPALETTEENTRY lpp)
+{
+ INT i;
+ register PALETTEENTRY16 *pp16;
+
+ GETVDMPTR(vppe, sizeof(PALETTEENTRY16)*c, pp16);
+
+ if( lpp ) {
+ for (i=0; i < c; i++) {
+ lpp[i].peRed = pp16[i].peRed;
+ lpp[i].peGreen = pp16[i].peGreen;
+ lpp[i].peBlue = pp16[i].peBlue;
+ lpp[i].peFlags = pp16[i].peFlags;
+ }
+ }
+ FREEVDMPTR(pp16);
+}
+
+
+VOID putpaletteentry16(VPPALETTEENTRY16 vppe, INT c, LPPALETTEENTRY lpp)
+{
+ INT i;
+ register PALETTEENTRY16 *pp16;
+
+ GETVDMPTR(vppe, sizeof(PALETTEENTRY16)*c, pp16);
+
+ if( pp16 ) {
+ for (i=0; i < c; i++) {
+ pp16[i].peRed = lpp[i].peRed;
+ pp16[i].peGreen = lpp[i].peGreen;
+ pp16[i].peBlue = lpp[i].peBlue;
+ pp16[i].peFlags = lpp[i].peFlags;
+ }
+ }
+
+ FLUSHVDMPTR(vppe, sizeof(PALETTEENTRY16)*c, pp16);
+ FREEVDMPTR(pp16);
+}
+
+
+
+// Converts a 16 bit handle table to 32 bit
+VOID gethandletable16(VPWORD vpht, UINT c, LPHANDLETABLE lpht)
+{
+ PHANDLETABLE16 pht16;
+ WORD w;
+ GETVDMPTR(vpht, sizeof(HAND16)*c, pht16);
+
+ // be careful, we need to get the correct 32 obj handle from alias
+
+ while (c--)
+ {
+ w = FETCHWORD(pht16->objectHandle[c]);
+ if (w)
+ lpht->objectHandle[c] = HOBJ32(w);
+ else
+ lpht->objectHandle[c] = (HANDLE)NULL;
+ }
+
+ FREEVDMPTR(pht16);
+}
+
+// Converts a 32 bit handle table to 16 bit
+VOID puthandletable16(VPWORD vpht, UINT c, LPHANDLETABLE lpht)
+{
+ PHANDLETABLE16 pht16;
+ DWORD dw;
+ GETVDMPTR(vpht, sizeof(HAND16)*c, pht16);
+
+ // be careful, we need to get the correct 16 alias the 32 obj handle
+
+ while (c--) {
+ dw = FETCHDWORD(lpht->objectHandle[c]);
+ if (dw) {
+ pht16->objectHandle[c] = GETHOBJ16((HAND32)dw);
+ }
+ else {
+ pht16->objectHandle[c] = (HAND16)NULL;
+ }
+ }
+
+ FREEVDMPTR(pht16);
+}
+
+
+
+
+
+
+
+/*
+ * To solve a ton of devmode compatibility issues we are now going to return
+ * Win3.1 devmodes to 16-bit apps instead of NT devmodes.
+ *
+ * The most common problem we encounter is that apps determine the size to
+ * allocate for a DEVMODE buffer by: sizeof(DEVMODE) + dm->dmDriverExtra
+ * Apps seem to handle the DriverExtra stuff pretty well but there is a wide-
+ * spread belief that the public DEVMODE structure is a fixed size.
+ * We hide the NT specific DEVMODE stuff and the WOW devmode thunk info in
+ * what the app thinks is the DriverExtra part of the devmode:
+ *
+ * ____________________________ _____
+ * | Win 3.1 DEVMODE | |
+ * | dmSize = sizeof(DEVMODE31) | |
+ * | dmDriverExtra = | |
+ * ___|__/ (sizeof(DEVMODENT) - | Win 3.1 DEVMODE
+ * | | \ sizeof(DEVMODE31)) + | |
+ * -|---|--- original DriverExtra + | |
+ * | | _|__/ sizeof(DWORD) + | |
+ * | | | | \ (sizeof(WORD) * 3) | |
+ * | | | |____________________________| _____| <-- where app thinks driver
+ * | | | | NT DEVMODE stuff not in | | extra starts
+ * | `-->| the Win3.1 DEVMODE struct | NT specific DEVMODE stuff
+ * | | |____________________________| _____| <-- where driver extra really
+ * `---->| actual NT driver extra | starts
+ * | |____________________________| <-- where WOWDM31 struct starts
+ * | | DWORD with "DM31" | <--- WOW DEVMODE31 signature
+ * ->| WORD original dmSpecVersion|\
+ * | WORD original dmSize | <--- values returned by the driver
+ * | WORD original dmDriverExtra|/
+ * | WORD to pad to even DWORD | <--- requried for ptr arithmetic
+ * |____________________________|
+ *
+ * NOTE: We may see Win3.0 & Win3.1 DevModes that are returned by 16-bit fax
+ * drivers.
+ *
+*/
+LPDEVMODE ThunkDevMode16to32(VPDEVMODE31 vpdm16)
+{
+ INT nSize, nDriverExtra;
+ LPDEVMODE lpdm32;
+ PDEVMODE31 pdm16;
+ PWOWDM31 pWOWDM31;
+
+ if(FETCHDWORD(vpdm16) == 0L) {
+ return(NULL);
+ }
+
+ GETVDMPTR(vpdm16, sizeof(DEVMODE31), pdm16);
+
+
+ // we will generally see only Win3.1 DevMode's here but 16-bit fax
+ // drivers can return a Win3.0 DevMode.
+ nSize = FETCHWORD(pdm16->dmSize);
+ WOW32WARNMSGF((nSize==sizeof(DEVMODE31)),
+ ("ThunkDevMode16to32: Unexpected dmSize(16) = %d\n", nSize));
+
+ // check for bad DEVMODE (PageMaker & MSProfit are known culprits)
+ // (PageMaker 5.0a passes a 16:16 ptr to NULL!!)
+ // this test taken from gdi\client\object.c!bConvertToDevmodeW
+ if ( (nSize < (offsetof(DEVMODE, dmDriverExtra) + sizeof(WORD))) ||
+ (nSize > sizeof(DEVMODE)) ) {
+ LOGDEBUG(LOG_ALWAYS,("WOW::ThunkDevMode16to32:Bail out case!!\n"));
+
+ return(NULL);
+ }
+
+ // note this might include the "extra" DriverExtra we added in
+ // ThunkDevMode32to16()
+ nDriverExtra = FETCHWORD(pdm16->dmDriverExtra);
+
+ // allocate 32-bit DEVMODE -- don't worry if we alloc a little too much due
+ // to the WOW stuff we added to the end of the driver extra
+ if(lpdm32 = malloc_w(nSize + nDriverExtra)) {
+
+ // fill in the 32-bit devmode
+ RtlCopyMemory((VOID *)lpdm32,(CONST VOID *)pdm16, nSize + nDriverExtra);
+
+ // if this is a Win3.1 size DEVMODE, it may be one of our special ones
+ if(nSize == sizeof(DEVMODE31)) {
+
+ // see if it has our "DM31" signature at the end of the DEVMODE
+ pWOWDM31 = (PWOWDM31)((PBYTE)lpdm32 +
+ sizeof(DEVMODE31) +
+ nDriverExtra -
+ sizeof(WOWDM31));
+
+ // if it does, adjust the dmSpecVersion, dmSize & dmDriverExtra
+ // back to the values we got from the driver
+ if(pWOWDM31->dwWOWSig == WOW_DEVMODE31SIG) {
+ lpdm32->dmSpecVersion = pWOWDM31->dmSpecVersion;
+ lpdm32->dmSize = pWOWDM31->dmSize;
+ lpdm32->dmDriverExtra = pWOWDM31->dmDriverExtra;
+ }
+ }
+ }
+
+ FREEVDMPTR(pdm16);
+
+ return(lpdm32);
+}
+
+
+
+
+
+
+BOOL ThunkDevMode32to16(VPDEVMODE31 vpdm16, LPDEVMODE lpdm32, UINT nBytes)
+{
+
+ UINT nSize, nDriverExtra;
+
+ PDEVMODE31 pdm16;
+ PWOWDM31 pWOWDM31;
+
+
+ GETVDMPTR(vpdm16, sizeof(DEVMODE31), pdm16);
+
+ if((FETCHDWORD(vpdm16) == 0L) || (!lpdm32) || (!pdm16)) {
+ return(FALSE);
+ }
+
+ nSize = lpdm32->dmSize;
+
+ // We should only see DevModes of the current NT size because the spooler
+ // converts all devmodes to the current version
+ WOW32WARNMSGF((nSize==sizeof(DEVMODE)),
+ ("ThunkDevMode32to16: Unexpected devmode size = %d\n",nSize));
+
+ nDriverExtra = lpdm32->dmDriverExtra;
+
+ // fill in the 16-bit devmode
+ RtlCopyMemory((VOID *)pdm16,
+ (CONST VOID *)lpdm32,
+ min((nSize + nDriverExtra), nBytes));
+
+ // Convert NT sized devmodes to Win3.1 devmodes.
+ // Note: Winfax.drv passes back an NT size DevMode with dmSpecVersion=0x300
+ // also it passes a hard coded 0xa9 to GetEnvironment() as the max
+ // size of its buffer (see GetEnvironment() notes in wgdi.c)
+ // If there is a buffer constraint, we'll just have to be satisfied
+ // with copying the nBytes worth of the devmode which should work
+ // in the case of WinFax.
+ if((nSize == sizeof(DEVMODE)) && ((nSize + nDriverExtra) <= nBytes)) {
+
+ // save our signature along with the original dmSpecVersion, dmSize,
+ // and dmDriverExtra at the end of the DriverExtra memory
+ pWOWDM31 = (PWOWDM31)((PBYTE)pdm16 +
+ sizeof(DEVMODE) +
+ nDriverExtra);
+ pWOWDM31->dwWOWSig = WOW_DEVMODE31SIG;
+ pWOWDM31->dmSpecVersion = lpdm32->dmSpecVersion;
+ pWOWDM31->dmSize = nSize;
+ pWOWDM31->dmDriverExtra = nDriverExtra;
+
+ // Make our special adjustments to the public devmode stuff.
+ // We can't tell an app a Win3.0 DevMode is a Win3.1 version or it might
+ // try to write to the new Win3.1 fields
+ if(lpdm32->dmSpecVersion > WOW_DEVMODE31SPEC) {
+ pdm16->dmSpecVersion = WOW_DEVMODE31SPEC;
+ }
+ pdm16->dmSize = sizeof(DEVMODE31);
+ pdm16->dmDriverExtra += WOW_DEVMODEEXTRA;
+ }
+
+ FLUSHVDMPTR(vpdm16, sizeof(DEVMODE31), pdm16);
+ FREEVDMPTR(pdm16);
+
+ return(TRUE);
+}
+
+
+
+
+VOID getwindowpos16( VPWINDOWPOS16 vpwp, LPWINDOWPOS lpwp )
+{
+ register PWINDOWPOS16 pwp16;
+
+ GETVDMPTR(vpwp, sizeof(WINDOWPOS16), pwp16);
+
+ lpwp->hwnd = HWND32(pwp16->hwnd);
+ lpwp->hwndInsertAfter = HWNDIA32(pwp16->hwndInsertAfter);
+ lpwp->x = (INT) FETCHSHORT(pwp16->x);
+ lpwp->y = (INT) FETCHSHORT(pwp16->y);
+ lpwp->cx = (INT) FETCHSHORT(pwp16->cx);
+ lpwp->cy = (INT) FETCHSHORT(pwp16->cy);
+ lpwp->flags = (WORD) FETCHWORD(pwp16->flags);
+
+ FREEVDMPTR(pwp16);
+}
+
+VOID putwindowpos16( VPWINDOWPOS16 vpwp, LPWINDOWPOS lpwp )
+{
+ register PWINDOWPOS16 pwp16;
+
+ GETVDMPTR(vpwp, sizeof(WINDOWPOS16), pwp16);
+
+ STOREWORD(pwp16->hwnd, GETHWND16(lpwp->hwnd));
+ STOREWORD(pwp16->hwndInsertAfter, GETHWNDIA16(lpwp->hwndInsertAfter));
+ STORESHORT(pwp16->x, lpwp->x);
+ STORESHORT(pwp16->y, lpwp->y);
+ STORESHORT(pwp16->cx, lpwp->cx);
+ STORESHORT(pwp16->cy, lpwp->cy);
+ STOREWORD(pwp16->flags, lpwp->flags);
+
+ FLUSHVDMPTR(vpwp, sizeof(WINDOWPOS16), pwp16);
+ FREEVDMPTR(pwp16);
+}
+
+
+VOID W32CopyMsgStruct(VPMSG16 vpmsg16, LPMSG lpmsg, BOOL fThunk16To32)
+{
+ register PMSG16 pmsg16;
+
+ GETVDMPTR(vpmsg16, sizeof(MSG16), pmsg16);
+
+ if (fThunk16To32) {
+ lpmsg->hwnd = HWND32(pmsg16->hwnd);
+ lpmsg->message = pmsg16->message;
+ lpmsg->wParam = pmsg16->wParam;
+ lpmsg->lParam = pmsg16->lParam;
+ lpmsg->time = pmsg16->time;
+ lpmsg->pt.x = pmsg16->pt.x;
+ lpmsg->pt.y = pmsg16->pt.y;
+ }
+ else {
+ // for later use.
+ }
+
+ FREEVDMPTR(pmsg16);
+ return;
+}
+
+VOID getpaintstruct16(VPVOID vp, LPPAINTSTRUCT lp)
+{
+ PPAINTSTRUCT16 pps16;
+ GETVDMPTR(vp, sizeof(PAINTSTRUCT16), pps16);
+ (lp)->hdc = HDC32(FETCHWORD(pps16->hdc));
+ (lp)->fErase = FETCHSHORT(pps16->fErase);
+ (lp)->rcPaint.left = FETCHSHORT(pps16->rcPaint.left);
+ (lp)->rcPaint.top = FETCHSHORT(pps16->rcPaint.top);
+ (lp)->rcPaint.right = FETCHSHORT(pps16->rcPaint.right);
+ (lp)->rcPaint.bottom= FETCHSHORT(pps16->rcPaint.bottom);
+ (lp)->fRestore = FETCHSHORT(pps16->fRestore);
+ (lp)->fIncUpdate = FETCHSHORT(pps16->fIncUpdate);
+ RtlCopyMemory((lp)->rgbReserved,
+ pps16->rgbReserved, sizeof(pps16->rgbReserved));
+ FREEVDMPTR(pps16);
+}
+
+
+VOID putpaintstruct16(VPVOID vp, LPPAINTSTRUCT lp)
+{
+ PPAINTSTRUCT16 pps16;
+ GETVDMPTR(vp, sizeof(PAINTSTRUCT16), pps16);
+ STOREWORD(pps16->hdc, GETHDC16((lp)->hdc));
+ STORESHORT(pps16->fErase, (lp)->fErase);
+ STORESHORT(pps16->rcPaint.left, (lp)->rcPaint.left);
+ STORESHORT(pps16->rcPaint.top, (lp)->rcPaint.top);
+ STORESHORT(pps16->rcPaint.right, (lp)->rcPaint.right);
+ STORESHORT(pps16->rcPaint.bottom, (lp)->rcPaint.bottom);
+ STORESHORT(pps16->fRestore, (lp)->fRestore);
+ STORESHORT(pps16->fIncUpdate, (lp)->fIncUpdate);
+ RtlCopyMemory(pps16->rgbReserved,
+ (lp)->rgbReserved, sizeof(pps16->rgbReserved));
+ FLUSHVDMPTR(vp, sizeof(PAINTSTRUCT16), pps16);
+ FREEVDMPTR(pps16);
+}
diff --git a/private/mvdm/wow32/wstruc.h b/private/mvdm/wow32/wstruc.h
new file mode 100644
index 000000000..ed40e48bf
--- /dev/null
+++ b/private/mvdm/wow32/wstruc.h
@@ -0,0 +1,313 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSTRUC.H
+ * WOW32 16-bit structure conversion support
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * Added GDI macro definitions 6/13/91, ChandanC
+ * Added MDI structures 1/20/91, BobDay
+--*/
+#ifndef _DEF_WSTRUC_ // if this hasn't already been included
+#define _DEF_WSTRUC_
+
+/* Structure conversion macros
+ */
+#define PUTINT16(vp,i) WOW32ASSERT(!(LOW(vp)&1));\
+ *(PSHORT16)GetPModeVDMPointer(vp, sizeof(SHORT)) = (SHORT)i;
+
+#define PUTBOOL16(vp,b) WOW32ASSERT(!(LOW(vp)&1));\
+ if (FETCHDWORD(vp))\
+ *(PWORD16)GetPModeVDMPointer(vp, sizeof(WORD)) = (WORD)b;
+#define STACKORHEAPALLOC(cBytesNeeded, cBytesAvail, lpStackBuffer) \
+ ((INT)(cBytesNeeded) > (INT)(cBytesAvail)) ? (PVOID)malloc_w(cBytesNeeded) : \
+ (PVOID)(lpStackBuffer)
+
+#define STACKORHEAPFREE(lpToFree, lpStackBuffer) \
+ if ((lpToFree) && (PVOID)(lpToFree) != (PVOID)(lpStackBuffer)) free_w(lpToFree)
+
+#define PUTINTARRAY16(vp,c,p) putintarray16(FETCHDWORD(vp), c, p)
+#define PUTINTARRAY16V(vp,c,p) putintarray16(vp, c, p)
+
+// GETDWORDARRAY16 is not analogous to any of the above.
+#define GETDWORDARRAY16(vp,c,p) {GETVDMPTR(vp, c*sizeof(DWORD), p);}
+#define FREEDWORDARRAY16(p) {if (p) FREEVDMPTR(p);}
+
+#define GETRECT16(vp,p) getrect16(FETCHDWORD(vp), p)
+#define PUTRECT16(vp,p) putrect16(FETCHDWORD(vp), p)
+
+// COPYPOINT16 is used by ClientToScreen because the point is passed
+// directly as an argument, instead of a pointer to the point.
+
+#define COPYPOINT16(Pt16,Pt) {Pt.x = Pt16.x; Pt.y = Pt16.y;}
+
+#define GETPOINT16(vp,p) getpoint16(FETCHDWORD(vp), 1, p)
+#define PUTPOINT16(vp,p) putpoint16(FETCHDWORD(vp), 1, p)
+
+
+//
+// Get/Put point array macros.
+//
+// These routines will use a static buffer if the number of points to
+// be thunked is small enough. This will break badly if a thunk uses
+// GETPOINTARRAY16 and then calls a function which calls back, since
+// during the callback we could call another function which uses the
+// same static buffer.
+//
+// As of 7-Jan-92 the only callers are in GDI, which doesn't call back,
+// so we're OK.
+//
+// GETPOINTARRAY16 sometimes allocates memory, so you must call
+// FREEPOINTARRAY16 once for every GETPOINTARRAY16.
+//
+
+#define PUTPOINTARRAY16(vp,c,p) putpoint16(FETCHDWORD(vp), c, p)
+
+#define FREEMSG16(vp,lp)
+
+#define GETWNDCLASS16(vp,lp) {\
+ WORD w;\
+ PWNDCLASS16 pwc16;\
+ GETVDMPTR(vp, sizeof(WNDCLASS16), pwc16);\
+ (lp)->style = FETCHWORD(pwc16->style);\
+ (lp)->lpfnWndProc = (WNDPROC)FETCHDWORD(pwc16->vpfnWndProc);\
+ (lp)->cbClsExtra = FETCHWORD(pwc16->cbClsExtra);\
+ (lp)->cbWndExtra = FETCHWORD(pwc16->cbWndExtra);\
+ w = FETCHWORD(pwc16->hInstance);\
+ if((w == gUser16hInstance) || (w == BOGUSGDT))\
+ (lp)->hInstance = ghInstanceUser32;\
+ else\
+ (lp)->hInstance = HMODINST32(FETCHWORD(pwc16->hInstance));\
+ (lp)->hIcon = HICON32_REGCLASS(FETCHWORD(pwc16->hIcon));\
+ (lp)->hCursor = HCURSOR32(FETCHWORD(pwc16->hCursor));\
+ w = FETCHWORD(pwc16->hbrBackground);\
+ if (w > COLOR_ENDCOLORS)\
+ (lp)->hbrBackground = HBRUSH32(w);\
+ else\
+ (lp)->hbrBackground = (HBRUSH)w;\
+ (lp)->lpszMenuName = (LPSTR)FETCHDWORD(pwc16->vpszMenuName);\
+ (lp)->lpszClassName = (LPSTR)FETCHDWORD(pwc16->vpszClassName);\
+ FREEVDMPTR(pwc16);\
+ }
+
+
+#define GETBITMAP16(vp, lp) {\
+ PBITMAP16 pbm16;\
+ GETVDMPTR(vp, sizeof(BITMAP16), pbm16);\
+ (lp)->bmType = FETCHSHORT(pbm16->bmType);\
+ (lp)->bmWidth = FETCHSHORT(pbm16->bmWidth);\
+ (lp)->bmHeight = FETCHSHORT(pbm16->bmHeight);\
+ (lp)->bmWidthBytes = FETCHSHORT(pbm16->bmWidthBytes);\
+ (lp)->bmPlanes = pbm16->bmPlanes;\
+ (lp)->bmBitsPixel = pbm16->bmBitsPixel;\
+ GETMISCPTR(pbm16->bmBits, (lp)->bmBits);\
+ FREEVDMPTR(pbm16);\
+ }
+
+
+#define PUTBITMAP16(vp,cb,lp) {\
+ PBITMAP16 pbm16;\
+ GETVDMPTR(vp, ((int)cb), pbm16);\
+ if (cb >= (FIELD_OFFSET(BITMAP16, bmType) + sizeof(pbm16->bmType)))\
+ STORESHORT(pbm16->bmType, (lp)->bmType);\
+ if (cb >= (FIELD_OFFSET(BITMAP16, bmWidth) + sizeof(pbm16->bmWidth)))\
+ STORESHORT(pbm16->bmWidth, (lp)->bmWidth);\
+ if (cb >= (FIELD_OFFSET(BITMAP16, bmHeight) + sizeof(pbm16->bmHeight)))\
+ STORESHORT(pbm16->bmHeight, (lp)->bmHeight);\
+ if (cb >= (FIELD_OFFSET(BITMAP16, bmWidthBytes) + sizeof(pbm16->bmWidthBytes)))\
+ STORESHORT(pbm16->bmWidthBytes, \
+ ((int)((((lp)->bmWidth * (lp)->bmBitsPixel + 15) / 16) * 2)));\
+ if (cb >= (FIELD_OFFSET(BITMAP16, bmPlanes) + sizeof(pbm16->bmPlanes)))\
+ pbm16->bmPlanes = (BYTE)(lp)->bmPlanes;\
+ if (cb >= (FIELD_OFFSET(BITMAP16, bmBitsPixel) + sizeof(pbm16->bmBitsPixel)))\
+ pbm16->bmBitsPixel = (BYTE)(lp)->bmBitsPixel;\
+ if (cb >= (FIELD_OFFSET(BITMAP16, bmBits) + sizeof(pbm16->bmBits)))\
+ pbm16->bmBits = (VPBYTE)NULL;\
+ FLUSHVDMPTR(vp, cb, pbm16);\
+ FREEVDMPTR(pbm16);\
+ }
+
+
+
+#define GETDCB16(vp,lp) // not implemented yet
+#define PUTDCB16(vp,lp) // not implemented yet
+#define PUTCOMSTAT16(vp,lp) // not implemented yet
+
+#define PUTSEGINFO16(vp,lp) // not implemented yet
+#define GETLOADPARMS16(vp,lp) // not implemented yet
+#define PUTOFSTRUCT16(vp,lp) // not implemented yet
+
+#define GETCATCHBUF16(vp,lp) // not implemented yet
+#define PUTCATCHBUF16(vp,lp) // not implemented yet
+
+
+#define GETLOGPEN16(vp, lp) {\
+ PLOGPEN16 plp16;\
+ GETVDMPTR(vp, sizeof(LOGPEN16), plp16);\
+ (lp)->lopnStyle = FETCHWORD(plp16->lopnStyle);\
+ (lp)->lopnWidth.x = FETCHSHORT(plp16->lopnWidth.x);\
+ (lp)->lopnColor = FETCHDWORD(plp16->lopnColor);\
+ FREEVDMPTR(plp16);\
+ }
+
+#define PUTLOGPEN16(vp,cb,lp) {\
+ PLOGPEN16 plp16;\
+ GETVDMPTR(vp, cb, plp16);\
+ if (cb >= 2)\
+ STOREWORD(plp16->lopnStyle, (lp)->lopnStyle);\
+ if (cb >= 4)\
+ STOREWORD(plp16->lopnWidth.x, (lp)->lopnWidth.x);\
+ if (cb >= 6)\
+ STOREWORD(plp16->lopnWidth.y, (lp)->lopnWidth.y);\
+ if (cb >= 10)\
+ STOREDWORD(plp16->lopnColor, (lp)->lopnColor);\
+ FLUSHVDMPTR(vp, cb, plp16);\
+ FREEVDMPTR(plp16);\
+ }
+
+
+#define GETLOGBRUSH16(vp,lp) {\
+ PLOGBRUSH16 plb16;\
+ WORD wStyle;\
+ GETVDMPTR(vp, sizeof(LOGBRUSH16), plb16);\
+ wStyle = FETCHWORD(plb16->lbStyle);\
+ (lp)->lbStyle = wStyle;\
+ (lp)->lbColor = FETCHDWORD(plb16->lbColor);\
+ if (wStyle == BS_PATTERN) { \
+ (lp)->lbHatch = (DWORD)HBITMAP32(FETCHWORD(plb16->lbHatch));\
+ } else { \
+ (lp)->lbHatch = FETCHWORD(plb16->lbHatch);\
+ } \
+ FREEVDMPTR(plb16);\
+ }
+#define PUTLOGBRUSH16(vp,cb,lp) {\
+ PLOGBRUSH16 plb16;\
+ GETVDMPTR(vp, cb, plb16);\
+ if (cb >= 2)\
+ STOREWORD(plb16->lbStyle, (lp)->lbStyle);\
+ if (cb >= 6)\
+ STOREDWORD(plb16->lbColor, (lp)->lbColor);\
+ if (cb >= 8){\
+ if( ((lp)->lbStyle == BS_PATTERN) || ((lp)->lbStyle == BS_DIBPATTERN)){\
+ STORESHORT(plb16->lbHatch, GETHBITMAP16((HAND32)(lp)->lbHatch));\
+ }\
+ else {\
+ STORESHORT(plb16->lbHatch, (lp)->lbHatch);\
+ }\
+ }\
+ FLUSHVDMPTR(vp, cb, plb16);\
+ FREEVDMPTR(plb16);\
+ }
+
+#define GETLOGFONT16(vp,p) getlogfont16(FETCHDWORD(vp), p)
+#define PUTLOGFONT16(vp,cb,p) putlogfont16(FETCHDWORD(vp), cb, p)
+#define PUTENUMLOGFONT16(vp,p) putenumlogfont16(FETCHDWORD(vp), p)
+
+#define PUTTEXTMETRIC16(vp,p) puttextmetric16(FETCHDWORD(vp), p)
+#define PUTNEWTEXTMETRIC16(vp,p) putnewtextmetric16(FETCHDWORD(vp), p)
+#define PUTOUTLINETEXTMETRIC16(vp,c,p) putoutlinetextmetric16(vp,c,p)
+
+#define GETLOGPALETTE16(vp,p) {\
+ INT cb;\
+ PLOGPALETTE16 plp16;\
+ GETVDMPTR(vp, sizeof(LOGPALETTE16), plp16);\
+ cb = FETCHWORD(plp16->palNumEntries);\
+ cb = sizeof(LOGPALETTE) + ((cb - 1) * sizeof(PALETTEENTRY));\
+ if( p=malloc_w(cb) )\
+ RtlCopyMemory(p,plp16,cb);\
+ FREEVDMPTR(plp16);\
+ }
+#define FREELOGPALETTE16(p) {if (p) free_w(p);}
+
+#define ALLOCPALETTEENTRY16(c,p) p=malloc_w(c*sizeof(PALETTEENTRY))
+#define GETPALETTEENTRY16(vp,c,p) getpaletteentry16(FETCHDWORD(vp), c, ALLOCPALETTEENTRY16(c, p))
+#define PUTPALETTEENTRY16(vp,c,p) putpaletteentry16(FETCHDWORD(vp), c, p)
+#define FREEPALETTEENTRY16(p) {if (p) free_w(p);}
+
+#define ALLOCHANDLETABLE16(c,p) p=malloc_w(c*sizeof(HANDLE))
+#define GETHANDLETABLE16(vp,c, p) gethandletable16(FETCHDWORD(vp), c, p)
+#define PUTHANDLETABLE16(vp,c, p) puthandletable16(FETCHDWORD(vp), c, p)
+#define FREEHANDLETABLE16(p) {if (p) free_w(p);}
+
+#define FREEDEVMODE32(p) {if (p) free_w(p);}
+
+#define GETCLIENTCREATESTRUCT16(vp,lp) { \
+ PCLIENTCREATESTRUCT16 pccs16;\
+ GETVDMPTR(vp, sizeof(CLIENTCREATESTRUCT16), pccs16);\
+ (lp)->hWindowMenu = HMENU32(FETCHWORD(pccs16->hWindowMenu));\
+ (lp)->idFirstChild = FETCHWORD(pccs16->idFirstChild);\
+ FREEVDMPTR(pccs16);\
+ }
+#define PUTCLIENTCREATESTRUCT16(vp,lp) { \
+ PCLIENTCREATESTRUCT16 pccs16;\
+ GETVDMPTR(vp, sizeof(CLIENTCREATESTRUCT16), pccs16);\
+ STOREWORD(pccs16->hWindowMenu, GETHMENU16((lp)->hWindowMenu));\
+ STOREWORD(pccs16->idFirstChild, (lp)->idFirstChild);\
+ }
+
+
+// following 2 for allocating a maximum sized BITMAPINFO structure from stack
+#define MAXDIBCOLORS 256 // for biBitCount == 8
+typedef struct _tagSTACKBMI32 {
+ BITMAPINFOHEADER bmiHeader;
+ RGBQUAD bmiColors[MAXDIBCOLORS];
+} STACKBMI32, *LPSTACKBMI32;
+
+
+/* Function prototypes
+ */
+VOID getstr16(VPSZ vpszSrc, LPSZ lpszDst, INT cb);
+VOID putstr16(VPSZ vpszDst, LPCSTR lpszSrc, INT cb);
+LPRECT getrect16(VPRECT16 vpRect, LPRECT lpRect);
+VOID putrect16(VPRECT16 vpRect, LPRECT lpRect);
+VOID getpoint16(VPPOINT16 vpPoint, INT c, LPPOINT lpPoint);
+VOID putpoint16(VPPOINT16 vpPoint, INT c, LPPOINT lpPoint);
+VOID getintarray16(VPINT16 vpInt, INT c, LPINT lpInt);
+VOID putintarray16(VPINT16 vpInt, INT c, LPINT lpInt);
+VOID getuintarray16(VPWORD vp, INT c, PUINT puint);
+VOID getdrawitem16(VPDRAWITEMSTRUCT16 vpDI16, LPDRAWITEMSTRUCT lpDI);
+VOID putdrawitem16(VPDRAWITEMSTRUCT16 vpDI16, LPDRAWITEMSTRUCT lpDI);
+VOID getmeasureitem16(VPMEASUREITEMSTRUCT16 vpMI16, LPMEASUREITEMSTRUCT lpMI, HWND16 hwnd16);
+VOID putmeasureitem16(VPMEASUREITEMSTRUCT16 vpMI16, LPMEASUREITEMSTRUCT lpMI);
+VOID getdeleteitem16(VPDELETEITEMSTRUCT16 vpDI16, LPDELETEITEMSTRUCT lpDI);
+VOID putdeleteitem16(VPDELETEITEMSTRUCT16 vpDI16, LPDELETEITEMSTRUCT lpDI);
+VOID getcompareitem16(VPCOMPAREITEMSTRUCT16 vpCI16, LPCOMPAREITEMSTRUCT lpCI);
+VOID putcompareitem16(VPCOMPAREITEMSTRUCT16 vpCI16, LPCOMPAREITEMSTRUCT lpCI);
+VOID getmsg16(VPMSG16 vpmsg16, LPMSG lpmsg, LPMSGPARAMEX lpmpex);
+ULONG putmsg16(VPMSG16 vpmsg16, LPMSG lpmsg);
+VOID getlogfont16(VPLOGFONT16 vplf, LPLOGFONT lplf);
+VOID putlogfont16(VPLOGFONT16 vplf, INT cb, LPLOGFONT lplf);
+VOID putenumlogfont16(VPENUMLOGFONT16 vpelf, LPENUMLOGFONT lpelf);
+VOID puttextmetric16(VPTEXTMETRIC16 vptm, LPTEXTMETRIC lptm);
+VOID putnewtextmetric16(VPNEWTEXTMETRIC16 vpntm, LPNEWTEXTMETRIC lpntm);
+VOID putoutlinetextmetric16(VPOUTLINETEXTMETRIC16 vpotm, INT cb, LPOUTLINETEXTMETRIC lpotm);
+VOID getlogpalette16(VPLOGPALETTE16 vplp, LPLOGPALETTE lplp);
+VOID getpaletteentry16(VPPALETTEENTRY16 vppe, INT c, LPPALETTEENTRY lpp);
+VOID putpaletteentry16(VPPALETTEENTRY16 vppe, INT c, LPPALETTEENTRY lpp);
+VOID gethandletable16(VPWORD vpht, UINT c, LPHANDLETABLE lpht);
+VOID puthandletable16(VPWORD vpht, UINT c, LPHANDLETABLE lpht);
+VOID putkerningpairs16(VPWORD vp, UINT cb, LPKERNINGPAIR lp);
+
+#ifdef NOTUSED
+BOOL getdropfilestruct16(HAND16 hand16, PHANDLE phand32);
+#endif
+INT GetBMI16Size(PVPVOID vpbmi16, WORD fuColorUse, LPDWORD lpdwClrUsed);
+INT GetBMI32Size(LPBITMAPINFO lpbmi32, WORD fuColorUse);
+LPBITMAPINFO CopyBMI16ToBMI32(PVPVOID vpbmi16, LPBITMAPINFO lpbmi32, WORD fuColorUse);
+LPBITMAPINFOHEADER CopyBMIH16ToBMIH32(PVPVOID vpbmih16, LPBITMAPINFOHEADER lpbmih);
+
+
+VOID getwindowpos16( VPWINDOWPOS16 vpwp, LPWINDOWPOS lpwp );
+VOID putwindowpos16( VPWINDOWPOS16 vpwp, LPWINDOWPOS lpwp );
+VOID W32CopyMsgStruct(VPMSG16 vpmsg16, LPMSG lpmsg, BOOL fThunk16To32);
+VOID getpaintstruct16(VPVOID vp, LPPAINTSTRUCT lp);
+VOID putpaintstruct16(VPVOID vp, LPPAINTSTRUCT lp);
+
+LPDEVMODE ThunkDevMode16to32(VPDEVMODE31 vpdm16);
+BOOL ThunkDevMode32to16(VPDEVMODE31 vpdm16, LPDEVMODE lpdm32, UINT nBytes);
+
+#endif // ifndef _DEF_WSTRUC_ THIS SHOULD BE THE LAST LINE IN THIS FILE
diff --git a/private/mvdm/wow32/wsubcls.c b/private/mvdm/wow32/wsubcls.c
new file mode 100644
index 000000000..89e333f6f
--- /dev/null
+++ b/private/mvdm/wow32/wsubcls.c
@@ -0,0 +1,587 @@
+//*****************************************************************************
+//
+// SUBCLASSING -
+//
+// Support for subclassing of 32bit standard (predefined) classes by
+// WOW apps.
+//
+//
+// 01-10-92 NanduriR Created.
+//
+//*****************************************************************************
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wsubcls.c);
+
+VPVOID vptwpFirst = (VPVOID)NULL;
+
+#ifdef OLD_SUBCLASS_STUFF
+
+THUNKWNDPROC vaStdClassThunkWindowProc[] = { {0, 0}, {0, 0}, {0, 0}, {0, 0},
+ {0, 0}, {0, 0}, {0, 0}, {0, 0},
+ {0, 0}, {0, 0}, {0, 0}, {0, 0},
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}
+ };
+
+
+
+//*****************************************************************************
+// GetStdClassThunkWindowProc -
+//
+// Returns the 16-bit thunk proc for all standard (predefined) window
+// classes. Each standard class has a separate unique 16bit thunk. We need
+// to callback to "getprocaddress" of the thunkproc.
+//
+// The classes are subclassed whenever any of the 'several' apis which
+// return a 'window proc' is called. ie. GetClassInfo, GetClassLong,
+// GetWindowLong, SetWindowLong...
+//
+// We will pass this address to a 16bit app, whenever it subclasses a
+// standard window. Since the thunk proc is a real 16bit callable function
+// the app can call this function directly.
+//
+// .i.e the apps that do the following sequence will work
+//
+// pfn = SetWindowLong(hwnd, GWL_WNDPROC, myproc);
+// ...
+// (*pfn)(hwnd, message, wParam, lParam);
+//
+// Needlesss to say, the following will definitely work.
+//
+// pfn = SetWindowLong(hwnd, GWL_WNDPROC, myproc);
+// ...
+// CallWindowProc(pfn, hwnd, message, wParam, lParam);
+//
+//
+// Infact the 16bit thunkproc, calls CallWindowProc with
+// pfn=its own address. How very logical!!!
+//
+// WU32CallWindowProc checks if the passed in 'pfn' is a 16bit thunk proc
+// of a standard calss. If so, special processing is done.
+//
+//*****************************************************************************
+
+DWORD GetStdClassThunkWindowProc(LPSTR lpstrClass, PWW pww, HANDLE h32)
+{
+ PARM16 Parm16;
+ WNDCLASS wndclass;
+ INT iClass;
+
+
+ // the input is either lpstrClass or pww. One of them is always NULL.
+
+ if (lpstrClass != NULL) {
+ iClass = GetStdClassNumber(lpstrClass);
+ }
+ else {
+ iClass = pww->iClass;
+ }
+
+ if (iClass == 0) {
+ LOGDEBUG(LOG_ALWAYS, ("WOW:GetStdClassThunkWindowProc: class unknown\n"));
+ return 0;
+ }
+
+ WOW32ASSERT(sizeof(vaStdClassThunkWindowProc) >
+ iClass * sizeof(vaStdClassThunkWindowProc[0]));
+
+
+ if (vaStdClassThunkWindowProc[iClass].Proc16 == (DWORD)NULL) {
+ switch (iClass) {
+ case WOWCLASS_BUTTON:
+ Parm16.SubClassProc.iOrdinal = FUN_BUTTONWNDPROC;
+ break;
+
+ case WOWCLASS_COMBOBOX:
+ Parm16.SubClassProc.iOrdinal = FUN_COMBOBOXCTLWNDPROC;
+ break;
+
+ case WOWCLASS_EDIT:
+ Parm16.SubClassProc.iOrdinal = FUN_EDITWNDPROC;
+ break;
+
+ case WOWCLASS_LISTBOX:
+ Parm16.SubClassProc.iOrdinal = FUN_LBOXCTLWNDPROC;
+ break;
+
+ case WOWCLASS_MDICLIENT:
+ Parm16.SubClassProc.iOrdinal = FUN_MDICLIENTWNDPROC;
+ break;
+
+ case WOWCLASS_SCROLLBAR:
+ Parm16.SubClassProc.iOrdinal = FUN_SBWNDPROC;
+ break;
+
+ case WOWCLASS_STATIC:
+ Parm16.SubClassProc.iOrdinal = FUN_STATICWNDPROC;
+ break;
+
+ case WOWCLASS_DESKTOP:
+ Parm16.SubClassProc.iOrdinal = FUN_DESKTOPWNDPROC;
+ break;
+
+ case WOWCLASS_DIALOG:
+ Parm16.SubClassProc.iOrdinal = FUN_DEFDLGPROC;
+ break;
+
+ case WOWCLASS_ICONTITLE:
+ Parm16.SubClassProc.iOrdinal = FUN_TITLEWNDPROC;
+ break;
+
+ case WOWCLASS_MENU:
+ Parm16.SubClassProc.iOrdinal = FUN_MENUWNDPROC;
+ break;
+
+ default:
+ Parm16.SubClassProc.iOrdinal = 0;
+ WOW32ASSERT(FALSE);
+ }
+
+ if (!CallBack16(RET_SUBCLASSPROC, &Parm16, (VPPROC)NULL,
+ (PVPVOID)&vaStdClassThunkWindowProc[iClass].Proc16)) {
+ WOW32ASSERT(FALSE);
+ }
+
+ if (lpstrClass == NULL) {
+
+ // Note: we avoid calling GetWindowLong(..GWL_WNDPROC)..
+ // Instead we call GetClassLong(..GCL_WNDPROC).. This way
+ // we don't need to check for possible recursion.
+ //
+
+ vaStdClassThunkWindowProc[iClass].Proc32 =
+ GetClassLong(h32, GCL_WNDPROC);
+ }
+ else {
+ GetClassInfo(NULL, lpstrClass, &wndclass);
+ vaStdClassThunkWindowProc[iClass].Proc32 =
+ (DWORD)wndclass.lpfnWndProc;
+
+ }
+
+
+
+
+ }
+
+ if (vaStdClassThunkWindowProc[iClass].Proc32 == (DWORD)NULL)
+ vaStdClassThunkWindowProc[iClass].Proc16 = (DWORD)NULL;
+
+ return vaStdClassThunkWindowProc[iClass].Proc16;
+}
+
+
+
+//*****************************************************************************
+// IsStdClassThunkWindowProc -
+//
+// Returns 'the corresponding 32bit proc' if the passed in 'Proc16' is
+// a 16bit standard class thunk proc.
+//
+// else NULL
+//
+//*****************************************************************************
+
+// DESCRIPTION OF THIS HACK CAN BE FOUND IN \wow16\user\wclass.asm
+
+DWORD IsStdClassThunkWindowProc(DWORD Proc16, PINT piClass) {
+ INT i;
+
+ for (i = 0; i < NUMEL(vaStdClassThunkWindowProc); i++) {
+ if (Proc16 == vaStdClassThunkWindowProc[i].Proc16) {
+ *piClass = i;
+ return vaStdClassThunkWindowProc[i].Proc32;
+ }
+ }
+
+ return (DWORD)NULL;
+}
+
+
+
+
+//*****************************************************************************
+// GetStdClass32WindowProc -
+//
+// Returns the 32bit WndProc given the class number.
+//
+// else NULL
+//
+//*****************************************************************************
+
+DWORD GetStdClass32WindowProc( INT iClass )
+{
+ if( iClass >= 0 && iClass < NUMEL(vaStdClassThunkWindowProc) ) {
+ WOW32ASSERT( vaStdClassThunkWindowProc[iClass].Proc32 != (DWORD)0 );
+ return vaStdClassThunkWindowProc[iClass].Proc32;
+ }
+ else {
+ return (DWORD)NULL;
+ }
+}
+#endif
+
+BOOL ConstructThunkWindowProc(
+ LPTWPLIST lptwp,
+ VPVOID vptwp
+) {
+/*
+** This is the code which would build a thunk window proc but since we already
+** have code like this laying around (button window proc thunk) we can just
+** copy it. This also saves us from having to know things like the DGROUP
+** of USER16, or the address of the 16-bit CallWindowProc function.
+**
+** lptwp->Code[0x00] = 0x45; inc bp
+** lptwp->Code[0x01] = 0x55; push bp
+** lptwp->Code[0x02] = 0x8B; mov bp,sp
+** lptwp->Code[0x03] = 0xEC;
+** lptwp->Code[0x04] = 0x1E; push ds
+** lptwp->Code[0x05] = 0xB8; mov ax,DGROUP
+** lptwp->Code[0x06] = LOBYTE(USER_DGROUP);
+** lptwp->Code[0x07] = HIBYTE(USER_DGROUP);
+** lptwp->Code[0x08] = 0x8E; mov ds,ax
+** lptwp->Code[0x09] = 0xD8;
+** lptwp->Code[0x0A] = 0xB8; mov ax,OFFSET BUTTONWNDPROC
+** lptwp->Code[0x0B] = LOBYTE(LOWORD(ThunkProc16));
+** lptwp->Code[0x0C] = HIBYTE(LOWORD(ThunkProc16));
+** lptwp->Code[0x0D] = 0xBA; mov dx,SEG BUTTONWNDPROC
+** lptwp->Code[0x0E] = LOBYTE(HIWORD(ThunkProc16));
+** lptwp->Code[0x0F] = HIBYTE(HIWORD(ThunkProc16));
+** lptwp->Code[0x10] = 0x52; push dx
+** lptwp->Code[0x11] = 0x50; push ax
+** lptwp->Code[0x12] = 0xFF; push WORD PTR [bp+14] ;hwnd
+** lptwp->Code[0x13] = 0x76;
+** lptwp->Code[0x14] = 0x0E;
+** lptwp->Code[0x15] = 0xFF; push WORD PTR [bp+12] ;messag
+** lptwp->Code[0x16] = 0x76;
+** lptwp->Code[0x17] = 0x0C;
+** lptwp->Code[0x18] = 0xFF; push WORD PTR [bp+10] ;wParam
+** lptwp->Code[0x19] = 0x76;
+** lptwp->Code[0x1A] = 0x0A;
+** lptwp->Code[0x1B] = 0xFF; push WORD PTR [bp+8]
+** lptwp->Code[0x1C] = 0x76;
+** lptwp->Code[0x1D] = 0x08;
+** lptwp->Code[0x1E] = 0xFF; push WORD PTR [bp+6] ;lParam
+** lptwp->Code[0x1F] = 0x76;
+** lptwp->Code[0x20] = 0x06;
+** lptwp->Code[0x21] = 0x9A; call FAR PTR CALLWINDOWPROC
+** lptwp->Code[0x22] = LOBYTE(LOWORD(CallWindowProc16));
+** lptwp->Code[0x23] = HIBYTE(LOWORD(CallWindowProc16));
+** lptwp->Code[0x24] = LOBYTE(HIWORD(CallWindowProc16));
+** lptwp->Code[0x25] = HIBYTE(HIWORD(CallWindowProc16));
+** lptwp->Code[0x26] = 0x4D; dec bp
+** lptwp->Code[0x27] = 0x4D; dec bp
+** lptwp->Code[0x28] = 0x8B; mov sp,bp
+** lptwp->Code[0x29] = 0xE5; dec bp
+** lptwp->Code[0x2A] = 0x1F; pop ds
+** lptwp->Code[0x2B] = 0x5D; pop bp
+** lptwp->Code[0x2C] = 0x4D; dec bp
+** lptwp->Code[0x2D] = 0xCA; ret 10
+** lptwp->Code[0x2E] = 0x0A;
+** lptwp->Code[0x2F] = 0x00;
+*/
+ VPVOID vpfn;
+ LPVOID lpfn;
+ VPVOID vpProc16;
+
+ /*
+ ** Get the proc address of the Button Window Proc thunk
+ */
+ vpfn = GetStdClassThunkProc( WOWCLASS_BUTTON );
+
+ if ( vpfn == (VPVOID)NULL ) {
+ return( FALSE );
+ }
+
+ /*
+ ** Now copy it into our thunk
+ */
+ GETVDMPTR( vpfn, THUNKWP_SIZE, lpfn);
+
+ RtlCopyMemory( lptwp->Code, lpfn, THUNKWP_SIZE );
+
+ FREEVDMPTR( lpfn );
+
+ /*
+ ** Patch the "our address" pointer
+ */
+ vpProc16 = (VPVOID)((DWORD)vptwp + FIELD_OFFSET(TWPLIST,Code[0]));
+
+ lptwp->Code[0x0B] = LOBYTE(LOWORD(vpProc16));
+ lptwp->Code[0x0C] = HIBYTE(LOWORD(vpProc16));
+ lptwp->Code[0x0E] = LOBYTE(HIWORD(vpProc16));
+ lptwp->Code[0x0F] = HIBYTE(HIWORD(vpProc16));
+
+ /*
+ ** Initialize the rest of the TWPLIST structure
+ */
+ lptwp->lpfn32 = 0;
+ lptwp->vpfn16 = vpProc16;
+ lptwp->vptwpNext = (VPVOID)NULL;
+ lptwp->hwnd32 = (HWND)0;
+ lptwp->dwMagic = SUBCLASS_MAGIC;
+
+ return( TRUE );
+}
+
+
+DWORD GetThunkWindowProc(
+ DWORD lpfn32,
+ LPSTR lpszClass,
+ PWW pww,
+ HWND hwnd32
+) {
+ VPVOID vptwp;
+ LPTWPLIST lptwp;
+ INT count;
+ DWORD dwResult;
+ BOOL fOk;
+ VPVOID vpAvail = (VPVOID)NULL;
+ INT iClass;
+
+ // the input is either lpstrClass or pww. One of them is always NULL.
+
+ if (lpszClass != NULL) {
+ iClass = GetStdClassNumber(lpszClass);
+ }
+ else {
+ iClass = pww->iClass;
+ }
+
+ if ( iClass == 0 ) {
+ DWORD dwpid;
+ LOGDEBUG(LOG_ALWAYS, ("WOW:GetThunkWindowProc: class unknown\n"));
+
+ // iClass == 0 implies that hwnd could either be a 32bit window
+ // belonging to a WOW process (like Ole windows) or a window of a
+ // different process. If it is the former return a stub proc
+ // else return 0;
+
+ if (!(GetWindowThreadProcessId(hwnd32,&dwpid) &&
+ (dwpid == GetCurrentProcessId()))){
+ return 0;
+ }
+ } else {
+ //
+ // If they are subclassing one of the standard classes, and they
+ // are doing it for the 1st time, then return the address of the
+ // hardcoded thunk in USER16.
+ //
+ if ( lpfn32 == (DWORD)GetStdClassWndProc(iClass) ) {
+ dwResult = GetStdClassThunkProc(iClass);
+ return( dwResult );
+ }
+ }
+
+
+ /*
+ ** Scan the list for available TWPLIST entries or duplicates
+ */
+ vptwp = vptwpFirst;
+
+ while ( vptwp != (VPVOID)NULL ) {
+
+ GETVDMPTR( vptwp, sizeof(TWPLIST), lptwp );
+
+ if ( lptwp->lpfn32 == 0 && vpAvail == (VPVOID)NULL ) {
+ vpAvail = vptwp;
+ }
+ //
+ // If we find that we've already subclassed this proc32
+ // then return that thunk proc again.
+ //
+ if ( lptwp->lpfn32 == lpfn32 ) {
+ dwResult = (DWORD)lptwp->vpfn16;
+ FREEVDMPTR( lptwp );
+ return( dwResult );
+ }
+
+ vptwp = lptwp->vptwpNext;
+
+ FREEVDMPTR( lptwp );
+
+ }
+
+ // Obviously we didn't find any duplicate if we got here.
+
+ // If we didn't find a slot to reuse, then allocate more.
+
+ if ( vpAvail == (VPVOID)NULL ) {
+ /*
+ ** No more available slots, allocate some more
+ */
+ vptwp = GlobalAllocLock16( GMEM_MOVEABLE,
+ THUNKWP_BLOCK * sizeof(TWPLIST),
+ NULL );
+
+ if ( vptwp == (VPVOID)NULL ) {
+ LOGDEBUG( 1, ("GetThunkWindowProc: GlobalAllocLock16 failed to allocate memory\n"));
+ return( (DWORD)NULL );
+ }
+
+ count = THUNKWP_BLOCK;
+
+ while ( count ) {
+ GETVDMPTR( vptwp, sizeof(TWPLIST), lptwp );
+
+ fOk = ConstructThunkWindowProc( lptwp, vptwp );
+
+ if ( fOk ) {
+ /*
+ ** Insert this thunk window proc into the list
+ */
+ lptwp->vptwpNext = vptwpFirst;
+ vptwpFirst = vptwp;
+ vpAvail = vptwp;
+ }
+
+ FLUSHVDMPTR( vptwp, sizeof(TWPLIST), lptwp );
+ FREEVDMPTR( lptwp );
+
+ vptwp = (VPVOID)((DWORD)vptwp + sizeof(TWPLIST));
+
+ --count;
+ }
+
+ ChangeSelector16( HIWORD(vptwp) ); // Change into a code selector
+
+ }
+
+ if ( vpAvail != (VPVOID)NULL ) {
+ /*
+ ** Use that available slot
+ */
+ GETVDMPTR( vpAvail, sizeof(TWPLIST), lptwp );
+ lptwp->lpfn32 = lpfn32;
+ lptwp->hwnd32 = hwnd32;
+ lptwp->iClass = iClass;
+
+ dwResult = (DWORD)lptwp->vpfn16;
+ FLUSHVDMCODEPTR(vpAvail, sizeof(TWPLIST), lptwp);
+ FREEVDMPTR( lptwp );
+
+ return( dwResult );
+ }
+
+ return( (DWORD)NULL );
+}
+
+
+#if 0 // Currently unused
+
+BOOL FreeThunkWindowProc(
+ DWORD vpProc16
+) {
+ VPVOID vptwp;
+ LPTWPLIST lptwp;
+
+ /*
+ ** Scan the list for available TWPLIST entries
+ */
+ vptwp = vptwpFirst;
+
+ while ( vptwp != (VPVOID)NULL ) {
+
+ GETVDMPTR( vptwp, sizeof(TWPLIST), lptwp );
+
+ if ( lptwp->vpfn16 == vpProc16 ) {
+ /*
+ ** Found slot to free
+ */
+ lptwp->lpfn32 = 0;
+ lptwp->hwnd32 = (HWND)0;
+ lptwp->iClass = WOWCLASS_UNKNOWN;
+ FREEVDMPTR( lptwp );
+ return( TRUE );
+ }
+
+ vptwp = lptwp->vptwpNext;
+
+ FREEVDMPTR( lptwp );
+ }
+
+ return( FALSE );
+}
+
+void W32FreeThunkWindowProc(
+ DWORD lpfn32,
+ DWORD lpfn16
+) {
+ VPVOID vptwp;
+ LPTWPLIST lptwp;
+
+ /*
+ ** Scan the list for available TWPLIST entries
+ */
+ vptwp = vptwpFirst;
+
+ while ( vptwp != (VPVOID)NULL ) {
+
+ GETVDMPTR( vptwp, sizeof(TWPLIST), lptwp );
+
+ if ( lptwp->lpfn32 == lpfn32 ) {
+ /*
+ ** Found slot to free
+ */
+ lptwp->lpfn32 = 0;
+ lptwp->hwnd32 = (HWND)0;
+ lptwp->iClass = WOWCLASS_UNKNOWN;
+ FREEVDMPTR( lptwp );
+ }
+
+ vptwp = lptwp->vptwpNext;
+
+ FREEVDMPTR( lptwp );
+ }
+}
+#endif
+
+DWORD IsThunkWindowProc(
+ DWORD vpProc16, // IN
+ PINT piClass // OUT OPTIONAL
+) {
+ VPVOID vpdw;
+ DWORD UNALIGNED * lpdw;
+ DWORD dwResult;
+ INT iClass;
+
+ /* Screen for valid addresses... */
+
+ if ( (HIWORD(vpProc16) == 0) || (LOWORD(vpProc16) < (sizeof(DWORD)*3)) ) {
+ return( 0 );
+ }
+
+ /*
+ ** If it is a valid sub-class thunk, then it should be preceeded by
+ ** three dword values. The first is the subclassing magic number,
+ ** the second is the WOWCLASS_*, the 3rd is the 32-bit proc address.
+ */
+ vpdw = (VPVOID)((DWORD)vpProc16 - sizeof(DWORD)*3);
+
+ GETVDMPTR( vpdw, sizeof(DWORD)*3, lpdw );
+
+ iClass = (INT)*(lpdw+1);
+
+ dwResult = *(lpdw+2); // Get the lpfn32 value
+
+ if ( *lpdw != SUBCLASS_MAGIC ) {
+ dwResult = 0; // Zero it if it wasn't valid
+ iClass = WOWCLASS_UNKNOWN;
+ } else {
+ if ( dwResult == 0 ) {
+ WOW32ASSERT( iClass != WOWCLASS_UNKNOWN );
+ // They cheated and looked up the export from USER.EXE
+ dwResult = (DWORD) GetStdClassWndProc( iClass );
+ }
+ }
+
+ if (piClass) {
+ *piClass = iClass;
+ }
+
+ FREEVDMPTR( lpdw );
+
+ return( dwResult );
+}
diff --git a/private/mvdm/wow32/wsubcls.h b/private/mvdm/wow32/wsubcls.h
new file mode 100644
index 000000000..cbbe82f57
--- /dev/null
+++ b/private/mvdm/wow32/wsubcls.h
@@ -0,0 +1,41 @@
+//*****************************************************************************
+//
+// SUBCLASSING -
+//
+// Support for subclassing of 32bit standard (predefined) classes by
+// WOW apps.
+//
+//
+// 01-10-92 NanduriR Created.
+//
+//*****************************************************************************
+
+
+typedef struct {
+ DWORD Proc16;
+ DWORD Proc32;
+} THUNKWNDPROC, FAR *LPTHUNKWNDPROC;
+
+DWORD GetStdClassThunkWindowProc(LPSTR lpstrClass, PWW pww, HANDLE h32);
+DWORD IsStdClassThunkWindowProc(DWORD Proc16, PINT piClass);
+DWORD GetStdClass32WindowProc( INT iWOWClass ) ;
+
+#define THUNKWP_SIZE 0x30 /* Code size of a thunk */
+#define THUNKWP_BLOCK ((INT)(4096 / sizeof(TWPLIST))) /* Number of thunks per block */
+
+typedef struct _twpList {
+ VPVOID vpfn16; /* 16-bit proc address */
+ VPVOID vptwpNext; /* Pointer to next proc in the list */
+ HWND hwnd32; /* 32-bit window handle */
+ DWORD dwMagic; /* Magic identifier */
+ INT iClass; /* Class of original proc */
+ DWORD lpfn32; /* 32-bit proc address, 0 means available */
+ BYTE Code[THUNKWP_SIZE]; /* Code for the thunk */
+} TWPLIST, *LPTWPLIST;
+
+#define SUBCLASS_MAGIC 0x534C4353 /* "SCLS" Sub-Class magic value */
+
+DWORD GetThunkWindowProc( DWORD Proc32, LPSTR lpszClass, PWW pww, HWND hwnd32 );
+BOOL FreeThunkWindowProc( DWORD Proc16 );
+void W32FreeThunkWindowProc( DWORD Proc32, DWORD Proc16 );
+DWORD IsThunkWindowProc( DWORD Proc16, PINT piClass );
diff --git a/private/mvdm/wow32/wthman.c b/private/mvdm/wow32/wthman.c
new file mode 100644
index 000000000..5bd489e72
--- /dev/null
+++ b/private/mvdm/wow32/wthman.c
@@ -0,0 +1,20 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WTHMAN.H
+ * WOW32 16-bit ToolHelp API support (manually-coded thunks for
+ * unimplemented 16-bit APIs).
+ *
+ * History:
+ * 12-Nov-92 davehart Created using wkman.c as template
+ *
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wthman.c);
+
diff --git a/private/mvdm/wow32/wthman.h b/private/mvdm/wow32/wthman.h
new file mode 100644
index 000000000..a9aa10bdd
--- /dev/null
+++ b/private/mvdm/wow32/wthman.h
@@ -0,0 +1,15 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WTHMAN.H
+ * WOW32 16-bit ToolHelp API support (manually-coded thunks for
+ * unimplemented 16-bit APIs).
+ *
+ * History:
+ * 12-Nov-92 davehart Created using wkman.h as template
+ *
+--*/
+
diff --git a/private/mvdm/wow32/wthtbl.h b/private/mvdm/wow32/wthtbl.h
new file mode 100644
index 000000000..8ed69201d
--- /dev/null
+++ b/private/mvdm/wow32/wthtbl.h
@@ -0,0 +1,24 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WKTBL.H
+ * WOW32 16-bit Kernel API tables
+ *
+ * History:
+ * Created 12-Nov-1992 by Dave Hart (davehart) using wktbl.h as template
+ *
+--*/
+
+
+
+/* ToolHelp dispatch table
+ */
+extern W32 aw32ToolHelp[];
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iToolHelpMax;
+#endif
diff --git a/private/mvdm/wow32/wthtbl2.h b/private/mvdm/wow32/wthtbl2.h
new file mode 100644
index 000000000..9201e6979
--- /dev/null
+++ b/private/mvdm/wow32/wthtbl2.h
@@ -0,0 +1,16 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WTHTBL2.h
+ * WOW32 16-bit toolhelp API thunk table
+ *
+ * This file is included into the master thunk table.
+ *
+--*/
+
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_TOOLHELP, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "CLASSFIRST", MOD_TOOLHELP, sizeof (CLASSFIRST16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "CLASSNEXT", MOD_TOOLHELP, sizeof (CLASSNEXT16))},
diff --git a/private/mvdm/wow32/wuansi.h b/private/mvdm/wow32/wuansi.h
new file mode 100644
index 000000000..2b4e3c2af
--- /dev/null
+++ b/private/mvdm/wow32/wuansi.h
@@ -0,0 +1,23 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUANSI.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+/*
+
+ULONG FASTCALL WU32AnsiLower(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnsiLowerBuff(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnsiNext(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnsiPrev(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnsiUpper(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnsiUpperBuff(PVDMFRAME pFrame);
+
+*/
diff --git a/private/mvdm/wow32/wucaret.c b/private/mvdm/wow32/wucaret.c
new file mode 100644
index 000000000..694fca8a5
--- /dev/null
+++ b/private/mvdm/wow32/wucaret.c
@@ -0,0 +1,336 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUCARET.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wucaret.c);
+
+
+/*++
+ void CreateCaret(<hwnd>, <hBitmap>, <nWidth>, <nHeight>)
+ HWND <hwnd>;
+ BITMAP <hBitmap>;
+ int <nWidth>;
+ int <nHeight>;
+
+ The %CreateCaret% function creates a new shape for the system caret and
+ assigns ownership of the caret to the given window. The caret shape can be a
+ line, block, or bitmap as defined by the <hBitmap> parameter. If <hBitmap>
+ is a bitmap handle, the <nWidth> and <nHeight> parameters are ignored; the
+ bitmap defines its own width and height. (The bitmap handle must have been
+ previously created by using the %CreateBitmap%, %CreateDIBitmap%, or
+ %LoadBitmap% function.) If <hBitmap> is NULL or 1, <nWidth> and <nHeight>
+ give the caret's width and height (in logical units); the exact width and
+ height (in pixels) depend on the window's mapping mode.
+
+ If <nWidth> or <nHeight> is zero, the caret width or height is set to the
+ system's window-border width or height. Using the window-border width or
+ height guarantees that the caret will be visible on a high-resolution
+ display.
+
+ The %CreateCaret% function automatically destroys the previous caret shape,
+ if any, regardless of which window owns the caret. Once created, the caret
+ is initially hidden. To show the caret, the %ShowCaret% function must be
+ called.
+
+ <hwnd>
+ Identifies the window that owns the new caret.
+
+ <hBitmap>
+ Identifies the bitmap that defines the caret shape. If
+ <hBitmap> is NULL, the caret is solid; if <hBitmap> is 1, the caret is
+ gray.
+
+ <nWidth>
+ Specifies the width of the caret (in logical units).
+
+ <nHeight>
+ Specifies the height of the caret (in logical units).
+
+ This function does not return a value.
+
+ The system caret is a shared resource. A window should create a caret only
+ when it has the input focus or is active. It should destroy the caret before
+ losing the input focus or becoming inactive.
+
+ The system's window-border width or height can be retrieved by using the
+ %GetSystemMetrics% function with the SM_CXBORDER and SM_CYBORDER indexes.
+--*/
+
+ULONG FASTCALL WU32CreateCaret(PVDMFRAME pFrame)
+{
+ register PCREATECARET16 parg16;
+ HANDLE h32;
+
+ GETARGPTR(pFrame, sizeof(CREATECARET16), parg16);
+
+ h32 = (HANDLE)parg16->f2;
+
+ // 0 -> caret is solid, 1 -> caret is gray, otherwise it's an hBitmap
+ if(((DWORD)h32) > 1) {
+ h32 = HBITMAP32(h32);
+ }
+
+ CreateCaret(HWND32(parg16->f1), h32, INT32(parg16->f3), INT32(parg16->f4));
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ void DestroyCaret(VOID)
+
+ The %DestroyCaret% function destroys the current caret shape, frees the
+ caret from the window that currently owns it, and removes the caret from the
+ screen if it is visible. The %DestroyCaret% function checks the ownership of
+ the caret and destroys the caret only if a window in the current task owns
+ it.
+
+ If the caret shape was previously a bitmap, %DestroyCaret% does not free the
+ bitmap.
+
+ This function has no parameters.
+
+ This function does not return a value.
+
+ The caret is a shared resource. If a window has created a caret shape, it
+ destroys that shape before it loses the input focus or becomes inactive.
+--*/
+
+ULONG FASTCALL WU32DestroyCaret(PVDMFRAME pFrame)
+{
+ UNREFERENCED_PARAMETER(pFrame);
+
+ DestroyCaret();
+
+ RETURN(0);
+}
+
+
+/*++
+ WORD GetCaretBlinkTime(VOID)
+
+ The %GetCaretBlinkTime% function retrieves the caret blink rate. The blink
+ rate is the elapsed time in milliseconds between flashes of the caret.
+
+ This function has no parameters.
+
+ The return value specifies the blink rate (in milliseconds).
+--*/
+
+ULONG FASTCALL WU32GetCaretBlinkTime(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETWORD16(GetCaretBlinkTime());
+
+ RETURN(ul);
+}
+
+
+/*++
+ void GetCaretPos(<lpPoint>)
+ LPPOINT <lpPoint>;
+
+ The %GetCaretPos% function retrieves the caret's current position (in screen
+ coordinates), and copies them to the %POINT% structure pointed to by the
+ <lpPoint> parameter.
+
+ <lpPoint>
+ Points to the %POINT% structure that is to receive the screen coordinates
+ of the caret.
+
+ This function does not return a value.
+
+ The caret position is always given in the client coordinates of the window
+ that contains the caret.
+--*/
+
+ULONG FASTCALL WU32GetCaretPos(PVDMFRAME pFrame)
+{
+ POINT t1;
+ register PGETCARETPOS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCARETPOS16), parg16);
+
+ GetCaretPos(
+ &t1
+ );
+
+ PUTPOINT16(parg16->f1, &t1);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ void HideCaret(<hwnd>)
+ HWND <hwnd>;
+
+ The %HideCaret% function hides the caret by removing it from the display
+ screen. Although the caret is no longer visible, it can be displayed again
+ by using the %ShowCaret% function. Hiding the caret does not destroy its
+ current shape.
+
+ The %HideCaret% function hides the caret only if the given window owns the
+ caret. If the <hwnd> parameter is NULL, the function hides the caret only if
+ a window in the current task owns the caret.
+
+ Hiding is cumulative. If %HideCaret% has been called five times in a row,
+ %ShowCaret% must be called five times before the caret will be shown.
+
+ <hwnd>
+ Identifies the window that owns the caret, or it is NULL to indirectly
+ specify the window in the current task that owns the caret.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32HideCaret(PVDMFRAME pFrame)
+{
+ register PHIDECARET16 parg16;
+
+ GETARGPTR(pFrame, sizeof(HIDECARET16), parg16);
+
+ HideCaret(
+ HWND32(parg16->f1)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ void SetCaretBlinkTime(<wMSeconds>)
+ WORD <wMSeconds>;
+
+ The %SetCaretBlinkTime% function sets the caret blink rate (elapsed time
+ between caret flashes) to the number of milliseconds specified by the
+ <wMSeconds> parameter. The caret flashes on or off each <wMSeconds>
+ milliseconds. This means one complete flash (on-off-on) takes 2 x
+ <wMSeconds> milliseconds.
+
+ <wMSeconds>
+ Specifies the new blink rate (in milliseconds).
+
+ This function does not return a value.
+
+ The caret is a shared resource. A window should set the caret blink rate
+ only if it owns the caret. It should restore the previous rate before it
+ loses the input focus or becomes inactive.
+--*/
+
+ULONG FASTCALL WU32SetCaretBlinkTime(PVDMFRAME pFrame)
+{
+ register PSETCARETBLINKTIME16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCARETBLINKTIME16), parg16);
+
+ SetCaretBlinkTime(
+ WORD32(parg16->f1)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ void SetCaretPos(<X>, <Y>)
+ int <X>;
+ int <Y>;
+
+ The %SetCaretPos% function moves the caret to the position given by logical
+ coordinates specified by the <X> and <Y> parameters. Logical coordinates are
+ relative to the client area of the window that owns them and are affected by
+ the window's mapping mode, so the exact position in pixels depends on this
+ mapping mode.
+
+ The %SetCaretPos% function moves the caret only if it is owned by a window
+ in the current task. %SetCaretPos% moves the caret whether or not the caret
+ is hidden.
+
+ <X>
+ Specifies the new x-coordinate (in logical coordinates) of the caret.
+
+ <Y>
+ Specifies the new <y>-coordinate (in logical coordinates) of the
+ caret.
+
+ This function does not return a value.
+
+ The caret is a shared resource. A window should not move the caret if it
+ does not own the caret.
+--*/
+
+ULONG FASTCALL WU32SetCaretPos(PVDMFRAME pFrame)
+{
+ register PSETCARETPOS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCARETPOS16), parg16);
+
+ SetCaretPos(
+ INT32(parg16->f1),
+ INT32(parg16->f2)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ void ShowCaret(<hwnd>)
+
+ The %ShowCaret% function shows the caret on the display at the caret's
+ current position. Once shown, the caret begins flashing automatically.
+
+ The %ShowCaret% function shows the caret only if it has a current shape and
+ has not been hidden two or more times in a row. If the caret is not owned by
+ the given window, the caret is not shown. If the <hwnd> parameter is NULL,
+ the %ShowCaret% function shows the caret only if it is owned by a window in
+ the current task.
+
+ Hiding the caret is accumulative. If the %HideCaret% function has been
+ called five times in a row, %ShowCaret% must be called five times to show
+ the caret.
+
+ <hwnd>
+ Identifies the window that owns the caret, or is NULL to specify
+ indirectly the owner window in the current task.
+
+ This function does not return a value.
+
+ The caret is a shared resource. A window should show the caret only when it
+ has the input focus or is active.
+--*/
+
+ULONG FASTCALL WU32ShowCaret(PVDMFRAME pFrame)
+{
+ register PSHOWCARET16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SHOWCARET16), parg16);
+
+ ShowCaret(
+ HWND32(parg16->f1)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
diff --git a/private/mvdm/wow32/wucaret.h b/private/mvdm/wow32/wucaret.h
new file mode 100644
index 000000000..e2ccf8b24
--- /dev/null
+++ b/private/mvdm/wow32/wucaret.h
@@ -0,0 +1,23 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUCARET.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WU32CreateCaret(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DestroyCaret(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetCaretBlinkTime(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetCaretPos(PVDMFRAME pFrame);
+ULONG FASTCALL WU32HideCaret(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetCaretBlinkTime(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetCaretPos(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ShowCaret(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wuclass.c b/private/mvdm/wow32/wuclass.c
new file mode 100644
index 000000000..c40e1cb40
--- /dev/null
+++ b/private/mvdm/wow32/wuclass.c
@@ -0,0 +1,1052 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUCLASS.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wuclass.c);
+
+extern HANDLE ghInstanceUser32;
+extern WORD gUser16hInstance;
+
+/*++
+ BOOL GetClassInfo(<hInstance>, <lpClassName>, <lpWndClass>)
+ HANDLE <hInstance>;
+ LPSTR <lpClassName>;
+ LPWNDCLASS <lpWndClass>;
+
+ The %GetClassInfo% function retrieves information about a window class. The
+ <hInstance> parameter identifies the instance of the application that
+ created the class, and the <lpClassName> parameter identifies the window
+ class. If the function locates the specified window class, it copies the
+ %WNDCLASS% data used to register the window class to the %WNDCLASS%
+ structure pointed to by the <lpWndClass> parameter.
+
+ <hInstance>
+ Identifies the instance of the application that created the class. To
+ retrieve information on classes defined by Windows (such as buttons or
+ list boxes), set hInstance to NULL.
+
+ <lpClassName>
+ Points to a null-terminated string that contains the name of the
+ class to find. If the high-order word of this parameter is NULL, the
+ low-order word is assumed to be a value returned by the
+ %MAKEINTRESOURCE% macro used when the class was created.
+
+ <lpWndClass>
+ Points to the %WNDCLASS% structure that will receive the class
+ information.
+
+ The return value is TRUE if the function found a matching class and
+ successfully copied the data; the return value is FALSE if the function did
+ not find a matching class.
+
+ The %lpszClassName%, %lpszMenuName%, and %hInstance% members of the
+ %WNDCLASS% structure are <not> set by this function. The menu name is
+ not stored internally and cannot be returned. The class name is already
+ known since it is passed to this function. The %GetClassInfo% function
+ returns all other fields with the values used when the class was
+ registered.
+--*/
+
+ULONG FASTCALL WU32GetClassInfo(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2, pszClass;
+ WNDCLASS t3;
+ register PGETCLASSINFO16 parg16;
+ WORD w;
+ HINSTANCE hInst;
+ PWC pwc = NULL;
+ PWNDCLASS16 pwc16;
+ CHAR szAtomName[WOWCLASS_ATOM_NAME];
+
+ GETARGPTR(pFrame, sizeof(GETCLASSINFO16), parg16);
+ GETPSZIDPTR(parg16->f2, psz2);
+
+ if ( HIWORD(psz2) == 0 ) {
+ pszClass = szAtomName;
+ GetAtomName( (ATOM)psz2, pszClass, WOWCLASS_ATOM_NAME );
+ } else {
+ pszClass = psz2;
+ }
+
+ // map hInst user16 to hMod user32
+ if(parg16->f1 == gUser16hInstance) {
+ hInst = ghInstanceUser32;
+ }
+ else {
+ hInst = HMODINST32(parg16->f1);
+ }
+
+ ul = GETBOOL16(GetClassInfo(hInst, pszClass, &t3));
+
+ // This fine piece of hackery mimicks the difference between the class list
+ // search algorithms in Win3.1 & SUR. Essentially SUR checks the private,
+ // public, and global class lists while Win3.1 only checks the private and
+ // global lists. Note we are striving for Win3.1 compatibility here -- not
+ // always the logical thing! Finding an existing *stale* class breaks some
+ // apps! Bug #31269 a-craigj, GerardoB
+ // Restrict this hack to PageMaker 50a for now
+ if(CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_FAKECLASSINFOFAIL) {
+ if(ul && hInst) {
+
+ // if this class wasn't registered by this app, AND it's not a global
+ // class, then it must have come from the public list and this app
+ // wouldn't know about it on Win3.1 -- so lie and say it doesn't exist!
+ // Note: The high word is the *hModule* which is what Win3.1 AND NT save
+ // with the class internally (not the hInstance!)
+ if((HIWORD(t3.hInstance) != HIWORD(hInst)) && !(t3.style & CS_GLOBALCLASS)) {
+ WOW32WARNMSGF(0,("\nWOW:GetClassInfo force failure hack:\n class = '%s' wc.hInstance = %X app_hInst = %X\n\n", pszClass, t3.hInstance, hInst));
+ ul = 0;
+ }
+ }
+ }
+
+ if (ul) {
+
+ //
+ // If the class is a 'standard' class, replace the class proc
+ // with a thunk proc
+ //
+
+ GETVDMPTR(parg16->f3, sizeof(WNDCLASS16), pwc16);
+ STOREWORD(pwc16->style, t3.style);
+ if (!_stricmp(pszClass, "edit")) {
+ STOREWORD(pwc16->style, (FETCHWORD(pwc16->style) & ~CS_GLOBALCLASS));
+ }
+
+ STOREDWORD(pwc16->vpfnWndProc, 0);
+
+ // if this class was registered by WOW
+ if ( (DWORD)t3.lpfnWndProc & WNDPROC_WOW ) {
+ pwc16->vpfnWndProc = (VPWNDPROC)((DWORD)t3.lpfnWndProc & WNDPROC_MASK);
+
+ //
+ // if the actual selector had the high bit on then we turned off
+ // bit 2 of the selector (the LDT bit, which will always be on)
+ //
+
+ if (!((DWORD)pwc16->vpfnWndProc & WOWCLASS_VIRTUAL_NOT_BIT31)) {
+ pwc16->vpfnWndProc |= (WNDPROC_WOW | WOWCLASS_VIRTUAL_NOT_BIT31);
+ }
+
+ // we need to subtract out our WOW DWORDS for WOW classes
+ // (see GCW_CBCLSEXTRA notes in RegisterClass())
+ STORESHORT(pwc16->cbClsExtra, t3.cbClsExtra - (2 * sizeof(DWORD)));
+
+ } else {
+ pwc16->vpfnWndProc = GetThunkWindowProc((DWORD)t3.lpfnWndProc, pszClass, NULL, NULL);
+ STORESHORT(pwc16->cbClsExtra, t3.cbClsExtra);
+ }
+
+#ifdef OLD_WAY
+ if (parg16->f1 ||
+ !(pwc16->vpfnWndProc = GetThunkWindowProc((DWORD)t3.lpfnWndProc, pszClass, NULL, NULL))) {
+
+ pwc = FindClass16(pszClass, (HINST16)parg16->f1);
+ STOREDWORD(pwc16->vpfnWndProc, pwc->vpfnWndProc);
+ }
+#endif
+
+ STORESHORT(pwc16->cbWndExtra, t3.cbWndExtra);
+
+ // Win3.1 copies the hInst passed in by the app into the WNDCLASS struct
+ // unless hInst == NULL, in which case they copy user's hInst
+ if((!parg16->f1) || (t3.hInstance == ghInstanceUser32)) {
+ w = gUser16hInstance;
+ } else {
+ w = VALIDHMOD(t3.hInstance);
+ if(w != BOGUSGDT) {
+ w = parg16->f1;
+ }
+ }
+ STOREWORD(pwc16->hInstance, w);
+ w = GETHICON16(t3.hIcon); STOREWORD(pwc16->hIcon, w);
+ w = GETHCURSOR16(t3.hCursor); STOREWORD(pwc16->hCursor, w);
+ w = ((ULONG)t3.hbrBackground > COLOR_ENDCOLORS) ?
+ GETHBRUSH16(t3.hbrBackground) : (WORD)t3.hbrBackground;
+ STOREWORD(pwc16->hbrBackground, w);
+
+ // These are strange assignments. We don't keep the class name or
+ // menu name in 16-bit memory. For class name, USER32 just returns
+ // the value which is passed as the second parameter, which works
+ // MOST of the time; we do the same. For the menu name, USER32 just
+ // returns the value which was passed when the class was registered.
+ // There are some situations where these psz's might go out of scope
+ // and no longer be valid when the application attempts to use them.
+ // IF YOU EVER FIND AN APPLICATION WHICH GETS THE WRONG
+ // THING AND IT FAILS BECAUSE OF IT, SOME NASTY HACKING WILL HAVE
+ // TO BE DONE AND IT SHOULD BE DONE IN USER32 ALSO...
+ // -BobDay
+ //
+ if ( pwc = FindClass16(pszClass, (HINST16)parg16->f1)) {
+ STOREDWORD(pwc16->vpszMenuName, pwc->vpszMenu);
+ } else {
+ STOREDWORD(pwc16->vpszMenuName, 0 );
+ }
+
+ STOREDWORD(pwc16->vpszClassName, parg16->f2);
+
+ FLUSHVDMPTR(parg16->f3, sizeof(WNDCLASS16), pwc16);
+ FREEVDMPTR(pwc16);
+ }
+ FREEPSZIDPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ LONG GetClassLong(<hwnd>, <nIndex>)
+ HWND <hwnd>;
+ int <nIndex>;
+
+ The %GetClassLong% function retrieves the long value specified by the
+ <nIndex> parameter from the %WNDCLASS% structure of the window specified by
+ the <hwnd> parameter.
+
+ <hwnd>
+ Identifies the window.
+
+ <nIndex>
+ Specifies the byte offset of the value to be retrieved. It can also
+ be the following value:
+
+ GCL_WNDPROC
+ Retrieves a long pointer to the window function.
+ GCL_MENUNAME
+ Retrieves a long pointer to the menu name.
+
+ The return value specifies the value retrieved from the %WNDCLASS%
+ structure.
+
+ To access any extra four-byte values allocated when the window-class
+ structure was created, use a positive byte offset as the index specified by
+ the <nIndex> parameter. The first four-byte value in the extra space is at
+ offset zero, the next four-byte value is at offset 4, and so on.
+--*/
+
+ULONG FASTCALL WU32GetClassLong(PVDMFRAME pFrame)
+{
+ ULONG ul, flag;
+ INT iOffset;
+ HWND hwnd;
+ register PWW pww;
+ register PWC pwc;
+ register PGETCLASSLONG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCLASSLONG16), parg16);
+
+ // Make sure Win32 didn't change offsets for GCL constants
+
+#if (GCL_WNDPROC != (-24) || GCL_MENUNAME != (-8))
+#error Win16/Win32 GCL constants differ
+#endif
+
+ // Make sure the 16-bit app is requesting allowable offsets
+
+ iOffset = INT32(parg16->f2);
+ WOW32ASSERT(iOffset >= 0 ||
+ iOffset == GCL_WNDPROC ||
+ iOffset == GCL_MENUNAME);
+
+ hwnd = HWND32(parg16->f1);
+
+ switch (iOffset) {
+ case GCL_WNDPROC:
+ {
+ DWORD dwProc32;
+
+ dwProc32 = GetClassLong(hwnd, iOffset);
+
+ if ( dwProc32 & WNDPROC_WOW ) {
+ if ( HIWORD(dwProc32) == WNDPROC_HANDLE ) {
+ //
+ // Class has a window proc which is really a handle
+ // to a proc. This happens when there is some
+ // unicode to ansi transition or vice versa.
+ //
+ pww = FindPWW( hwnd, WOWCLASS_UNKNOWN);
+ if ( pww == NULL ) {
+ ul = 0;
+ } else {
+ ul = GetThunkWindowProc(dwProc32,NULL,pww,hwnd);
+ }
+ } else {
+ //
+ // Class already has a 16:16 address
+ //
+ ul = dwProc32 & WNDPROC_MASK;
+
+ //
+ // if the actual selector had the high bit on then we turned off
+ // bit 2 of the selector (the LDT bit, which will always be on)
+ //
+ if (!(ul & WOWCLASS_VIRTUAL_NOT_BIT31)) {
+ ul |= (WNDPROC_WOW | WOWCLASS_VIRTUAL_NOT_BIT31);
+ }
+ }
+ } else {
+ //
+ // Class has a 32-bit proc, return an allocated thunk
+ //
+ pww = FindPWW(hwnd, WOWCLASS_UNKNOWN);
+ if ( pww == NULL ) {
+ ul = 0;
+ } else {
+ ul = GetThunkWindowProc(dwProc32,NULL,pww,hwnd);
+ }
+ }
+ }
+ break;
+
+ case GCL_MENUNAME:
+ if ((pww = FindPWW(hwnd, WOWCLASS_UNKNOWN)) &&
+ (WOWCLASS_WIN16 == pww->iClass) &&
+ (pwc = FindPWC(hwnd))) {
+ ul = pwc->vpszMenu;
+ } else {
+ ul = 0;
+ }
+ break;
+
+ case GCL_CBCLSEXTRA:
+ ul = GetClassLong(hwnd, GCL_CBCLSEXTRA);
+
+ // verify that this class was registered by WOW
+ // (see GCW_CBCLSEXTRA notes in thunk for RegisterClass())
+ if(GetClassLong(hwnd, GCL_WNDPROC) & WNDPROC_WOW) {
+
+ // get the bozo flag
+ iOffset = ul - sizeof(DWORD);
+ flag = GetClassLong(hwnd, iOffset);
+
+ // if bozo app flag is set, get the value the app saved
+ // otherwise good little apps get cbClsExtra
+ if(flag) {
+ iOffset -= sizeof(DWORD);
+ ul = GetClassLong(hwnd, iOffset);
+ }
+ else {
+ ul -= (2 * sizeof(DWORD)); // account for our WOW DWORDs
+ }
+ }
+ break;
+
+ default:
+ ul = GetClassLong(hwnd, iOffset);
+ break;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ WORD GetClassWord(<hwnd>, <nIndex>)
+ HWND <hwnd>;
+ int <nIndex>;
+
+ The %GetClassWord% function retrieves the word that is specified by the
+ <nIndex> parameter from the %WNDCLASS% structure of the window specified by
+ the <hwnd> parameter.
+
+ <hwnd>
+ Identifies the window.
+
+ <nIndex>
+ Specifies the byte offset of the value to be retrieved. It can also
+ be one of the following values:
+
+ GCL_CBCLSEXTRA
+ Tells how many bytes of additional class information you have. For
+ information on how to access this memory, see the following "Comments"
+ section.
+
+ GCL_CBWNDEXTRA
+ Tells how many bytes of additional window information you have. For
+ information on how to access this memory, see the following<>Comments
+ section.
+
+ GCL_HBRBACKGROUND
+ Retrieves a handle to the background brush.
+
+ GCL_HCURSOR
+ Retrieves a handle to the cursor.
+
+ GCL_HICON
+ Retrieves a handle to the icon.
+
+ GCL_HMODULE
+ Retrieves a handle to the module.
+
+ GCL_STYLE
+ Retrieves the window-class style bits.
+
+ The return value specifies the value retrieved from the %WNDCLASS%
+ structure.
+
+ To access any extra two-byte values allocated when the window-class
+ structure was created, use a positive byte offset as the index specified by
+ the <nIndex> parameter, starting at zero for the first two-byte value in the
+ extra space, 2 for the next two-byte value and so on.
+--*/
+
+ULONG FASTCALL WU32GetClassWord(PVDMFRAME pFrame)
+{
+ ULONG ul, flag;
+ HWND hwnd;
+ INT iOffset;
+ register PGETCLASSWORD16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCLASSWORD16), parg16);
+
+ // Make sure Win32 didn't change offsets
+
+#if (GCL_HBRBACKGROUND != (-10) || GCL_HCURSOR != (-12) || GCL_HICON != (-14) || GCL_HMODULE != (-16) || GCL_CBWNDEXTRA != (-18) || GCL_CBCLSEXTRA != (-20) || GCL_STYLE != (-26))
+#error Win16/Win32 class-word constants differ
+#endif
+
+ // Make sure the 16-bit app is requesting allowable offsets
+ // (It's just assertion code, so it doesn't have to be pretty! -JTP)
+
+ iOffset = INT32(parg16->f2);
+ WOW32ASSERT(iOffset >= 0 ||
+ iOffset == GCL_HBRBACKGROUND ||
+ iOffset == GCL_HCURSOR ||
+ iOffset == GCL_HICON ||
+ iOffset == GCL_HMODULE ||
+ iOffset == GCL_CBWNDEXTRA ||
+ iOffset == GCL_CBCLSEXTRA ||
+ iOffset == GCL_STYLE ||
+ iOffset == GCW_ATOM);
+
+ hwnd = HWND32(parg16->f1);
+
+ switch(iOffset) {
+ case GCL_HBRBACKGROUND:
+ ul = GetClassLong(hwnd, iOffset);
+ if (ul > COLOR_ENDCOLORS)
+ ul = GETHBRUSH16(ul);
+ break;
+
+ case GCL_HCURSOR:
+ ul = GETHCURSOR16((HAND32)GetClassLong(hwnd, iOffset));
+ break;
+
+ case GCL_HICON:
+ ul = GETHICON16((HAND32)GetClassLong(hwnd, iOffset));
+ break;
+
+ case GCL_HMODULE:
+ ul = GetGCL_HMODULE(hwnd);
+ break;
+
+ case GCL_CBWNDEXTRA:
+ case GCL_STYLE:
+ ul = GetClassLong(hwnd, iOffset);
+ break;
+
+ case GCL_CBCLSEXTRA:
+ ul = GetClassLong(hwnd, GCL_CBCLSEXTRA);
+
+ // verify that this class was registered by WOW
+ // (see GCW_CBCLSEXTRA notes in thunk for RegisterClass())
+ if(GetClassLong(hwnd, GCL_WNDPROC) & WNDPROC_WOW) {
+
+ // get the bozo flag
+ iOffset = ul - sizeof(DWORD);
+ flag = GetClassLong(hwnd, iOffset);
+
+ // if bozo app flag is set, get the value the app saved
+ // otherwise good little apps get cbClsExtra
+ if(flag) {
+ iOffset -= sizeof(DWORD);
+ ul = GetClassWord(hwnd, iOffset);
+ }
+ else {
+ ul -= (2 * sizeof(DWORD)); // account for our WOW DWORDs
+ }
+ }
+ break;
+
+
+ default:
+ ul = GetClassWord(hwnd, iOffset);
+ break;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL RegisterClass(<lpWndClass>)
+ LPWNDCLASS <lpWndClass>;
+
+ The %RegisterClass% function registers a window class for subsequent use in
+ calls to the %CreateWindow% function. The window class has the attributes
+ defined by the contents of the structure pointed to by the <lpWndClass>
+ parameter. If two classes with the same name are registered, the second
+ attempt fails and the information for that class is ignored.
+
+ <lpWndClass>
+ Points to a %WNDCLASS% structure. The structure must be filled with
+ the appropriate class attributes before being passed to the function.
+ See the following "Comments" section for details.
+
+ The return value specifies whether the window class is registered. It is
+ TRUE if the class is registered. Otherwise, it is FALSE.
+
+ The callback function must use the Pascal calling conventions and must be
+ declared %FAR%.
+
+ Callback Function:
+
+ BOOL FAR PASCAL <WndProc>(<hwnd>, <wMsg>, <wParam>, <lParam>)
+ HWND <hwnd>;
+ WORD <wMsg>;
+ WORD<wParam>;
+ DWORD<lParam>;
+
+ <WndProc> is a placeholder for the application-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the application's module-definition file.
+
+ <wMsg>
+ Specifies the message number.
+
+ <wParam>
+ Specifies additional message-dependent information.
+
+ <lParam>
+ Specifies additional message-dependent information.
+
+ The window function returns the result of the message processing. The
+ possible return values depend on the actual message sent.
+--*/
+
+ULONG FASTCALL WU32RegisterClass(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ WNDCLASS t1;
+ VPSZ vpszMenu;
+ PSZ pszMenu;
+ PSZ pszClass;
+ register PREGISTERCLASS16 parg16;
+ CHAR szAtomName[WOWCLASS_ATOM_NAME];
+ WC wc;
+
+ GETARGPTR(pFrame, sizeof(REGISTERCLASS16), parg16);
+
+ GETWNDCLASS16(parg16->vpWndClass, &t1);
+
+ // Fix up the window words for apps that have hardcode values and did not
+ // use the value from GetClassInfo when superclassing system proc.
+ // Some items have been expanded from a WORD to a DWORD bug 22014
+// t1.cbWndExtra = (t1.cbWndExtra + 3) & ~3;
+
+ // Some apps call SetClassWord()and SetClassLong() with the GCW_CBCLSEXTRA
+ // offset specified and clobber the cbClsExtra in the class structure on
+ // Win3.1 and retreive the value later (Wall Street Analyst, PC Anywhere are
+ // known culprits). Win'95 allows this for apps whose WinVer is less than
+ // 4.0. NT can't allow it without exposing the kernel to problems. What
+ // we do is add 2 extra DWORDs of class extra bytes to any classes that are
+ // created by WOW. We use the 1st DWORD to save the value the app passed to
+ // us and the 2nd DWORD as a flag that specifies that the bozo app did this.
+ // When an app calls GetClassXXXX(GWC_CBCLSEXTRA) we test the flag and
+ // return the appropriate value -- either cbClsExtra or the bozo value.
+ t1.cbClsExtra += (2 * sizeof(DWORD));
+
+ vpszMenu = (VPSZ)t1.lpszMenuName;
+ if (HIWORD(t1.lpszMenuName) != 0) {
+ GETPSZPTR(t1.lpszMenuName, pszMenu);
+ t1.lpszMenuName = pszMenu;
+ }
+
+ if (HIWORD(t1.lpszClassName) == 0) {
+ pszClass = szAtomName;
+ GetAtomName( (ATOM)t1.lpszClassName, pszClass, WOWCLASS_ATOM_NAME);
+ } else {
+ GETPSZPTR(t1.lpszClassName, pszClass);
+ }
+
+ t1.lpszClassName = pszClass;
+
+ ul = 0;
+
+ wc.vpszMenu = vpszMenu;
+ wc.vpfnWndProc = (VPWNDPROC)t1.lpfnWndProc;
+
+ t1.lpfnWndProc = (WNDPROC)((DWORD)t1.lpfnWndProc | WNDPROC_WOW);
+
+ //
+ // FEATURE-O-RAMA
+ //
+ // if the selector already has the high bit on then turn off bit 2
+ // of the selector (the LDT bit, which should always be on). we
+ // need a way to not blindly strip off the high bit in our wndproc.
+ //
+
+ if ((DWORD)wc.vpfnWndProc & WNDPROC_WOW) {
+ WOW32ASSERT((DWORD)t1.lpfnWndProc & WOWCLASS_VIRTUAL_NOT_BIT31);
+ (DWORD)t1.lpfnWndProc &= ~WOWCLASS_VIRTUAL_NOT_BIT31;
+ }
+
+ // Validate hbrBackground, because apps can pass an invalid handle.
+ // The GetGDI32 returns a non-null value even if h16 is invalid.
+ //
+ // if hbrBackground is not valid we set it to NULL if the apps
+ // ExpWinVer is < 3.1. This behaviour is identical to WIN31 behaviour.
+ //
+ // We need to do this validation here because USER32 will fail
+ // RegisterClass() if hbrBackground is not valid.
+ //
+ // known culprits: QuickCase:W (that comes with QcWin)
+ // class "iconbutton".
+
+ if ((DWORD)t1.hbrBackground > (DWORD)(COLOR_ENDCOLORS) &&
+ GetObjectType(t1.hbrBackground) != OBJ_BRUSH) {
+ if ((WORD)W32GetExpWinVer((HANDLE) LOWORD(t1.hInstance) ) < 0x030a)
+ t1.hbrBackground = (HBRUSH)NULL;
+ }
+
+ ul = GETBOOL16((pfnOut.pfnRegisterClassWOWA)(&t1, (DWORD *)&wc));
+
+ if (!ul) {
+ LOGDEBUG(LOG_ALWAYS,("WOW: RegisterClass failed (\"%s\")\n", (LPSZ)pszClass));
+ // WOW32ASSERT(ul);
+ }
+
+ FREEPSZPTR(pszClass);
+ FREEPSZPTR(pszMenu);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ LONG SetClassLong(<hwnd>, <nIndex>, <dwNewLong>)
+ HWND <hwnd>;
+ int <nIndex>;
+ DWORD <dwNewLong>;
+
+ The %SetClassLong% function replaces the long value specified by the
+ <nIndex> parameter in the %WNDCLASS% structure of the window specified by
+ the <hwnd> parameter.
+
+ <hwnd>
+ Identifies the window.
+
+ <nIndex>
+ Specifies the byte offset of the word to be changed. It can also
+ be one of the following values:
+
+ GCL_MENUNAME
+ Sets a new long pointer to the menu
+
+ GCL_WNDPROC
+ Sets a new long pointer to the window function.
+
+ <dwNewLong>
+ Specifies the replacement value.
+
+ The return value specifies the previous value of the specified long
+ integer.
+
+ If the %SetClassLong% function and GCL_WNDPROC index are used to set a
+ window function, the given function must have the window-function form and
+ be exported in the module-definition file. See the %RegisterClass% function
+ earlier in this chapter for details.
+
+ Calling %SetClassLong% with the GCL_WNDPROC index creates a subclass of the
+ window class that affects all windows subsequently created with the class.
+ See Chapter 1, Window Manager Interface Functions, for more information on
+ window subclassing. An application should not attempt to create a window
+ subclass for standard Windows controls such as combo boxes and buttons.
+
+ To access any extra two-byte values allocated when the window-class
+ structure was created, use a positive byte offset as the index specified by
+ the <nIndex> parameter, starting at zero for the first two-byte value in the
+ extra space, 2 for the next two-byte value and so on.
+--*/
+
+ULONG FASTCALL WU32SetClassLong(PVDMFRAME pFrame)
+{
+ ULONG ul, flag;
+ INT iOffset;
+ PSZ pszMenu;
+ register PWC pwc;
+ register PSETCLASSLONG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCLASSLONG16), parg16);
+
+ // Make sure Win32 didn't change offsets for GCL constants
+
+#if (GCL_MENUNAME != (-8) || GCL_WNDPROC != (-24))
+#error Win16/Win32 GCL constants differ
+#endif
+
+ // Make sure the 16-bit app is requesting allowable offsets
+
+ iOffset = INT32(parg16->f2);
+
+ WOW32ASSERT(iOffset >= 0 ||
+ iOffset == GCL_WNDPROC ||
+ iOffset == GCL_MENUNAME);
+
+ ul = 0;
+
+ switch (iOffset) {
+ case GCL_WNDPROC:
+ {
+ DWORD dwWndProc32Old;
+ DWORD dwWndProc32New;
+ PWW pww;
+
+ // Look to see if the new 16:16 proc is a thunk for a 32-bit proc.
+ dwWndProc32New = IsThunkWindowProc(LONG32(parg16->f3), NULL );
+
+ if ( dwWndProc32New != 0 ) {
+ //
+ // They are attempting to set the window proc to an existing
+ // 16-bit thunk that is really just a thunk for a 32-bit
+ // routine. We can just set it back to the 32-bit routine.
+ //
+ dwWndProc32Old = SetClassLong(HWND32(parg16->f1), GCL_WNDPROC, (LONG)dwWndProc32New);
+ SETWC(HWND32(parg16->f1), GCL_WOWvpfnWndProc, 0);
+ } else {
+ //
+ // They are attempting to set it to a real 16:16 proc.
+ //
+ LONG l;
+
+ l = LONG32(parg16->f3);
+
+ //
+ // FEATURE-O-RAMA
+ //
+ // if the selector already has the high bit on then turn off bit 2
+ // of the selector (the LDT bit, which should always be on). we
+ // need a way to not blindly strip off the high bit in our wndproc.
+ //
+
+ if (l & WNDPROC_WOW) {
+ WOW32ASSERT(l & WOWCLASS_VIRTUAL_NOT_BIT31);
+ l &= ~WOWCLASS_VIRTUAL_NOT_BIT31;
+ }
+
+ dwWndProc32Old = SetClassLong(HWND32(parg16->f1), GCL_WNDPROC, l | WNDPROC_WOW );
+ SETWC(HWND32(parg16->f1), GCL_WOWvpfnWndProc, LONG32(parg16->f3));
+ }
+
+ if ( dwWndProc32Old & WNDPROC_WOW ) {
+ if ( HIWORD(dwWndProc32Old) == WNDPROC_HANDLE ) {
+ //
+ // If the return value is a handle, then just thunk it.
+ //
+ pww = FindPWW(HWND32(parg16->f1), WOWCLASS_UNKNOWN);
+ if ( pww == NULL ) {
+ ul = 0;
+ } else {
+ ul = GetThunkWindowProc(dwWndProc32Old, NULL, pww, HWND32(parg16->f1));
+ }
+ } else {
+ //
+ // Previous proc was a 16:16 proc
+ //
+ ul = dwWndProc32Old & WNDPROC_MASK;
+
+ //
+ // if the actual selector had the high bit on then we turned off
+ // bit 2 of the selector (the LDT bit, which will always be on)
+ //
+ if (!(ul & WOWCLASS_VIRTUAL_NOT_BIT31)) {
+ ul |= (WNDPROC_WOW | WOWCLASS_VIRTUAL_NOT_BIT31);
+ }
+ }
+ } else {
+ //
+ // Previous proc was a 32-bit proc, use an allocated thunk
+ //
+ pww = FindPWW(HWND32(parg16->f1), WOWCLASS_UNKNOWN);
+ if ( pww == NULL ) {
+ ul = 0;
+ } else {
+ ul = GetThunkWindowProc(dwWndProc32Old, NULL, pww, HWND32(parg16->f1));
+ }
+
+ }
+ }
+ break;
+
+ case GCL_MENUNAME:
+ if (pwc = FindPWC(HWND32(parg16->f1))) {
+ ul = pwc->vpszMenu;
+ GETPSZPTR(parg16->f3, pszMenu);
+ SETWC(HWND32(parg16->f1), GCL_WOWvpszMenu, parg16->f3);
+ SetClassLong(HWND32(parg16->f1), GCL_MENUNAME, (LONG)pszMenu);
+ FREEPSZPTR(pszMenu);
+ }
+ break;
+
+
+ case GCL_CBCLSEXTRA:
+ // apps shouldn't do this but of course some do!
+ // (see GCW_CBCLSEXTRA notes in thunk for RegisterClass())
+ WOW32WARNMSG(0, ("WOW:SetClassLong(): app changing cbClsExtra!"));
+
+ // only allow this to be set by classes registered via WOW
+ if(GetClassLong(HWND32(parg16->f1), GCL_WNDPROC) & WNDPROC_WOW) {
+
+ ul = WORD32(parg16->f3);
+
+ // set the bozo flag & save the value the app passed us
+ iOffset = GetClassLong(HWND32(parg16->f1), GCL_CBCLSEXTRA);
+ iOffset -= sizeof(DWORD);
+ flag = SetClassLong(HWND32(parg16->f1), iOffset, 1);
+ iOffset -= sizeof(DWORD);
+ ul = SetClassLong(HWND32(parg16->f1), iOffset, ul);
+
+ // SetClassLong() returns the "previous" value.
+ // if this is the first time the app pulls this stunt it will
+ // get back the original cbClsExtra, otherwise it will get back
+ // the value it stored here on the previous call.
+ if(!flag) {
+ ul = iOffset; // the WOW DWORDs have already been subtracted
+ }
+ }
+ else {
+ ul = 0; // no can do for non-WOW classes
+ }
+ break;
+
+ default:
+ ul = SetClassLong(HWND32(parg16->f1), iOffset, LONG32(parg16->f3));
+ break;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ WORD SetClassWord(<hwnd>, <nIndex>, <wNewWord>)
+ HWND <hwnd>;
+ int <nIndex>;
+ WORD <wNewWord>;
+
+ The %SetClassWord% function replaces the word specified by the <nIndex>
+ parameter in the %WNDCLASS% structure of the window specified by the <hwnd>
+ parameter.
+
+ <hwnd>
+ Identifies the window.
+
+ <nIndex>
+ Specifies the byte offset of the word to be changed. It can also
+ be one of the following values:
+
+ GCL_CBCLSEXTRA
+ Sets two new bytes of additional window-class data.
+
+ GCL_CBWNDEXTRA
+ Sets two new bytes of additional window-class data.
+
+ GCL_HBRBACKGROUND
+ Sets a new handle to a background brush.
+
+ GCL_HCURSOR
+ Sets a new handle to a cursor.
+
+ GCL_HICON
+ Sets a new handle to an icon.
+
+ GCL_STYLE
+ Sets a new style bit for the window class.
+
+ <wNewWord>
+ Specifies the replacement value.
+
+ The return value specifies the previous value of the specified word.
+
+ The %SetClassWord% function should be used with care. For example, it is
+ possible to change the background color for a class by using %SetClassWord%,
+ but this change does not cause all windows belonging to the class to be
+ repainted immediately.
+
+ To access any extra four-byte values allocated when the window-class
+ structure was created, use a positive byte offset as the index specified by
+ the <nIndex> parameter, starting at zero for the first four-byte value in
+ the extra space, 4 for the next four-byte value and so on.
+--*/
+
+ULONG FASTCALL WU32SetClassWord(PVDMFRAME pFrame)
+{
+ ULONG ul, flag;
+ HWND hwnd;
+ INT iOffset;
+ register PSETCLASSWORD16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCLASSWORD16), parg16);
+
+ // Make sure Win32 didn't change offsets
+
+#if (GCL_HBRBACKGROUND != (-10) || GCL_HCURSOR != (-12) || GCL_HICON != (-14) || GCL_CBWNDEXTRA != (-18) || GCL_CBCLSEXTRA != (-20) || GCL_STYLE != (-26))
+#error Win16/Win32 GCW constants differ
+#endif
+
+ // Make sure the 16-bit app is requesting allowable offsets
+ // (It's just assertion code, so it doesn't have to be pretty! -JTP)
+
+ iOffset = INT32(parg16->f2);
+ WOW32ASSERT(iOffset >= 0 ||
+ iOffset == GCL_HBRBACKGROUND ||
+ iOffset == GCL_HCURSOR ||
+ iOffset == GCL_HICON ||
+ iOffset == GCL_CBWNDEXTRA ||
+ iOffset == GCL_CBCLSEXTRA ||
+ iOffset == GCL_STYLE)
+
+ hwnd = HWND32(parg16->f1);
+ ul = WORD32(parg16->f3);
+
+ switch(iOffset) {
+ case GCL_HBRBACKGROUND:
+ if (ul > COLOR_ENDCOLORS)
+ ul = (LONG) HBRUSH32(ul);
+
+ ul = SetClassLong(hwnd, iOffset, (LONG) ul);
+
+ if (ul > COLOR_ENDCOLORS)
+ ul = GETHBRUSH16(ul);
+ break;
+
+ case GCL_HCURSOR:
+ ul = GETHCURSOR16(SetClassLong(hwnd, iOffset, (LONG)HCURSOR32(ul)));
+ break;
+
+ case GCL_HICON:
+ ul = GETHICON16(SetClassLong(hwnd, iOffset, (LONG)HICON32(ul)));
+ break;
+
+ case GCL_HMODULE:
+ ul = 0; // not allowed to set this
+ break;
+
+ case GCL_CBWNDEXTRA:
+ case GCL_STYLE:
+ ul = SetClassLong(hwnd, iOffset, (LONG)ul);
+ break;
+
+ case GCL_CBCLSEXTRA:
+ // apps shouldn't do this but of course some do!
+ // (see GCW_CBCLSEXTRA notes in thunk for RegisterClass())
+ WOW32WARNMSG(0, ("WOW:SetClassWord(): app changing cbClsExtra!"));
+
+ // only allow this to be set by classes registered via WOW
+ if(GetClassLong(hwnd, GCL_WNDPROC) & WNDPROC_WOW) {
+
+ // set the bozo flag
+ iOffset = GetClassLong(hwnd, GCL_CBCLSEXTRA);
+ iOffset -= sizeof(DWORD);
+ flag = SetClassLong(hwnd, iOffset, 1);
+
+ // save the value the app passed
+ iOffset -= sizeof(DWORD);
+ ul = (WORD)SetClassWord(hwnd, iOffset, LOWORD(ul));
+
+ // SetClassWord() returns the "previous" value.
+ // if this is the first time the app pulls this stunt it will
+ // get back the original cbClsExtra, otherwise it will get back
+ // the value it stored here on the previous call.
+ if(!flag) {
+ ul = iOffset; // the WOW DWORDs have already been subtracted
+ }
+ }
+ else {
+ ul = 0; // no can do for non-WOW classes
+ }
+ break;
+
+ default:
+ ul = SetClassWord(hwnd, iOffset, (WORD)ul);
+ break;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL UnregisterClass(<lpClassName>, <hInstance>)
+
+ The %UnregisterClass% function removes the window class specified by
+ <lpClassName> from the window-class table, freeing the storage required for
+ the class.
+
+ <lpClassName>
+ Points to a null-terminated string containing the class name. This class
+ name must have been previously registered by calling the RegisterClass
+ function with a valid hInstance field in the %WNDCLASS% structure
+ parameter. Predefined classes, such as dialog-box controls, may not be
+ unregistered.
+
+ <hInstance>
+ Identifies the instance of the module that created the class.
+
+ The return value is TRUE if the function successfully removed the window
+ class from the window-class table. It is FALSE if the class could not be
+ found or if a window exists that was created with the class.
+
+ Before using this function, destroy all windows created with the specified
+ class.
+--*/
+
+ULONG FASTCALL WU32UnregisterClass(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1, pszClass;
+ register PUNREGISTERCLASS16 parg16;
+ CHAR szAtomName[WOWCLASS_ATOM_NAME];
+
+ GETARGPTR(pFrame, sizeof(UNREGISTERCLASS16), parg16);
+ GETPSZIDPTR(parg16->vpszClass, psz1);
+
+ if ( HIWORD(psz1) == 0 ) {
+ pszClass = szAtomName;
+ GetAtomName( (ATOM)psz1, pszClass, WOWCLASS_ATOM_NAME );
+ } else {
+ pszClass = psz1;
+ }
+
+#ifdef WOWEDIT
+ if (!_stricmp(pszClass, "Edit"))
+ pszClass = "WOWEdit";
+#endif
+
+ ul = GETBOOL16(UnregisterClass(
+ pszClass,
+ HMODINST32(parg16->hInstance)
+ ));
+
+ FREEPSZPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wuclass.h b/private/mvdm/wow32/wuclass.h
new file mode 100644
index 000000000..6681ef174
--- /dev/null
+++ b/private/mvdm/wow32/wuclass.h
@@ -0,0 +1,27 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUCLASS.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+#define WOWCLASS_ATOM_NAME 9 /* "#" + 7 digits + "\0" */
+
+#define WOWCLASS_VIRTUAL_NOT_BIT31 0x00040000 // the LDT bit
+
+/* Function prototypes
+ */
+
+ULONG FASTCALL WU32GetClassInfo(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetClassLong(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetClassWord(PVDMFRAME pFrame);
+ULONG FASTCALL WU32RegisterClass(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetClassLong(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetClassWord(PVDMFRAME pFrame);
+ULONG FASTCALL WU32UnregisterClass(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wuclip.c b/private/mvdm/wow32/wuclip.c
new file mode 100644
index 000000000..b33d49a06
--- /dev/null
+++ b/private/mvdm/wow32/wuclip.c
@@ -0,0 +1,1245 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUCLIP.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * WOW Clipboard functionality designed and developed by ChandanC
+ *
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+struct _CBFORMATS ClipboardFormats;
+
+DLLENTRYPOINTS OleStringConversion[WOW_OLESTRINGCONVERSION_COUNT] =
+ {"ConvertObjDescriptor", NULL};
+
+
+
+UINT CFOLEObjectDescriptor;
+UINT CFOLELinkSrcDescriptor;
+
+
+MODNAME(wuclip.c);
+
+
+/*++
+ BOOL ChangeClipboardChain(<hwnd>, <hwndNext>)
+ HWND <hwnd>;
+ HWND <hwndNext>;
+
+ The %ChangeClipboardChain% function removes the window specified by the
+ <hwnd> parameter from the chain of clipboard viewers and makes the window
+ specified by the <hwndNext> parameter the descendant of the <hwnd>
+ parameter's ancestor in the chain.
+
+ <hwnd>
+ Identifies the window that is to be removed from the chain. The handle
+ must previously have been passed to the SetClipboardViewer function.
+
+ <hwndNext>
+ Identifies the window that follows <hwnd> in the clipboard-viewer
+ chain (this is the handle returned by the %SetClipboardViewer% function,
+ unless the sequence was changed in response to a WM_CHANGECBCHAIN
+ message).
+
+ The return value specifies the status of the <hwnd> window. It is TRUE if
+ the window is found and removed. Otherwise, it is FALSE.
+--*/
+
+ULONG FASTCALL WU32ChangeClipboardChain(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCHANGECLIPBOARDCHAIN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CHANGECLIPBOARDCHAIN16), parg16);
+
+ ul = GETBOOL16(ChangeClipboardChain(
+ HWND32(parg16->f1),
+ HWND32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL CloseClipboard(VOID)
+
+ The %CloseClipboard% function closes the clipboard. The %CloseClipboard%
+ function should be called when a window has finished examining or changing
+ the clipboard. It lets other applications access the clipboard.
+
+ This function has no parameters.
+
+ The return value specifies whether the clipboard is closed. It is TRUE if
+ the clipboard is closed. Otherwise, it is FALSE.
+--*/
+
+ULONG FASTCALL WU32CloseClipboard(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETBOOL16(CloseClipboard());
+
+ RETURN(ul);
+}
+
+
+/*++
+ No REF header file
+--*/
+
+ULONG FASTCALL WU32CountClipboardFormats(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETINT16(CountClipboardFormats());
+
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL EmptyClipboard(VOID)
+
+ The %EmptyClipboard% function empties the clipboard and frees handles to
+ data in the clipboard. It then assigns ownership of the clipboard to the
+ window that currently has the clipboard open.
+
+ This function has no parameters.
+
+ The return value specifies the status of the clipboard. It is TRUE if the
+ clipboard is emptied. It is FALSE if an error occurs.
+
+ The clipboard must be open when the %EmptyClipboard% function is called.
+--*/
+
+ULONG FASTCALL WU32EmptyClipboard(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETBOOL16(EmptyClipboard());
+
+ W32EmptyClipboard ();
+
+ RETURN(ul);
+}
+
+
+/*++
+ WORD EnumClipboardFormats(<wFormat>)
+ WORD <wFormat>;
+
+ The %EnumClipboardFormats% function enumerates the formats found in a list
+ of available formats that belong to the clipboard. On each call to this
+ function, the <wFormat> parameter specifies a known available format, and
+ the function returns the format that appears next in the list. The first
+ format in the list can be retrieved by setting <wFormat> to zero.
+
+ <wFormat>
+ Specifies a known format.
+
+ The return value specifies the next known clipboard data format. It is zero
+ if <wFormat> specifies the last format in the list of available formats. It
+ is zero if the clipboard is not open.
+
+ Before it enumerates the formats by using the %EnumClipboardFormats%
+ function, an application must open the clipboard by using the
+ %OpenClipboard% function.
+
+ The order that an application uses for putting alternative formats for the
+ same data into the clipboard is the same order that the enumerator uses when
+ returning them to the pasting application. The pasting application should
+ use the first format enumerated that it can handle. This gives the donor a
+ chance to recommend formats that involve the least loss of data.
+--*/
+
+ULONG FASTCALL WU32EnumClipboardFormats(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PENUMCLIPBOARDFORMATS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENUMCLIPBOARDFORMATS16), parg16);
+
+ ul = GETWORD16(EnumClipboardFormats(
+ WORD32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HANDLE GetClipboardData(<wFormat>)
+ WORD <wFormat>;
+
+ The %GetClipboardData% function retrieves data from the clipboard in the
+ format given by the <wFormat> parameter. The clipboard must have been opened
+ previously.
+
+ <wFormat>
+ Specifies a data format. For a description of the data formats, see the
+ SetClipboardData function, later in this chapter.
+
+ The return value identifies the memory block that contains the data from the
+ clipboard. The handle type depends on the type of data specified by the
+ <wFormat> parameter. It is NULL if there is an error.
+
+ The available formats can be enumerated in advance by using the
+ %EnumClipboardFormats% function.
+
+ The data handle returned by %GetClipboardData% is controlled by the
+ clipboard, not by the application. The application should copy the data
+ immediately, instead of relying on the data handle for long-term use. The
+ application should not free the data handle or leave it locked.
+
+ Windows supports two formats for text, CF_TEXT and CF_OEMTEXT. CF_TEXT is
+ the default Windows text clipboard format, while Windows uses the CF_OEMTEXT
+ format for text in non-Windows applications. If you call %GetClipboardData%
+ to retrieve data in one text format and the other text format is the only
+ available text format, Windows automatically converts the text to the
+ requested format before supplying it to your application.
+
+ If the clipboard contains data in the CF_PALETTE (logical color palette)
+ format, the application should assume that any other data in the clipboard
+ is realized against that logical palette.
+--*/
+
+ULONG FASTCALL WU32GetClipboardData(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ HANDLE hMem32, hMeta32 = 0;
+ HMEM16 hMem16=0, hMeta16 = 0;
+ VPVOID vp;
+ LPBYTE lpMem32;
+ LPBYTE lpMem16;
+ int cb;
+ register PGETCLIPBOARDDATA16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCLIPBOARDDATA16), parg16);
+
+ LOGDEBUG(6, ("WOW::WUICBGetClipboardData(): CF_FORMAT is %04x\n", parg16->f1));
+
+ switch (parg16->f1) {
+
+ // This is intentional to let it thru to the "case statements".
+ // ChandanC 5/11/92.
+
+ default:
+ if ((parg16->f1 == CFOLEObjectDescriptor) || (parg16->f1 == CFOLELinkSrcDescriptor)) {
+ hMem32 = GetClipboardData(WORD32(parg16->f1));
+ if (hMem32) {
+ hMem16 = (HMEM16) W32ConvertObjDescriptor(hMem32, CFOLE_UNICODE_TO_ANSI);
+ }
+ WU32ICBStoreHandle(parg16->f1, hMem16);
+ break;
+ }
+
+ case CF_DIB:
+ case CF_TEXT:
+ case CF_DSPTEXT:
+ case CF_SYLK:
+ case CF_DIF:
+ case CF_TIFF:
+ case CF_OEMTEXT:
+ case CF_PENDATA:
+ case CF_RIFF:
+ case CF_WAVE:
+ case CF_OWNERDISPLAY:
+ hMem16 = WU32ICBGetHandle(parg16->f1);
+ if (!hMem16) {
+ hMem32 = GetClipboardData(WORD32(parg16->f1));
+
+ if (hMem16 = WU32ICBGetHandle(parg16->f1)) {
+
+ //
+ // We couldn't find the hMem16 using WU32ICBGetHandle
+ // before we called Win32 GetClipboardData, but we can
+ // now, so that means it was cut/copied from a task in
+ // this WOW using delayed rendering, so that the actual
+ // non-NULL hMem16 wasn't SetClipboardData until we
+ // just called GetClipboardData. Since we now have
+ // a valid cached copy of the data in 16-bit land,
+ // we can just return that.
+ //
+
+ break;
+ }
+
+ if (hMem32) {
+ lpMem32 = GlobalLock(hMem32);
+ cb = GlobalSize(hMem32);
+ vp = GlobalAllocLock16(GMEM_MOVEABLE | GMEM_DDESHARE, cb, &hMem16);
+ // 16-bit memory may have moved - refresh flat pointers
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(GETCLIPBOARDDATA16), parg16);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ RtlCopyMemory(lpMem16, lpMem32, cb);
+ GlobalUnlock16(hMem16);
+ FLUSHVDMPTR(vp, cb, lpMem16);
+ FREEMISCPTR(lpMem16);
+ }
+ GlobalUnlock(hMem32);
+ }
+
+ WU32ICBStoreHandle(parg16->f1, hMem16);
+ }
+ break;
+
+ case CF_HDROP:
+ // This is the case when app is retrieving cf_hdrop from the
+ // clipboard, thus we will convert the dropfiles structure
+ // from 32 to 16-bit one
+ hMem16 = WU32ICBGetHandle(parg16->f1);
+ if (!hMem16) {
+ hMem32 = GetClipboardData(WORD32(parg16->f1));
+ if (hMem32) {
+ hMem16 = CopyDropFilesFrom32(hMem32);
+ }
+ WU32ICBStoreHandle(parg16->f1, hMem16);
+ }
+ break;
+
+ case CF_DSPBITMAP:
+ case CF_BITMAP:
+ hMem16 = GETHBITMAP16(GetClipboardData(WORD32(parg16->f1)));
+ break;
+
+ case CF_PALETTE:
+ hMem16 = GETHPALETTE16(GetClipboardData(WORD32(parg16->f1)));
+ break;
+
+ case CF_DSPMETAFILEPICT:
+ case CF_METAFILEPICT:
+ hMem16 = WU32ICBGetHandle(parg16->f1);
+ if (!(hMem16)) {
+ hMem32 = GetClipboardData(WORD32(parg16->f1));
+
+ if (hMem16 = WU32ICBGetHandle(parg16->f1)) {
+
+ //
+ // We couldn't find the hMem16 using WU32ICBGetHandle
+ // before we called Win32 GetClipboardData, but we can
+ // now, so that means it was cut/copied from a task in
+ // this WOW using delayed rendering, so that the actual
+ // non-NULL hMem16 wasn't SetClipboardData until we
+ // just called GetClipboardData. Since we now have
+ // a valid cached copy of the data in 16-bit land,
+ // we can just return that.
+ //
+
+ break;
+ }
+
+ if (hMem32) {
+ lpMem32 = GlobalLock(hMem32);
+ vp = GlobalAllocLock16(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(METAFILEPICT16), &hMem16);
+ // 16-bit memory may have moved - refresh flat pointers
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(GETCLIPBOARDDATA16), parg16);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ FixMetafile32To16 ((LPMETAFILEPICT) lpMem32, (LPMETAFILEPICT16) lpMem16);
+ FREEMISCPTR(lpMem16);
+
+ hMeta32 = ((LPMETAFILEPICT) lpMem32)->hMF;
+ if (hMeta32) {
+ hMeta16 = WinMetaFileFromHMF(hMeta32, FALSE);
+ // 16-bit memory may have moved
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(GETCLIPBOARDDATA16), parg16);
+ }
+
+ GETMISCPTR(vp, lpMem16);
+ STOREWORD(((LPMETAFILEPICT16) lpMem16)->hMF, hMeta16);
+ GlobalUnlock16(hMem16);
+ FLUSHVDMPTR(vp, sizeof(METAFILEPICT16), lpMem16);
+ FREEMISCPTR(lpMem16);
+ }
+ GlobalUnlock(hMem32);
+ }
+ WU32ICBStoreHandle(parg16->f1, hMem16);
+ }
+ break;
+ }
+
+ ul = (ULONG) hMem16;
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int GetClipboardFormatName(<wFormat>, <lpFormatName>, <nMaxCount>)
+ WORD <wFormat>;
+ LPSTR <lpFormatName>;
+ int <nMaxCount>;
+
+ The %GetClipboardFormatName% function retrieves from the clipboard the name
+ of the registered format specified by the <wFormat> parameter. The name is
+ copied to the buffer pointed to by the <lpFormatName> parameter.
+
+ <wFormat>
+ Specifies the type of format to be retrieved. It must not specify any of
+ the predefined clipboard formats.
+
+ <lpFormatName>
+ Points to the buffer that is to receive the format name.
+
+ <nMaxCount>
+ Specifies the maximum length (in bytes) of the string to be copied
+ to the buffer. If the actual name is longer, it is truncated.
+
+ The return value specifies the actual length of the string copied to the
+ buffer. It is zero if the requested format does not exist or is a predefined
+ format.
+--*/
+
+ULONG FASTCALL WU32GetClipboardFormatName(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2 = NULL;
+ register PGETCLIPBOARDFORMATNAME16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCLIPBOARDFORMATNAME16), parg16);
+ ALLOCVDMPTR(parg16->f2, parg16->f3, psz2);
+
+ ul = GETINT16(GetClipboardFormatName(
+ WORD32(parg16->f1),
+ psz2,
+ INT32(parg16->f3)
+ ));
+
+ FLUSHVDMPTR(parg16->f2, strlen(psz2)+1, psz2);
+ FREEVDMPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HWND GetClipboardOwner(VOID)
+
+ The %GetClipboardOwner% function retrieves the window handle of the current
+ owner of the clipboard.
+
+ This function has no parameters.
+
+ The return value identifies the window that owns the clipboard. It is NULL
+ if the clipboard is not owned.
+
+ The clipboard can still contain data even if the clipboard is not currently
+ owned.
+--*/
+
+ULONG FASTCALL WU32GetClipboardOwner(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETHWND16(GetClipboardOwner());
+
+ RETURN(ul);
+}
+
+
+/*++
+ HWND GetClipboardViewer(VOID)
+
+ The %GetClipboardViewer% function retrieves the window handle of the first
+ window in the clipboard-viewer chain.
+
+ This function has no parameters.
+
+ The return value identifies the window currently responsible for displaying
+ the clipboard. It is NULL if there is no viewer.
+--*/
+
+ULONG FASTCALL WU32GetClipboardViewer(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETHWND16(GetClipboardViewer());
+
+ RETURN(ul);
+}
+
+
+/*++
+ int GetPriorityClipboardFormat(<lpPriorityList>, <cEntries>)
+ LPWORD <lpPriorityList>;
+ int <cEntries>;
+
+ The %GetPriorityClipboardFormat% function returns the first clipboard format
+ in a list for which data exist in the clipboard.
+
+ <lpPriorityList>
+ Points to an integer array that contains a list of clipboard formats in
+ priority order. For a description of the data formats, see the
+ SetClipboardData function later in this chapter.
+
+ <cEntries>
+ Specifies the number of entries in <lpPriorityList>. This value
+ must not be greater than the actual number of entries in the list.
+
+ The return value is the highest priority clipboard format in the list for
+ which data exist. If no data exist in the clipboard, this function returns
+ NULL. If data exist in the clipboard which did not match any format in the
+ list, the return value is -1.
+--*/
+
+ULONG FASTCALL WU32GetPriorityClipboardFormat(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ UINT *pu1;
+ register PGETPRIORITYCLIPBOARDFORMAT16 parg16;
+ INT BufferT[256]; // comfortably large array
+
+
+ GETARGPTR(pFrame, sizeof(GETPRIORITYCLIPBOARDFORMAT16), parg16);
+ pu1 = STACKORHEAPALLOC(parg16->f2 * sizeof(INT), sizeof(BufferT), BufferT);
+ getuintarray16(parg16->f1, parg16->f2, pu1);
+
+ if (pu1) {
+ ul = GETINT16(GetPriorityClipboardFormat(
+ pu1,
+ INT32(parg16->f2)
+ ));
+ } else {
+ ul = (ULONG)-1;
+ }
+
+ STACKORHEAPFREE(pu1, BufferT);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL IsClipboardFormatAvailable(<wFormat>)
+ WORD <wFormat>;
+
+ The %IsClipboardFormatAvailable% function specifies whether data of a
+ certain type exist in the clipboard.
+
+ <wFormat>
+ Specifies a registered clipboard format. For information on clipboard
+ formats, see the description of the SetClipboardData function, later in
+ this chapter.
+
+ The return value specifies the outcome of the function. It is TRUE if data
+ having the specified format are present. Otherwise, it is FALSE.
+
+ This function is typically called during processing of the WM_INITMENU or
+ WM_INITMENUPOPUP message to determine whether the clipboard contains data
+ that the application can paste. If such data are present, the application
+ typically enables the Paste command (in its Edit menu).
+--*/
+
+ULONG FASTCALL WU32IsClipboardFormatAvailable(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISCLIPBOARDFORMATAVAILABLE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISCLIPBOARDFORMATAVAILABLE16), parg16);
+
+ // Hack-a-roo! PhotoShop 2.5 has a bug in its code for handling large DIB's
+ // on the clipboard and will fault if it encounters one. On WFW, it usually
+ // won't encounter one because most apps (in this case alt-Prtscrn button)
+ // copy BITMAPS, not DIBS, to the clipboard. On NT, anytime an app writes
+ // a BITMAP to the clipboard it gets converted to a DIB & vice versa-making
+ // more clipboard data formats available to inquiring apps. Unfortunately,
+ // Photoshop checks for DIBS before BITMAPS and finds one on Win
+ // Versions >= 4.0. a-craigj
+
+ // if this is a DIB check && the app is PhotoShop...
+ if((WORD32(parg16->f1) == CF_DIB) &&
+ (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_NODIBSHERE)) {
+
+ // ...see if there is a bitmap format available too
+ if(IsClipboardFormatAvailable(CF_BITMAP)) {
+
+ // if so return FALSE which will cause Photoshop to ask for a
+ // BITMAP format next
+ ul = FALSE;
+ }
+
+ // otherwise we'll check for a DIB anyway & hope it's a small one
+ else {
+ ul = GETBOOL16(IsClipboardFormatAvailable(CF_DIB));
+ }
+ }
+
+ // no hack path
+ else {
+ ul = GETBOOL16(IsClipboardFormatAvailable(WORD32(parg16->f1)));
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL OpenClipboard(<hwnd>)
+ HWND <hwnd>;
+
+ The %OpenClipboard% function opens the clipboard. Other applications will
+ not be able to modify the clipboard until the %CloseClipboard% function is
+ called.
+
+ <hwnd>
+ Identifies the window to be associated with the open clipboard.
+
+ The return value is TRUE if the clipboard is opened, or FALSE if another
+ application or window has the clipboard opened.
+
+ The window specified by the <hwnd> parameter will not become the owner of
+ the clipboard until the %EmptyCLipboard% function is called.
+--*/
+
+ULONG FASTCALL WU32OpenClipboard(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register POPENCLIPBOARD16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OPENCLIPBOARD16), parg16);
+
+ ul = GETBOOL16(OpenClipboard(
+ HWND32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ WORD RegisterClipboardFormat(<lpFormatName>)
+ LPSTR <lpFormatName>;
+
+ The %RegisterClipboardFormat% function registers a new clipboard format
+ whose name is pointed to by the <lpFormatName> parameter. The registered
+ format can be used in subsequent clipboard functions as a valid format in
+ which to render data, and it will appear in the clipboard's list of
+ formats.
+
+ <lpFormatName>
+ Points to a character string that names the new format. The string must
+ be a null-terminated string.
+
+ The return value specifies the newly registered format. If the identical
+ format name has been registered before, even by a different application, the
+ format's reference count is increased and the same value is returned as when
+ the format was originally registered. The return value is zero if the format
+ cannot be registered.
+
+ The format value returned by the %RegisterClipboardFormat% function is
+ within the range of 0xC000 to 0xFFFF.
+--*/
+
+ULONG FASTCALL WU32RegisterClipboardFormat(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ register PREGISTERCLIPBOARDFORMAT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(REGISTERCLIPBOARDFORMAT16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+
+ ul = GETWORD16(RegisterClipboardFormat(
+ psz1
+ ));
+
+ FREEPSZPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HANDLE SetClipboardData(<wFormat>, <hData>)
+ WORD <wFormat>;
+ HANDLE <hData>;
+
+ The %SetClipboardData% function sets the data in the clipboard. The
+ application must have called the %OpenClipboard% function before calling
+ the %SetClipboardData% function.
+
+ <wFormat>
+ Specifies the format of the data. It can be any one of the
+ system-defined formats, or a format registered by the
+ %RegisterClipboardFormat% function. For a list of system-defined
+ formats,
+
+ <hData>
+ Identifies the data to be placed into the clipboard. For all formats
+ except CF_BITMAP and CF_PALETTE, this parameter must be a handle to
+ memory allocated by the %GlobalAlloc% function. For CF_BITMAP format,
+ the <hData> parameter is a handle to a bitmap (see %LoadBitmap%). For
+ CF_PALETTE format, the <hData> parameter is a handle to a palette (see
+ %CreatePalette%).
+
+ If this parameter is NULL, the owner of the clipboard will be sent a
+ WM_RENDERFORMAT message when it needs to supply the data.
+
+ The return value is a handle to the data if the function is succesful, or
+ NULL if an error occurred.
+
+ If the <hData> parameter contains a handle to memory allocated by the
+ %GlobalAlloc% function, the application must not use this handle once it
+ has called the %SetClipboardData% function.
+
+ The following list contains the system-defined clipboard formats:
+
+ CF_BITMAP
+ The data is a bitmap.
+
+ CF_DIB
+ The data is a memory block containing a %BITMAPINFO% structure followed
+ by the bitmap data.
+
+ CF_DIF
+ The data is in Software Arts' Data Interchange Format.
+
+ CF_DSPBITMAP
+ The data is a bitmap representation of a private format. This data is
+ displayed in bitmap format in lieu of the privately formatted data.
+
+ CF_DSPMETAFILEPICT
+ The data is a metafile representation of a private data format. This
+ data is displayed in metafile-picture format in lieu of the privately
+ formatted data.
+
+ CF_DSPTEXT
+ The data is a textual representation of a private data format. This data
+ is displayed in text format in lieu of the privately formatted data.
+
+ CF_METAFILEPICT
+ The data is a metafile (see description of the %METAFILEPICT%
+ structure).
+
+ CF_OEMTEXT
+ The data is an array of text characters in the OEM character set. Each
+ line ends with a carriage return/linefeed (CR-LF) combination. A null
+ character signals the end of the data.
+
+ CF_OWNERDISPLAY
+ The data is in a private format that the clipboard owner must display.
+
+ CF_PALETTE
+ The data is a color palette.
+
+ CF_SYLK
+ The data is in Microsoft Symbolic Link (SYLK) format.
+
+ CF_TEXT
+ The data is an array of text characters. Each line ends with a carriage
+ return/linefeed (CR-LF) combination. A null character signals the end of
+ the data.
+
+ CF_TIFF
+ The data is in Tag Image File Format.
+
+ Private data formats in the range of CF_PRIVATEFIRST to CF_PRIVATELAST are
+ not automatically freed when the data is deleted from the clipboard. Data
+ handles associated with these formats should be freed upon receiving a
+ WM_DESTROYCLIPBOARD message.
+
+ Private data formats in the range of CF_GDIOBJFIRST to CF_GDIOBJLAST will
+ be automatically deleted with a call to %DeleteObject% when the data is
+ deleted from the clipboard.
+
+ If the Windows clipboard application is running, it will not update its
+ window to show the data placed in the clipboard by the %SetClipboardData%
+ until after the %CloseClipboard% function is called.
+
+ 31-Oct-1990 [ralphw] Miscelanious material, needs to be moved to other
+ function descriptions/overviews.
+
+ Whenever an application places data in the clipboard that depends on or
+ assumes a color palette, it should also place the palette in the
+ clipboard as well.
+
+ If the clipboard contains data in the CF_PALETTE (logical color palette)
+ format, the application should assume that any other data in the
+ clipboard is realized against that logical palette.
+
+ The clipboard-viewer application (CLIPBRD.EXE) always uses as its
+ current palette any object in CF_PALETTE format that is in the clipboard
+ when it displays the other formats in the clipboard.
+
+ Windows supports two formats for text, CF_TEXT and CF_OEMTEXT. CF_TEXT
+ is the default Windows text clipboard format, while Windows uses the
+ CF_OEMTEXT format for text in non-Windows applications. If you call
+ %GetClipboardData% to retrieve data in one text format and the other
+ text format is the only available text format, Windows automatically
+ converts the text to the requested format before supplying it to your
+ application.
+
+ An application registers other standard formats, such as Rich Text
+ Format (RTF), by name using the %RegisterClipboardFormat% function
+ rather than by a symbolic constant. For information on these external
+ formats, see the README.TXT file.
+--*/
+
+ULONG FASTCALL WU32SetClipboardData(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ HANDLE hMem32 = NULL, hMF32 = NULL;
+ HAND16 hMem16, hMeta16 = 0;
+ LPBYTE lpMem16, lpMem32;
+ INT cb;
+ VPVOID vp;
+
+
+ register PSETCLIPBOARDDATA16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCLIPBOARDDATA16), parg16);
+
+ LOGDEBUG(6, ("WOW::WUICBSetClipboardData(): CF_FORMAT is %04x\n", parg16->f1));
+
+ switch (parg16->f1) {
+
+ default:
+ if ((parg16->f1 == CFOLEObjectDescriptor) || (parg16->f1 == CFOLELinkSrcDescriptor)) {
+ if (parg16->f2) {
+ hMem32 = W32ConvertObjDescriptor((HANDLE) parg16->f2, CFOLE_ANSI_TO_UNICODE);
+ }
+ ul = (ULONG) SetClipboardData(WORD32(parg16->f1), hMem32);
+ WU32ICBStoreHandle(parg16->f1, parg16->f2);
+ break;
+ }
+
+ // It is intentional to let it thru to the "case statements".
+ // ChandanC 5/11/92.
+
+ case CF_DIB:
+ case CF_TEXT:
+ case CF_DSPTEXT:
+ case CF_SYLK:
+ case CF_DIF:
+ case CF_TIFF:
+ case CF_OEMTEXT:
+ case CF_PENDATA:
+ case CF_RIFF:
+ case CF_WAVE:
+ case CF_OWNERDISPLAY:
+ hMem16 = parg16->f2;
+ if (hMem16) {
+ vp = GlobalLock16(hMem16, &cb);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ hMem32 = Copyh16Toh32 (cb, lpMem16);
+ GlobalUnlock16(hMem16);
+ FREEMISCPTR(lpMem16);
+ }
+ }
+
+ ul = (ULONG) SetClipboardData(WORD32(parg16->f1), hMem32);
+
+ WU32ICBStoreHandle(parg16->f1, hMem16);
+ break;
+
+ case CF_HDROP:
+ // support cf_hdrop format by converting the dropfiles structure
+ hMem16 = parg16->f2;
+ if (hMem16) {
+ hMem32 = CopyDropFilesFrom16(hMem16);
+ }
+ ul = (ULONG)SetClipboardData(WORD32(parg16->f1), hMem32);
+ WU32ICBStoreHandle(parg16->f1, hMem16);
+ break;
+
+ case CF_DSPBITMAP:
+ case CF_BITMAP:
+ ul = (ULONG) SetClipboardData(WORD32(parg16->f1),
+ HBITMAP32(parg16->f2));
+ break;
+
+
+ case CF_PALETTE:
+ ul = (ULONG) SetClipboardData(WORD32(parg16->f1),
+ HPALETTE32(parg16->f2));
+ break;
+
+ case CF_DSPMETAFILEPICT:
+ case CF_METAFILEPICT:
+ hMem16 = parg16->f2;
+ if (hMem16) {
+ vp = GlobalLock16(hMem16, &cb);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ hMem32 = GlobalAlloc(GMEM_DDESHARE, sizeof(METAFILEPICT));
+ WOW32ASSERT(hMem32);
+ if (hMem32) {
+ lpMem32 = GlobalLock(hMem32);
+ ((LPMETAFILEPICT) lpMem32)->mm = FETCHSHORT(((LPMETAFILEPICT16) lpMem16)->mm);
+ ((LPMETAFILEPICT) lpMem32)->xExt = (LONG) FETCHSHORT(((LPMETAFILEPICT16) lpMem16)->xExt);
+ ((LPMETAFILEPICT) lpMem32)->yExt = (LONG) FETCHSHORT(((LPMETAFILEPICT16) lpMem16)->yExt);
+ hMeta16 = FETCHWORD(((LPMETAFILEPICT16) lpMem16)->hMF);
+ if (hMeta16) {
+ hMF32 = (HMETAFILE) HMFFromWinMetaFile(hMeta16, FALSE);
+ }
+ ((LPMETAFILEPICT) lpMem32)->hMF = hMF32;
+ GlobalUnlock(hMem32);
+ }
+ GlobalUnlock16(hMem16);
+ FREEMISCPTR(lpMem16);
+ }
+
+ }
+
+ ul = (ULONG) SetClipboardData(WORD32(parg16->f1), hMem32);
+
+ WU32ICBStoreHandle(parg16->f1, hMem16);
+ break;
+
+ }
+
+ if (parg16->f2) {
+ ul = parg16->f2;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/*++
+ HWND SetClipboardViewer(<hwnd>)
+ HWND <hwnd>;
+
+ The %SetClipboardViewer% function adds the window specified by the <hwnd>
+ parameter to the chain of windows that are notified (via the
+ WM_DRAWCLIPBOARD message) whenever the contents of the clipboard are
+ changed.
+
+ <hwnd>
+ Identifies the window to receive clipboard-viewer chain messages.
+
+ The return value identifies the next window in the clipboard-viewer chain.
+ This handle should be saved in static memory and used in responding to
+ clipboard-viewer chain messages.
+
+ Windows that are part of the clipboard-viewer chain must respond to
+ WM_CHANGECBCHAIN, WM_DRAWCLIPBOARD, and WM_DESTROY messages.
+
+ If an application wishes to remove itself from the clipboard-viewer chain,
+ it must call the %ChangeClipboardChain% function.
+--*/
+
+ULONG FASTCALL WU32SetClipboardViewer(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETCLIPBOARDVIEWER16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCLIPBOARDVIEWER16), parg16);
+
+ ul = GETHWND16(SetClipboardViewer(HWND32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+VOID WU32ICBStoreHandle(WORD wFormat, HMEM16 hMem16)
+{
+ HAND16 h16, hMeta16;
+ PCBNODE Temp, Temp1;
+ LPBYTE lpMem16;
+ VPVOID vp;
+ int cb;
+
+
+ if ((wFormat == CF_METAFILEPICT) || (wFormat == CF_DSPMETAFILEPICT)) {
+ if (wFormat == CF_METAFILEPICT) {
+ h16 = ClipboardFormats.Pre1[wFormat];
+ }
+ else {
+ h16 = ClipboardFormats.Pre2[3];
+ }
+
+ if (h16) {
+ vp = GlobalLock16(h16, &cb);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ hMeta16 = FETCHWORD(((LPMETAFILEPICT16) lpMem16)->hMF);
+ GlobalUnlockFree16(GlobalLock16(hMeta16, NULL));
+ }
+ GlobalUnlockFree16(vp);
+
+ if (wFormat == CF_METAFILEPICT) {
+ ClipboardFormats.Pre1[wFormat] = 0;
+ }
+ else {
+ ClipboardFormats.Pre2[3] = 0;
+ }
+ }
+ }
+
+ if ((wFormat >= CF_TEXT ) && (wFormat <= CF_WAVE)) {
+ if (ClipboardFormats.Pre1[wFormat]) {
+ GlobalUnlockFree16(GlobalLock16(ClipboardFormats.Pre1[wFormat], NULL));
+ }
+ ClipboardFormats.Pre1[wFormat] = hMem16;
+ }
+ else if ((wFormat >= CF_OWNERDISPLAY) && (wFormat <= CF_DSPMETAFILEPICT)) {
+ wFormat = (wFormat & (WORD) 3);
+
+ if (ClipboardFormats.Pre2[wFormat]) {
+ GlobalUnlockFree16(GlobalLock16(ClipboardFormats.Pre2[wFormat], NULL));
+ }
+
+ ClipboardFormats.Pre2[wFormat] = hMem16;
+ }
+ else if (wFormat == CF_HDROP) {
+
+ if (ClipboardFormats.hmem16Drop) {
+ GlobalUnlockFree16(GlobalLock16(ClipboardFormats.hmem16Drop, NULL));
+ }
+ ClipboardFormats.hmem16Drop = hMem16;
+ }
+ else {
+ Temp = ClipboardFormats.NewFormats;
+ if (Temp) {
+ while ((Temp->Next) && (Temp->Id != wFormat)) {
+ Temp = Temp->Next;
+ }
+
+ if (Temp->Id == wFormat) {
+
+ // free a previous handle if it exists
+ if (Temp->hMem16) {
+ GlobalUnlockFree16(GlobalLock16(Temp->hMem16, NULL));
+ }
+
+ Temp->hMem16 = hMem16;
+ }
+ else {
+ Temp1 = (PCBNODE) malloc_w (sizeof(CBNODE));
+ if (Temp1) {
+ Temp->Next = Temp1;
+ Temp1->Id = wFormat;
+ Temp1->hMem16 = hMem16;
+ Temp1->Next = NULL;
+
+ LOGDEBUG(6,("WOW::WU32ICBStoreHandle: Adding a new node for private clipboard data format %04lx\n", wFormat));
+ }
+ }
+ }
+ else {
+ Temp = (PCBNODE) malloc_w (sizeof(CBNODE));
+ if (Temp) {
+ ClipboardFormats.NewFormats = Temp;
+ Temp->Id = wFormat;
+ Temp->hMem16 = hMem16;
+ Temp->Next = NULL;
+
+ LOGDEBUG(6,("WOW::WU32ICBStoreHandle: Adding the FIRST node for private clipboard data format %04lx\n", wFormat));
+ }
+ }
+ }
+}
+
+
+
+HMEM16 WU32ICBGetHandle(WORD wFormat)
+{
+ HMEM16 hMem16 = 0;
+ PCBNODE Temp;
+
+ if ((wFormat >= CF_TEXT) && (wFormat <= CF_WAVE)) {
+ hMem16 = ClipboardFormats.Pre1[wFormat];
+ }
+ else if ((wFormat >= CF_OWNERDISPLAY) && (wFormat <= CF_DSPMETAFILEPICT)) {
+ wFormat = (wFormat & (WORD) 3);
+ hMem16 = ClipboardFormats.Pre2[wFormat];
+ }
+ else if (wFormat == CF_HDROP) {
+ hMem16 = ClipboardFormats.hmem16Drop;
+ }
+ else {
+ Temp = ClipboardFormats.NewFormats;
+ if (Temp) {
+ while ((Temp->Next) && (Temp->Id != wFormat)) {
+ Temp = Temp->Next;
+ }
+
+ if (Temp->Id == wFormat) {
+ hMem16 = Temp->hMem16;
+ }
+ else {
+ LOGDEBUG(6,("WOW::WU32ICBGetHandle: Cann't find private clipboard data format %04lx\n", wFormat));
+ hMem16 = (WORD) NULL;
+ }
+ }
+ }
+
+ return (hMem16);
+}
+
+
+
+VOID W32EmptyClipboard ()
+{
+ PCBNODE Temp, Temp1;
+ int wFormat, cb;
+ HAND16 hMem16, hMeta16;
+ LPBYTE lpMem16;
+ VPVOID vp;
+
+ // Empty CF_METAFILEPICT
+
+ hMem16 = ClipboardFormats.Pre1[CF_METAFILEPICT];
+ if (hMem16) {
+ vp = GlobalLock16(hMem16, &cb);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ hMeta16 = FETCHWORD(((LPMETAFILEPICT16) lpMem16)->hMF);
+ GlobalUnlockFree16(GlobalLock16(hMeta16, NULL));
+ }
+ GlobalUnlockFree16(vp);
+ ClipboardFormats.Pre1[CF_METAFILEPICT] = 0;
+ }
+
+ // Empty CF_DSPMETAFILEPICT
+
+ hMem16 = ClipboardFormats.Pre2[3];
+ if (hMem16) {
+ vp = GlobalLock16(hMem16, &cb);
+ if (vp) {
+ GETMISCPTR(vp, lpMem16);
+ hMeta16 = FETCHWORD(((LPMETAFILEPICT16) lpMem16)->hMF);
+ GlobalUnlockFree16(GlobalLock16(hMeta16, NULL));
+ }
+ GlobalUnlockFree16(vp);
+ ClipboardFormats.Pre2[3] = 0;
+ }
+
+ // Empty rest of the formats
+
+ for (wFormat=0; wFormat <= CF_WAVE ; wFormat++) {
+ if (ClipboardFormats.Pre1[wFormat]) {
+ GlobalUnlockFree16(GlobalLock16(ClipboardFormats.Pre1[wFormat], NULL));
+ ClipboardFormats.Pre1[wFormat] = 0;
+ }
+ }
+
+ for (wFormat=0; wFormat < 4 ; wFormat++) {
+ if (ClipboardFormats.Pre2[wFormat]) {
+ GlobalUnlockFree16(GlobalLock16(ClipboardFormats.Pre2[wFormat], NULL));
+ ClipboardFormats.Pre2[wFormat] = 0;
+ }
+ }
+
+ if (ClipboardFormats.hmem16Drop) {
+ GlobalUnlockFree16(GlobalLock16(ClipboardFormats.hmem16Drop, NULL));
+ }
+ ClipboardFormats.hmem16Drop = 0;
+
+
+ // These are the private registered data formats. This list is purged when
+ // 32 bit USER purges its clipboard cache.
+
+ Temp = ClipboardFormats.NewFormats;
+ ClipboardFormats.NewFormats = NULL;
+
+ while (Temp) {
+
+ Temp1 = Temp->Next;
+
+ if (Temp->hMem16) {
+ GlobalUnlockFree16(GlobalLock16(Temp->hMem16, NULL));
+ }
+
+ free_w(Temp);
+
+ Temp = Temp1;
+ }
+
+}
+
+
+VOID InitCBFormats ()
+
+{
+ int wFormat;
+
+ for (wFormat = 0 ; wFormat <= CF_WAVE ; wFormat++) {
+ ClipboardFormats.Pre1[wFormat] = 0;
+ }
+
+ for (wFormat=0; wFormat < 4; wFormat++) {
+ ClipboardFormats.Pre2[wFormat] = 0;
+ }
+
+ ClipboardFormats.hmem16Drop = 0;
+
+ // These are the private registered data formats.
+
+ ClipboardFormats.NewFormats = NULL;
+
+
+ CFOLEObjectDescriptor = RegisterClipboardFormat ("Object Descriptor");
+ CFOLELinkSrcDescriptor = RegisterClipboardFormat ("Link Source Descriptor");
+
+#ifdef DEBUG
+
+ //
+ // This would assert in LoadLibraryAndGetProcAddresses if the function
+ // or DLL name has changed.
+ //
+
+ if (!(OleStringConversion[WOW_OLE_STRINGCONVERSION].lpfn)) {
+ LoadLibraryAndGetProcAddresses("OLETHK32.DLL", OleStringConversion, WOW_OLESTRINGCONVERSION_COUNT);
+ }
+
+#endif
+
+
+}
+
+
+HGLOBAL W32ConvertObjDescriptor(HANDLE hMem, UINT flag)
+{
+ HANDLE hMemOut;
+
+ if (!(OleStringConversion[WOW_OLE_STRINGCONVERSION].lpfn)) {
+ if (!LoadLibraryAndGetProcAddresses("OLETHK32.DLL", OleStringConversion, WOW_OLESTRINGCONVERSION_COUNT)) {
+ return (0);
+ }
+ }
+
+ hMemOut = (HANDLE) (*OleStringConversion[WOW_OLE_STRINGCONVERSION].lpfn) (hMem, flag);
+
+ return (hMemOut);
+}
diff --git a/private/mvdm/wow32/wuclip.h b/private/mvdm/wow32/wuclip.h
new file mode 100644
index 000000000..2ae084a6d
--- /dev/null
+++ b/private/mvdm/wow32/wuclip.h
@@ -0,0 +1,57 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUCLIP.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+ULONG FASTCALL WU32ChangeClipboardChain(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CloseClipboard(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CountClipboardFormats(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EmptyClipboard(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EnumClipboardFormats(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetClipboardData(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetClipboardFormatName(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetClipboardOwner(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetClipboardViewer(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetPriorityClipboardFormat(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsClipboardFormatAvailable(PVDMFRAME pFrame);
+ULONG FASTCALL WU32OpenClipboard(PVDMFRAME pFrame);
+ULONG FASTCALL WU32RegisterClipboardFormat(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetClipboardData(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetClipboardViewer(PVDMFRAME pFrame);
+
+ULONG WU32ICBRenderFormat (WORD wFormat);
+HMEM16 WU32ICBGetHandle(WORD wFormat);
+VOID WU32ICBStoreHandle(WORD wFormat, HMEM16 hMem16);
+VOID W32EmptyClipboard (void);
+VOID InitCBFormats (void);
+HGLOBAL W32ConvertObjDescriptor(HANDLE hMem, UINT flag);
+
+typedef struct _CBNODE {
+ WORD Id;
+ HMEM16 hMem16;
+ struct _CBNODE *Next;
+} CBNODE, *PCBNODE;
+
+
+typedef struct _CBFORMATS {
+ WORD Pre1[13];
+ WORD Pre2[4];
+ WORD hmem16Drop; // for the CF_HDROP support
+ struct _CBNODE *NewFormats;
+} CBFORMATS;
+
+
+#define CFOLE_UNICODE_TO_ANSI 0
+#define CFOLE_ANSI_TO_UNICODE 1
+
+#define WOW_OLE_STRINGCONVERSION 0
+#define WOW_OLESTRINGCONVERSION_COUNT 1
diff --git a/private/mvdm/wow32/wucomm.c b/private/mvdm/wow32/wucomm.c
new file mode 100644
index 000000000..98eabe3d7
--- /dev/null
+++ b/private/mvdm/wow32/wucomm.c
@@ -0,0 +1,2616 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUCOMM.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+ * made real Dec-1992 by Craig Jones (v-cjones)
+ * made work Apr-1993 by Craig Jones (v-cjones)
+ * made fast Jun-1993 by Craig Jones (v-cjones)
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+#include <ntddser.h>
+
+MODNAME(wucomm.c);
+
+/* Define the table for mapping Win3.1 idComDev's to 32-bit comm HFILE's. */
+/* This table is indexed by the 16-bit idComDev that we return to the app */
+/* which is assigned based on the device name (see wucomm.h). You can */
+/* use GETPWOWPTR(idComDev) to get the ptr to the corresponding WOWPort */
+/* struct from PortTab[]. */
+
+/* This table must contain NUMPORTS (def'd in wucomm.h) entries */
+static PORTTAB PortTab[] = { {"COM1", NULL},
+ {"COM2", NULL},
+ {"COM3", NULL},
+ {"COM4", NULL},
+ {"COM5", NULL},
+ {"COM6", NULL},
+ {"COM7", NULL},
+ {"COM8", NULL},
+ {"COM9", NULL},
+ {"LPT1", NULL},
+ {"LPT2", NULL},
+ {"LPT3", NULL}
+ };
+
+
+/* function prototypes for local support functions */
+DWORD Baud16toBaud32(UINT BaudRate);
+WORD Baud32toBaud16(DWORD BaudRate);
+void DCB16toDCB32(PWOWPORT pWOWPort, LPDCB lpdcb32, PDCB16 pdcb16);
+void DCB32toDCB16(PDCB16 pdcb16, LPDCB lpdcb32, UINT idComDev, BOOL fChEvt);
+BOOL DeletePortTabEntry(PWOWPORT pWOWPort);
+ULONG WOWCommWriterThread(LPVOID pWOWPortStruct);
+USHORT EnqueueCommWrite(PWOWPORT pwp, PUCHAR pch, USHORT cb);
+UINT GetModePortTabIndex(PSZ pszModeStr);
+BOOL GetPortName(LPSTR pszMode, LPSTR pszPort);
+UINT GetStrPortTabIndex(PSZ szPort);
+BOOL InitDCB32(LPDCB pdcb32, LPSTR pszModeStr);
+VOID InitDEB16(PCOMDEB16 pComDEB16, UINT iTab, WORD QInSize, WORD QOutSize);
+PSZ StripPortName(PSZ psz);
+PSZ GetPortStringToken(PSZ pszSrc, PSZ pszToken);
+BOOL MSRWait(PWOWPORT pwp);
+
+/* prototypes for Modem interrupt emulation thread support */
+VOID WOWModemIntThread(PWOWPORT pWOWPortStruct);
+BOOL WOWStartModemIntThread(PWOWPORT pWOWPort);
+DWORD WOWGetCommError(PWOWPORT pWOWPort);
+
+
+
+// Win3.1 returns:
+// 0 on success OR LPT.
+// -1 on ANY error.
+ULONG FASTCALL WU32BuildCommDCB(PVDMFRAME pFrame)
+{
+ ULONG ul = (ULONG)-1;
+ UINT len, iTab;
+ PSZ psz1;
+ PDCB16 pdcb16;
+ DCB dcb32;
+ register PBUILDCOMMDCB16 parg16;
+
+ GETARGPTR(pFrame, sizeof(BUILDCOMMDCB16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+
+ // if valid device name...
+ if((INT)(iTab = GetModePortTabIndex(psz1)) >= 0) {
+
+ // Initialize a Win3.1 compatible 32-bit DCB
+ if(InitDCB32(&dcb32, psz1)) {
+
+ GETMISCPTR(parg16->f2, pdcb16);
+
+ if(pdcb16) {
+ // copy the psz1 fields to the 16-bit struct
+ iTab = (VALIDCOM(iTab) ? iTab : TABIDTOLPT(iTab));
+ DCB32toDCB16(pdcb16, &dcb32, iTab, FALSE);
+
+ // set timeouts for COMx ports only
+ if(VALIDCOM(iTab)) {
+
+ // 'P' is the only "retry" option supported in Win3.1
+ len = strlen(psz1) - 1;
+ while(psz1[len] != ' ') { // delete trailing spaces
+ len--;
+ }
+ if((psz1[len] == 'P') || (psz1[len] == 'p')) {
+ pdcb16->RlsTimeout = INFINITE_TIMEOUT;
+ pdcb16->CtsTimeout = INFINITE_TIMEOUT;
+ pdcb16->DsrTimeout = INFINITE_TIMEOUT;
+ }
+ }
+
+ FLUSHVDMPTR(parg16->f2, sizeof(DCB16), pdcb16);
+ FREEMISCPTR(pdcb16);
+
+ ul = 0; // Win3.1 returns 0 if success
+ }
+ }
+ FREEPSZPTR(psz1);
+ }
+
+ WOW32ASSERTMSG((ul==0), ("WOW::WU32BuildCommDCB: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// Error word on success OR LPTx.
+// 0x8000 on bad idComDev.
+ULONG FASTCALL WU32ClearCommBreak(PVDMFRAME pFrame)
+{
+ ULONG ul = 0x00008000;
+ UINT idComDev;
+ PWOWPORT pWOWPort;
+ register PCLEARCOMMBREAK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CLEARCOMMBREAK16), parg16);
+
+ idComDev = UINT32(parg16->f1);
+ if (pWOWPort = GETPWOWPTR(idComDev)) {
+
+ if (VALIDCOM(idComDev)) {
+ if(!ClearCommBreak(pWOWPort->h32)) {
+ WOWGetCommError(pWOWPort);
+ }
+ }
+ ul = pWOWPort->dwErrCode;
+ }
+
+ WOW32ASSERTMSG((ul!=0x00008000),("WOW::WU32ClearCommBreak: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// 0 if success OR if LPTx.
+// -1 for bad idComDev OR port not open.
+// -2 for Timeout error.
+// We pass back (as a 2nd parameter) the DWORD obtained from the call to
+// GlobalDosAlloc() in IOpenComm() in user.exe. (WOWModemIntThread() support)
+ULONG FASTCALL WU32CloseComm(PVDMFRAME pFrame)
+{
+ ULONG ul = (ULONG)-1;
+ UINT idComDev;
+ PDWORD16 lpdwDEB16;
+ PWOWPORT pWOWPort = NULL;
+ register PCLOSECOMM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CLOSECOMM16), parg16);
+
+ idComDev = UINT32(parg16->f1);
+ if (pWOWPort = GETPWOWPTR(idComDev)) {
+
+ // pass back the 16:16 ptr for the WOWModemIntThread() support
+ GETMISCPTR(parg16->f2, lpdwDEB16);
+ if (lpdwDEB16) {
+ *lpdwDEB16 = pWOWPort->dwComDEB16;
+ FLUSHVDMPTR(parg16->f2, sizeof(DWORD), lpdwDEB16);
+ FREEMISCPTR(lpdwDEB16);
+ }
+
+ // clean up the PortTab[] entry
+ if (DeletePortTabEntry(pWOWPort)) {
+ ul = (ULONG)-2; // return Win3.1 timeOut error
+ }
+ else {
+ ul = 0;
+ }
+ }
+ else {
+ LOGDEBUG (0, ("WOW::WU32CloseComm: Not a valid COM or LPT\n"));
+ }
+
+ WOW32ASSERTMSG((ul==0), ("WOW::WU32CloseComm: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// TRUE on success.
+// FALSE if error OR if EnableCommNotification() not supported.
+// User16 validation layer returns 0 for bad hwnd.
+ULONG FASTCALL WU32EnableCommNotification(PVDMFRAME pFrame)
+{
+ ULONG ul = (ULONG)FALSE;
+ UINT idComDev;
+ WORD cbQue;
+ BOOL fOK = TRUE;
+ PWOWPORT pWOWPort;
+ PCOMDEB16 lpComDEB16;
+ register PENABLECOMMNOTIFICATION16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENABLECOMMNOTIFICATION16), parg16);
+
+ idComDev = UINT32(parg16->f1);
+ if ((VALIDCOM(idComDev)) && (pWOWPort = PortTab[idComDev].pWOWPort)) {
+
+ lpComDEB16 = pWOWPort->lpComDEB16;
+
+ // if they are trying to disable notifcation (HWND == NULL)
+ if(WORD32(parg16->f2) == 0) {
+ lpComDEB16->NotifyHandle = 0;
+ lpComDEB16->NotifyFlags = CN_TRANSMITHI;
+ lpComDEB16->RecvTrigger = (WORD)-1;
+ lpComDEB16->SendTrigger = 0;
+ ul = (ULONG)TRUE;
+ }
+
+ // Validate non-null hwnd's since hwnd validation is disabled in
+ // user16 validation layer
+ else if(!IsWindow(HWND32(parg16->f2))) {
+ ul = (ULONG)FALSE;
+ }
+
+ // else set up the notification mechanisms
+ else {
+
+ // if the Modem interrupt thread hasn't started yet -- go start it
+ if(pWOWPort->hMiThread == NULL) {
+
+ if(!WOWStartModemIntThread(pWOWPort)) {
+ fOK = FALSE;
+ }
+ }
+
+ // update the DEB to reflect notification
+ if(fOK) {
+
+ lpComDEB16->NotifyHandle = WORD32(parg16->f2);
+ lpComDEB16->NotifyFlags = CN_TRANSMITHI | CN_NOTIFYHI;
+
+ // set trigger values the same way Win3.1 does
+ cbQue = WORD32(parg16->f3);
+ if((cbQue < lpComDEB16->QInSize) || ((SHORT)cbQue == -1)) {
+ lpComDEB16->RecvTrigger = cbQue;
+ }
+ else {
+ lpComDEB16->RecvTrigger = lpComDEB16->QInSize - 10;
+ }
+ cbQue = WORD32(parg16->f4);
+ if((cbQue < lpComDEB16->QOutSize) || ((SHORT)cbQue == -1)) {
+ lpComDEB16->SendTrigger = cbQue;
+ }
+ else {
+ lpComDEB16->SendTrigger = lpComDEB16->QOutSize - 10;
+ }
+
+ ul = (ULONG)TRUE;
+ }
+ }
+ }
+ // else there is no notification for LPT in Win3.1
+ else {
+ ul = (ULONG)FALSE;
+ }
+
+ WOW32ASSERTMSG((ul==1), ("WOW::WU32EnableCommNotification: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// The value from the specified function.
+// The error word for: the line & signal state functions,
+// function not implemented, OR LPTx where function != (RESETDEV||GETMAXLPT).
+// 0x8000 for bad idComDev.
+ULONG FASTCALL WU32EscapeCommFunction(PVDMFRAME pFrame)
+{
+ ULONG ul = 0x00008000;
+ UINT idComDev;
+ UINT nFunction;
+ WORD IRQ;
+ VPVOID vpBiosData;
+ PWORD16 pwBiosData;
+ PWOWPORT pWOWPort;
+ register PESCAPECOMMFUNCTION16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ESCAPECOMMFUNCTION16), parg16);
+
+ // this construct is set up this way because Win3.1 will allow GETMAXCOM
+ // & GETMAXLPT to succeed as long as the idComDev is in the valid range.
+ // (ie: the app doesn't have to call OpenComm() first to set up the PortTab)
+ // for RESETDEV we tell them that we reset the printer. (we're such liars!)
+
+ nFunction = WORD32(parg16->f2);
+ idComDev = UINT32(parg16->f1);
+ if (VALIDCOM(idComDev)) {
+
+ if (nFunction == GETMAXCOM) {
+ ul = NUMCOMS-1;
+ } else if (nFunction == GETBASEIRQ || nFunction == GETBASEIRQ+1) {
+ ul = 0xFFFFFFFF;
+ if (idComDev < COM5) {
+ vpBiosData = (VPVOID) (RM_BIOS_DATA + (idComDev * sizeof(WORD)));
+ if (pwBiosData = (PWORD16)GetRModeVDMPointer(vpBiosData)) {
+ if (idComDev == COM1 || idComDev == COM3) {
+ IRQ = IRQ4;
+ } else {
+ IRQ = IRQ3;
+ }
+ ul = MAKELONG((WORD)(*pwBiosData), IRQ);
+ FREEVDMPTR(pwBiosData);
+ }
+ }
+ } else {
+ // for the other functions they must have called OpenComm()
+ if (pWOWPort = PortTab[idComDev].pWOWPort) {
+
+ switch(nFunction) {
+
+ // line & signal state functions
+ case SETXOFF:
+ case SETXON:
+ case SETRTS:
+ case CLRRTS:
+ case SETDTR:
+ case CLRDTR:
+ if(!EscapeCommFunction(pWOWPort->h32, nFunction)) {
+ WOWGetCommError(pWOWPort);
+ }
+ ul = pWOWPort->dwErrCode;
+ break;
+
+ // 0:
+ case 0:
+ ul = 0; // like WFW
+ break;
+
+ // any other value...
+ default:
+
+ // non-zero is error: use dwErrcode if there is one
+ if(pWOWPort->dwErrCode)
+ ul = pWOWPort->dwErrCode;
+
+ // else use what WFW seems inclined to return
+ else
+ ul = CE_OVERRUN | CE_RXPARITY;
+ break;
+ }
+ }
+ }
+ } else if (VALIDLPT(idComDev)) {
+ if(nFunction == RESETDEV) {
+ ul = 0; // no error (ie. "just tell them we did it" - TonyE)
+ }
+ else if(nFunction == GETMAXLPT) {
+ ul = LPTLAST;
+ }
+ else if (pWOWPort = PortTab[GETLPTID(idComDev)].pWOWPort) {
+ ul = pWOWPort->dwErrCode;
+ }
+ else {
+ ul = 0;
+ }
+ }
+
+ WOW32ASSERTMSG((ul>=0), ("WOW::WU32EscapeCommFunction: failed\n"));
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// 0 on success.
+// 0x8000 if bad idComDev.
+// Error word on error or LPTx.
+ULONG FASTCALL WU32FlushComm(PVDMFRAME pFrame)
+{
+ ULONG ul = 0x00008000;
+ UINT idComDev;
+ DWORD dwAction;
+ PWOWPORT pWOWPort;
+ register PFLUSHCOMM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(FLUSHCOMM16), parg16);
+
+ idComDev = UINT32(parg16->f1);
+ if (pWOWPort = GETPWOWPTR(idComDev)) {
+
+ // is a COMx?
+ if (VALIDCOM(idComDev)) {
+
+ // if flush transmit buffer specified
+ dwAction = PURGE_RXCLEAR;
+ if(parg16->f2 == 0) {
+ dwAction = PURGE_TXCLEAR | PURGE_TXABORT;
+
+ //
+ // Flush the local writers buffer
+ //
+
+ EnterCriticalSection(&pWOWPort->csWrite);
+ pWOWPort->pchWriteHead =
+ pWOWPort->pchWriteTail = pWOWPort->pchWriteBuf;
+ pWOWPort->cbWriteFree = pWOWPort->cbWriteBuf - 1;
+ pWOWPort->cbWritePending = 0;
+ LeaveCriticalSection(&pWOWPort->csWrite);
+ }
+
+
+ if(PurgeComm(pWOWPort->h32, dwAction)) {
+
+ if(dwAction == PURGE_RXCLEAR) {
+ pWOWPort->fUnGet = FALSE;
+ }
+
+ ul = 0; // Win3.1 returns 0 on success
+ }
+ else {
+ WOWGetCommError(pWOWPort);
+ ul = pWOWPort->dwErrCode;
+ }
+ }
+ // else just return current error code for LPTx
+ else {
+ ul = pWOWPort->dwErrCode;
+ }
+ }
+
+ WOW32ASSERTMSG((ul==0), ("WOW::WU32FlushComm: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// 0x8000 for bad idComDev.
+// The error word for all other cases.
+ULONG FASTCALL WU32GetCommError(PVDMFRAME pFrame)
+{
+ ULONG ul = 0x00008000;
+ UINT idComDev;
+ PWOWPORT pWOWPort;
+ PCOMSTAT16 pcs16;
+ register PGETCOMMERROR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCOMMERROR16), parg16);
+ GETMISCPTR(parg16->f2, pcs16);
+
+ idComDev = UINT32(parg16->f1);
+ if (pWOWPort = GETPWOWPTR (idComDev)) {
+
+ if (VALIDCOM(idComDev) && pcs16) {
+
+ WOWGetCommError(pWOWPort);
+
+
+ // Always update the COMSTAT status byte, DynComm depends on it.
+ pcs16->status = 0;
+ if(pWOWPort->cs.fCtsHold) pcs16->status |= W31CS_fCtsHold;
+ if(pWOWPort->cs.fDsrHold) pcs16->status |= W31CS_fDsrHold;
+ if(pWOWPort->cs.fRlsdHold) pcs16->status |= W31CS_fRlsdHold;
+ if(pWOWPort->cs.fXoffHold) pcs16->status |= W31CS_fXoffHold;
+ if(pWOWPort->cs.fXoffSent) pcs16->status |= W31CS_fSentHold;
+ if(pWOWPort->cs.fEof) pcs16->status |= W31CS_fEof;
+ if(pWOWPort->cs.fTxim) pcs16->status |= W31CS_fTxim;
+
+ pcs16->cbInQue = (WORD)pWOWPort->cs.cbInQue;
+ pcs16->cbOutQue = (WORD)pWOWPort->cs.cbOutQue;
+
+ // account for the UnGot char (if any)
+ if(pWOWPort->fUnGet) {
+ pcs16->cbInQue++;
+ }
+ }
+
+ // if an LPT OR pcs16 == NULL, Win3.1 returns the error code
+ else {
+ // for LPT's Win3.1 just zero's the COMSTAT & returns the error code
+ if(VALIDLPT(idComDev)) {
+ if(pcs16) {
+ RtlZeroMemory((PVOID)pcs16, sizeof(COMSTAT16));
+ }
+ }
+ }
+
+ ul = (ULONG)pWOWPort->dwErrCode;
+
+ // clear the error now that the app has got it (but maintain queues)
+ pWOWPort->dwErrCode = 0;
+ pWOWPort->lpComDEB16->ComErr = 0;
+ RtlZeroMemory((PVOID)&(pWOWPort->cs), sizeof(COMSTAT));
+ if(pcs16) {
+ pWOWPort->cs.cbInQue = pcs16->cbInQue;
+ pWOWPort->cs.cbOutQue = pcs16->cbOutQue;
+ }
+ }
+
+ FLUSHVDMPTR(parg16->f2, sizeof(COMSTAT16), pcs16);
+ FREEMISCPTR(pcs16);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// EvtWord on success.
+// 0 for bad idComDev OR LPTx.
+ULONG FASTCALL WU32GetCommEventMask(PVDMFRAME pFrame)
+{
+ ULONG ul=0;
+ DWORD dwEvtMask;
+ UINT idComDev;
+ PWOWPORT pWOWPort;
+ PCOMDEB16 pDEB16;
+ register PGETCOMMEVENTMASK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCOMMEVENTMASK16), parg16);
+
+ idComDev = UINT32(parg16->f1);
+ if (VALIDCOM(idComDev)) {
+ if(pWOWPort = PortTab[idComDev].pWOWPort) {
+
+ if(pDEB16 = pWOWPort->lpComDEB16) {
+
+ // in Win3.1 the app gets current event word (NOT the EvtMask!!)
+ ul = (ULONG)pDEB16->EvtWord;
+
+ // clear event word like Win3.1 does
+ dwEvtMask = (DWORD)WORD32(parg16->f2);
+ pDEB16->EvtWord = LOWORD((~dwEvtMask) & (DWORD)ul);
+ }
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// 0 for success.
+// -1 for bad idComDev.
+// IE_NOPEN for not opened.
+ULONG FASTCALL WU32GetCommState(PVDMFRAME pFrame)
+{
+ ULONG ul = (ULONG)-1;
+ UINT idComDev;
+ DCB dcb32;
+ PWOWPORT pWOWPort;
+ PDCB16 pdcb16;
+ register PGETCOMMSTATE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCOMMSTATE16), parg16);
+
+ idComDev = UINT32(parg16->f1);
+ if (pWOWPort = GETPWOWPTR(idComDev)) {
+
+ GETMISCPTR(parg16->f2, pdcb16);
+
+ if(pdcb16) {
+ if(VALIDCOM(idComDev)) {
+ if(GetCommState(pWOWPort->h32, &dcb32)) {
+
+ DCB32toDCB16(pdcb16, &dcb32, idComDev, pWOWPort->fChEvt);
+ ul = 0; // Win3.1 returns 0 if success
+ }
+ }
+
+ // else get DCB for LPT's
+ else {
+ RtlCopyMemory((PVOID)pdcb16,
+ (PVOID)pWOWPort->pdcb16,
+ sizeof(DCB16));
+ ul = 0; // Win3.1 returns 0 if success
+ }
+
+ FLUSHVDMPTR(parg16->f2, sizeof(DCB16), pdcb16);
+ FREEMISCPTR(pdcb16);
+ }
+ }
+ // else if they got a handle that looks good but they didn't open the port
+ else if(VALIDCOM(idComDev) || VALIDLPT(idComDev)) {
+ ul = (ULONG)IE_NOPEN;
+ }
+
+ WOW32ASSERTMSG((ul==0), ("WOW::WU32GetCommState: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// An idComDev on success.
+// IE_BADID for bad port name.
+// IE_OPEN if port already open.
+// IE_HARDWARE if hardware in use (ie. by mouse) OR port doesn't exist.
+// IE_MEMORY if both cbInQueue & cbOutQueue == 0 OR can't allocate a queue.
+// IE_NOPEN if can't open port.
+// IE_DEFAULT if initialization fails for various reasons.
+// We pass an additional (4th) parameter from IOpenComm() for SetCommEventMask()
+// support. It's a DWORD that is obtained by a call to GlobalDosAlloc().
+ULONG FASTCALL WU32OpenComm(PVDMFRAME pFrame)
+{
+ INT ret;
+ UINT iTab, idComDev;
+ CHAR COMbuf[] = "COMx:9600,E,7,1"; // Win3.1 default
+ CHAR szPort[MAXCOMNAMENULL];
+ DWORD dwDEBAddr;
+ DWORD cbInQ, cbOutQ;
+ HANDLE h32 = 0;
+ HANDLE hREvent = 0;
+ DCB dcb32;
+ PSZ psz1;
+ PDCB16 pdcb16 = NULL;
+ PWOWPORT pWOWPort;
+ PCOMDEB16 lpComDEB16;
+ COMMTIMEOUTS ct;
+ PUCHAR pchWriteBuf = NULL;
+ UINT cbWriteBuf = 0;
+ HANDLE hWriteEvent = 0;
+ DWORD dwWriteThreadId;
+ BOOL fIsLPTPort;
+ register POPENCOMM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OPENCOMM16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+
+ // see if valid com device name...
+ if((iTab = GetModePortTabIndex(psz1)) == (UINT)IE_BADID) {
+ ret = IE_BADID;
+ goto ErrorExit0;
+ }
+
+ // check if named port is already in use
+ if(PortTab[iTab].pWOWPort != NULL) {
+ ret = IE_OPEN;
+ goto ErrorExit0;
+ }
+
+ if ( VALIDCOM(iTab) ) {
+ idComDev = iTab;
+ fIsLPTPort = FALSE;
+ } else {
+ idComDev = TABIDTOLPT(iTab);
+ fIsLPTPort = TRUE;
+ }
+
+ // get port name: app may pass in a full mode string in Win3.1
+ GetPortName(psz1, szPort);
+
+ // try to open the port
+ if((h32 = CreateFile(szPort,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL)) == INVALID_HANDLE_VALUE) {
+
+ if(GetLastError() == ERROR_FILE_NOT_FOUND) {
+ ret = IE_HARDWARE;
+ }
+ else {
+ LOGDEBUG (LOG_ERROR,("WOW::WU32OpenComm CreateFile failed, lasterror=0x%x\n",GetLastError()));
+ ret = IE_NOPEN;
+ }
+ goto ErrorExit0;
+ }
+
+
+
+ // ignore LPT's for this check like Win3.1 does
+ if( !fIsLPTPort ) {
+
+ // common method apps use to see if a COM port is already open
+ if((WORD32(parg16->f2) == 0) &&
+ (WORD32(parg16->f3) == 0)) {
+ ret = IE_MEMORY;
+ goto ErrorExit1;
+ }
+
+ // set up the I/O queues
+ cbInQ = (DWORD)WORD32(parg16->f2);
+ cbOutQ = (DWORD)WORD32(parg16->f3);
+
+ //
+ // Allocate write buffer to emulate Win3.1's transmit queue.
+ // We allocate one extra byte because the last byte of the
+ // buffer is never filled. If it were, then the head and
+ // tail pointers would be equal, which we use to indicate
+ // an *empty* buffer.
+ //
+
+ cbWriteBuf = cbOutQ + 1;
+
+ if (!(pchWriteBuf = malloc_w(cbWriteBuf))) {
+ ret = IE_MEMORY;
+ goto ErrorExit1;
+ }
+
+ //
+ // IO buffers must be a multiple of 2 for SetupComm().
+ // Note that SetupComm may ignore the write buffer size
+ // entirely, but TonyE says that we should still pass
+ // down the size requested, since in any case writes
+ // will complete only when the bits are irretrievably
+ // sent, I.E. in the UART or other hardware, out of
+ // the control of the device driver.
+ //
+
+ cbInQ = (cbInQ + 1) & ~1;
+ cbOutQ = (cbOutQ + 1) & ~1;
+ if(!SetupComm(h32, cbInQ, cbOutQ)) {
+ ret = IE_MEMORY;
+ goto ErrorExit2;
+ }
+
+ //
+ // Create an event used by the app thread to wake up
+ // the writer thread when the write buffer is
+ // empty and the app writes something. The event
+ // is auto-reset, meaning it is reset when the
+ // writer wakes up. The event is initially not
+ // signaled, it will be signaled when the first
+ // write occurs.
+ //
+
+ if (!(hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) {
+ ret = IE_MEMORY;
+ goto ErrorExit2;
+ }
+
+ //
+ // create an event for ReadComm()'s overlapped structure
+ //
+
+ if(!(hREvent = CreateEvent(NULL, TRUE, FALSE, NULL))) {
+ ret = IE_NOPEN;
+ goto ErrorExit3;
+ }
+
+ // set the timeout values
+ ct.ReadIntervalTimeout = (DWORD)INFINITE; // == MAXDWORD
+ ct.ReadTotalTimeoutMultiplier=0;
+ ct.ReadTotalTimeoutConstant=0;
+ ct.WriteTotalTimeoutMultiplier=0;
+ ct.WriteTotalTimeoutConstant=WRITE_TIMEOUT;
+ if(!SetCommTimeouts(h32, &ct)) {
+ ret = IE_DEFAULT;
+ goto ErrorExit3;
+ }
+
+ // make sure the DCB is Win3.1 compatible
+ // NOTE: app can pass in a full mode string in Win3.1
+ if((strlen(psz1) < 4) || !InitDCB32(&dcb32, psz1)) {
+ if(!InitDCB32(&dcb32, COMbuf)) {
+ ret = IE_DEFAULT;
+ goto ErrorExit3;
+ }
+ }
+
+ // set current DCB to Win3.1 compatibility
+ if(!SetCommState(h32, &dcb32)) {
+ ret = IE_DEFAULT;
+ goto ErrorExit3;
+ }
+
+ // purge the I/O buffers just to be sure
+ PurgeComm(h32, PURGE_TXCLEAR);
+ PurgeComm(h32, PURGE_RXCLEAR);
+
+ }
+
+ // we need to set up a default DCB for LPT's
+ else {
+
+ if((pdcb16 = malloc_w(sizeof(DCB16))) == NULL) {
+ ret = IE_DEFAULT;
+ goto ErrorExit1;
+ }
+
+ // initialize everything to 0
+ RtlZeroMemory((PVOID)pdcb16, sizeof(DCB16));
+
+ // save the idComDev only in the DCB
+ pdcb16->Id = LOBYTE(LOWORD(idComDev));
+ }
+
+ // allocate the WOWPort structure for this port
+ if((pWOWPort = malloc_w(sizeof(WOWPORT))) == NULL) {
+ ret = IE_DEFAULT;
+ goto ErrorExit3;
+ }
+
+ // get seg:sel dword returned by GlobalDosAlloc for the DEB struct
+ // we'll treat the 16:16 pDEB as real mode on 32-bit side due to
+ // some MIPS issues: v-simonf
+ dwDEBAddr = DWORD32(parg16->f4) & 0xFFFF0000;
+
+ // save flat pointer to DEB for use in Modem interrupt thread
+ if(!(lpComDEB16 = (PCOMDEB16) GetRModeVDMPointer(dwDEBAddr))) {
+ goto ErrorExit4;
+ }
+
+ // init the DEB
+ InitDEB16(lpComDEB16, iTab, WORD32(parg16->f2), WORD32(parg16->f3));
+
+ // init the support struct
+ RtlZeroMemory((PVOID)pWOWPort, sizeof(WOWPORT));
+
+ pWOWPort->h32 = h32;
+ pWOWPort->idComDev = idComDev;
+ pWOWPort->dwComDEB16 = DWORD32(parg16->f4);
+ pWOWPort->lpComDEB16 = lpComDEB16;
+ pWOWPort->dwThreadID = CURRENTPTD()->dwThreadID;
+ pWOWPort->hREvent = hREvent;
+ pWOWPort->cbWriteBuf = cbWriteBuf;
+ pWOWPort->cbWriteFree = cbWriteBuf - 1; // never use byte before head.
+ pWOWPort->pchWriteBuf = pchWriteBuf;
+ pWOWPort->pchWriteHead = pchWriteBuf;
+ pWOWPort->pchWriteTail = pchWriteBuf;
+ pWOWPort->hWriteEvent = hWriteEvent;
+ pWOWPort->cbWritePending = 0;
+ InitializeCriticalSection(&pWOWPort->csWrite);
+ pWOWPort->pdcb16 = pdcb16;
+ pWOWPort->cbInQ = cbInQ;
+
+ if (!(pWOWPort->olWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) {
+ LOGDEBUG(0, ("%s", "WU32OpenComm unable to create overlapped write event, failing.\n"));
+ ret = IE_MEMORY;
+ goto ErrorExit4;
+ }
+
+ PortTab[iTab].pWOWPort = pWOWPort;
+
+ //
+ // Create the writer thread and pass it pWOWPort as its
+ // parameter.
+ //
+
+ if (!fIsLPTPort) {
+ pWOWPort->hWriteThread = CreateThread(
+ NULL, // lpsa
+ 0, // stack size (default)
+ WOWCommWriterThread, // start address
+ pWOWPort, // lpvThreadParm
+ 0, // fdwCreate
+ &dwWriteThreadId
+ );
+
+ if (!pWOWPort->hWriteThread) {
+ ret = IE_MEMORY;
+ goto ErrorExit5;
+ }
+ }
+
+ ret = idComDev; // return the idComDev
+ goto CleanExit;
+
+// this is the error code path
+ErrorExit5:
+ CloseHandle(pWOWPort->olWrite.hEvent);
+
+ErrorExit4:
+ free_w(pWOWPort);
+
+ErrorExit3:
+ if (hREvent) { CloseHandle(hREvent); }
+ if (hWriteEvent) { CloseHandle(hWriteEvent); }
+ if (fIsLPTPort) { free_w(pdcb16); }
+
+ErrorExit2:
+ if(pchWriteBuf) { free_w(pchWriteBuf); }
+
+ErrorExit1:
+ CloseHandle(h32);
+
+ErrorExit0:
+ LOGDEBUG (0, ("WOW::WU32OpenComm failed\n"));
+
+CleanExit:
+ FREEVDMPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN((ULONG)ret); // return error
+}
+
+
+//
+// WriteComm()
+//
+// Win3.1 returns:
+// # bytes written on success (*= -1 on error).
+// 0 for bad idComDev OR if app specifies to write 0 bytes.
+// -1 if port hasn't been opened,
+//
+
+ULONG FASTCALL WU32WriteComm(PVDMFRAME pFrame)
+{
+ register PWRITECOMM16 parg16;
+ LONG i = -1;
+ PSZ psz2;
+ PWOWPORT pwp;
+ UINT idComDev;
+ PWOWPORT pWOWPort;
+ DWORD cbWritten;
+
+
+ GETARGPTR(pFrame, sizeof(WRITECOMM16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+
+ idComDev = UINT32(parg16->f1);
+ // this will be true only if the (valid) port has been opened
+ if (pWOWPort = GETPWOWPTR(idComDev)) {
+
+ if(VALIDCOM(idComDev)) {
+
+ if ((pwp = GETPWOWPTR(UINT32(parg16->f1))) && psz2) {
+
+ // if the app is interested in timeouts...
+ if(pwp->lpComDEB16->MSRMask) {
+
+ // ...see if RLSD, CTS, & DSR timeout before going high
+ if(MSRWait(pwp)) {
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ return(0); // this is what Win3.1 does for Timeouts
+ }
+ }
+
+ i = EnqueueCommWrite(pwp, psz2, parg16->f3);
+ if (i != parg16->f3) {
+ i = -i;
+ pwp->dwErrCode |= CE_TXFULL;
+ }
+ }
+ }
+
+ // else LPT's go this way...
+ else {
+
+ //
+ // This call to WriteFile could block, but I don't think
+ // that's a problem. - DaveHart
+ //
+ if ((pwp = GETPWOWPTR(UINT32(parg16->f1))) && psz2) {
+
+ if (!WriteFile(pwp->h32, psz2, parg16->f3, &cbWritten, &pwp->olWrite)) {
+
+ if (ERROR_IO_PENDING == GetLastError() ) {
+
+ //
+ // Wait for the write to complete or for us to
+ // be alerted that the port is closing.
+ //
+
+ if (GetOverlappedResult(pwp->h32,
+ &pwp->olWrite,
+ &cbWritten,
+ TRUE
+ )) {
+ i = cbWritten;
+ goto WriteSuccess;
+ }
+ }
+ LOGDEBUG(0, ("WU32WriteComm: WriteFile to id %u fails (error %u)\n",
+ pwp->idComDev, GetLastError()));
+ if (cbWritten) {
+ i = cbWritten;
+ i = -i;
+ }
+ }
+ else {
+ i = cbWritten;
+ }
+ }
+ }
+ }
+ else if(!(VALIDCOM(idComDev) || VALIDLPT(idComDev))) {
+ i = 0;
+ }
+WriteSuccess:
+
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN((ULONG)i);
+}
+
+
+// Win3.1 returns:
+// # chars read on success.
+// 0 for: bad idComDev, cbRead == 0, LPTx, port not open, 0 chars read,
+// OR for general comm error.
+ULONG FASTCALL WU32ReadComm(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ ULONG cb;
+ BOOL fUnGet = FALSE;
+ UINT idComDev;
+ PBYTE pb2;
+ PWOWPORT pWOWPort;
+ OVERLAPPED Rol;
+ register PREADCOMM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(READCOMM16), parg16);
+ GETMISCPTR(parg16->f2, pb2);
+
+ cb = (ULONG)UINT32(parg16->f3);
+ if((cb != 0) && pb2) {
+
+ idComDev = UINT32(parg16->f1);
+ if (VALIDCOM(idComDev) && (pWOWPort = PortTab[idComDev].pWOWPort)) {
+
+ // if an UnGot char is pending
+ if (pWOWPort->fUnGet) {
+ fUnGet = TRUE;
+ pWOWPort->fUnGet = FALSE;
+ *pb2++ = pWOWPort->cUnGet;
+
+ // this line commented out 8/3/95
+ // cb--; // we now need one less char
+
+ // In order to make this work correctly we should cb-- above
+ // to reflect the ungot char, unfortunately Win3.1 & Win95
+ // don't do that so we will maintain this bug for "ouch!"
+ // compatibility. a-craigj 8/3/95
+
+ }
+
+ // TonyE claims we should do this before each read to avoid problems
+ Rol.Internal = 0;
+ Rol.InternalHigh = 0;
+ Rol.Offset = 0;
+ Rol.OffsetHigh = 0;
+ Rol.hEvent = pWOWPort->hREvent;
+
+ if (!ReadFile(pWOWPort->h32,
+ pb2,
+ cb,
+ (LPDWORD)&ul,
+ &Rol)) {
+
+ if (ERROR_IO_PENDING == GetLastError()) {
+
+ if (!GetOverlappedResult(pWOWPort->h32,
+ &Rol,
+ &ul,
+ TRUE
+ )) {
+
+ LOGDEBUG(0, ("WOW::WU32ReadComm:GetOverlappedResult failed, error = 0x%x\n",
+ GetLastError()));
+ ul = 0;
+
+ }
+
+ } else {
+
+ LOGDEBUG(0, ("WOW::WU32ReadComm:ReadFile failed, error = 0x%x\n",
+ GetLastError()));
+ ul = 0;
+ }
+ }
+
+ if(fUnGet) {
+ ul++; // account for ungot char
+ pb2--; // accounts for previous pb2++ for FREEVDMPTR
+ }
+
+ FLUSHVDMPTR(parg16->f2, (USHORT)ul, pb2);
+
+ }
+
+ FREEVDMPTR(pb2);
+ }
+
+ WOW32ASSERTMSG((ul>=0), ("WOW::WU32ReadComm: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// Error word on success OR LPTx.
+// 0x8000 on bad idComDev.
+ULONG FASTCALL WU32SetCommBreak(PVDMFRAME pFrame)
+{
+ ULONG ul = 0x00008000;
+ UINT idComDev;
+ PWOWPORT pWOWPort;
+ register PSETCOMMBREAK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCOMMBREAK16), parg16);
+
+ idComDev = UINT32(parg16->f1);
+ if (pWOWPort = GETPWOWPTR(idComDev)) {
+ if(VALIDCOM(idComDev)) {
+ if(!SetCommBreak(pWOWPort->h32)) {
+ WOWGetCommError(pWOWPort);
+ }
+ }
+ ul = pWOWPort->dwErrCode; // Win3.1 returns last err
+ }
+
+ WOW32ASSERTMSG((ul!=CE_MODE), ("WOW::WU32SetCommBreak: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// A 16:16 ptr into the DEB struct on success.
+// 0 on any error OR LPT.
+// The 16:16 ptr that we return to the app was actually obtained in
+// IOpenComm() in user.exe.
+ULONG FASTCALL WU32SetCommEventMask(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ BOOL fOK = TRUE;
+ UINT idComDev;
+ DWORD dwDEBAddr;
+ PWOWPORT pWOWPort;
+ register PSETCOMMEVENTMASK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCOMMEVENTMASK16), parg16);
+
+ idComDev = UINT32(parg16->f1);
+ if ((VALIDCOM(idComDev)) && (pWOWPort = PortTab[idComDev].pWOWPort)) {
+
+ // if the Modem interrupt thread hasn't been started yet -- go start it
+ if(pWOWPort->hMiThread == NULL) {
+
+ // start our Modem interrupt thread
+ if(!WOWStartModemIntThread(pWOWPort)) {
+ fOK = FALSE;
+ }
+ }
+
+ // if everything is hunky-dory...
+ if(fOK) {
+
+ // success: Win3.1 returns 16:16 protect mode ptr to
+ // DEB->EvtWord (some apps subtract offset of EvtWord
+ // from ptr to get start of DEB).
+ dwDEBAddr = LOWORD(pWOWPort->dwComDEB16) << 16;
+ ul = dwDEBAddr + FIELD_OFFSET(COMDEB16, EvtWord);
+
+ // save the mask the app requested
+ pWOWPort->lpComDEB16->EvtMask = (WORD)(parg16->f2);
+ }
+ }
+
+ WOW32ASSERTMSG((ul!=0), ("WOW::WU32SETCOMMEVENTMASK: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// 0 on success OR LPTx.
+// IE_BADID for bad idComDev.
+// IE_NOPEN if file hasn't been opened.
+// IE_BAUDRATE for bad baud rate.
+// IE_BYTESIZE for bad byte size.
+// IE_DEFAULT for bad parity or stop bits.
+ULONG FASTCALL WU32SetCommState(PVDMFRAME pFrame)
+{
+ ULONG ul = (ULONG)IE_BADID;
+ UINT idComDev;
+ PDCB16 pdcb16;
+ DCB dcb32;
+ PWOWPORT pWOWPort;
+ register PSETCOMMSTATE16 parg16;
+ DWORD dwMSR;
+
+ GETARGPTR(pFrame, sizeof(SETCOMMSTATE16), parg16);
+ GETMISCPTR(parg16->f1, pdcb16);
+
+ if(pdcb16) {
+
+ idComDev = pdcb16->Id;
+ if(pWOWPort = GETPWOWPTR(idComDev)) {
+
+ if(VALIDCOM(idComDev)) {
+ DCB16toDCB32(pWOWPort, &dcb32, pdcb16);
+
+ if(SetCommState(pWOWPort->h32, &dcb32)) {
+ ul = 0;
+
+ // Win 3.1 initializes the MSRShadow during SetCommState
+ // so we will too. InterNet in a Box Dialer depends on it.
+ GetCommModemStatus(pWOWPort->h32, &dwMSR);
+ dwMSR &= MSR_STATEONLY;
+ pWOWPort->lpComDEB16->MSRShadow = LOBYTE(LOWORD(dwMSR));
+ }
+ else {
+ ul = (ULONG)IE_DEFAULT; // we just say something's wrong
+ }
+
+ }
+ else {
+ RtlCopyMemory((PVOID)pWOWPort->pdcb16,
+ (PVOID)pdcb16,
+ sizeof(DCB16));
+ ul = 0;
+ }
+ }
+ // else if they got a handle that looks good but they didn't open port
+ else if (VALIDCOM(idComDev) || VALIDLPT(idComDev)) {
+ ul = (ULONG)IE_NOPEN;
+ }
+
+ FREEMISCPTR(pdcb16);
+ }
+
+
+ WOW32ASSERTMSG((ul>=0), ("WOW::WU32SetCommState: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+// Win3.1 returns:
+// 0 for success.
+// 0x8000 for bad idComDev.
+// 0x4000 if char can't be sent.
+ULONG FASTCALL WU32TransmitCommChar(PVDMFRAME pFrame)
+{
+ ULONG ul = 0x8000;
+ UINT idComDev;
+ CHAR ch;
+ PWOWPORT pWOWPort;
+ DWORD cbWritten;
+ register PTRANSMITCOMMCHAR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(TRANSMITCOMMCHAR16), parg16);
+
+ idComDev = UINT32(parg16->f1);
+ if (pWOWPort = GETPWOWPTR(idComDev)) {
+
+ if(VALIDCOM(idComDev)) {
+ if(TransmitCommChar(pWOWPort->h32, CHAR32(parg16->f2))) {
+ ul = 0; // Win3.1 returns 0 on success
+ }
+ else {
+ ul = (ULONG)ERR_XMIT;
+ }
+ }
+
+ // else LPT's go this way...
+ else {
+
+ //
+ // This call to WriteFile could block, but I don't think
+ // that's a problem. - DaveHart
+ //
+
+ ch = CHAR32(parg16->f2);
+ ul = ERR_XMIT;
+ if (pWOWPort = GETPWOWPTR(UINT32(parg16->f1))) {
+
+ if (!WriteFile(pWOWPort->h32, &ch, 1, &cbWritten, &pWOWPort->olWrite)) {
+
+ if (ERROR_IO_PENDING == GetLastError() ) {
+
+ //
+ // Wait for the write to complete or for us to
+ // be alerted that the port is closing.
+ //
+
+ if (GetOverlappedResult(pWOWPort->h32,
+ &pWOWPort->olWrite,
+ &cbWritten,
+ TRUE
+ )) {
+ ul = 0;
+ goto TransmitSuccess;
+ }
+ }
+ LOGDEBUG(0, ("WU32TransmitCommChar: WriteFile to id %u fails (error %u)\n",
+ pWOWPort->idComDev, GetLastError()));
+ }
+ else {
+ ul = 0;
+ }
+ }
+
+ }
+ }
+TransmitSuccess:
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+// Win3.1 returns:
+// 0 on success OR bad idComDev OR LPTx.
+// -1 if port not open OR if ungot char already pending.
+ULONG FASTCALL WU32UngetCommChar(PVDMFRAME pFrame)
+{
+ ULONG ul = (ULONG)-1;
+ UINT idComDev;
+ PWOWPORT pWOWPort;
+ register PUNGETCOMMCHAR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(UNGETCOMMCHAR16), parg16);
+
+ // see if port open...
+ idComDev = UINT32(parg16->f1);
+ if (VALIDCOM(idComDev)) {
+
+ if (pWOWPort = PortTab[idComDev].pWOWPort) {
+
+ // if ungot char already pending return -1
+ if(pWOWPort->fUnGet == FALSE) {
+ pWOWPort->fUnGet = TRUE;
+ pWOWPort->cUnGet = CHAR32(parg16->f2);
+ ul = 0;
+ }
+ }
+ }
+ else {
+ ul = 0;
+ }
+
+ WOW32ASSERTMSG((ul==0), ("WOW::WU32UngetCommChar: failed\n"));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+DWORD Baud16toBaud32(UINT BaudRate)
+{
+ UINT DLatch;
+
+ // this function is set up this way on purpose (see SetCom300 ibmsetup.asm)
+
+ // get the equivalent baud
+ switch(BaudRate) {
+
+ // it they specified the baud rate directly
+ case CBR_110:
+ case CBR_300:
+ case CBR_600:
+ case CBR_1200:
+ case CBR_2400:
+ case CBR_4800:
+ case CBR_9600:
+ case CBR_19200:
+ case CBR_14400:
+ case CBR_38400:
+ case CBR_56000: return(BaudRate);
+
+ // Win3.1 baud rate constants
+ case W31CBR_110: return(CBR_110);
+ case W31CBR_300: return(CBR_300);
+ case W31CBR_600: return(CBR_600);
+ case W31CBR_1200: return(CBR_1200);
+ case W31CBR_2400: return(CBR_2400);
+ case W31CBR_4800: return(CBR_4800);
+ case W31CBR_9600: return(CBR_9600);
+ case W31CBR_19200: return(CBR_19200);
+ case W31CBR_14400: return(CBR_14400);
+ case W31CBR_38400: return(CBR_38400);
+ case W31CBR_56000: return(CBR_56000);
+
+ // start special cases
+ // SmartCom uses this to get 115200
+ case W31CBR_115200: return(CBR_115200);
+
+ // Win3.1 fails these two (even though they're defined in windows.h)
+ // but they just might work on NT
+ case W31CBR_128000: return(CBR_128000);
+ case W31CBR_256000: return(CBR_256000);
+ // end special cases
+
+ // handle the blank table entries for "reserved"
+ case W31CBR_reserved1:
+ case W31CBR_reserved2:
+ case W31CBR_reserved3:
+ case W31CBR_reserved4:
+ case W31CBR_reserved5: return(0);
+
+ // avoid divide by zero
+ case 0:
+ case 1: return(0);
+
+ // handle obscure specifications that will work in Win3.1
+ default:
+
+ // get the integer divisor latch value
+ DLatch = CBR_115200 / BaudRate;
+
+ switch(DLatch) {
+ case W31_DLATCH_110: return(CBR_110);
+ case W31_DLATCH_300: return(CBR_300);
+ case W31_DLATCH_600: return(CBR_600);
+ case W31_DLATCH_1200: return(CBR_1200);
+ case W31_DLATCH_2400: return(CBR_2400);
+ case W31_DLATCH_4800: return(CBR_4800);
+ case W31_DLATCH_9600: return(CBR_9600);
+ case W31_DLATCH_19200: return(CBR_19200);
+ case W31_DLATCH_14400: return(CBR_14400);
+ case W31_DLATCH_38400: return(CBR_38400);
+ case W31_DLATCH_56000: return(CBR_56000);
+ case W31_DLATCH_115200: return(CBR_115200);
+
+ // Win3.1, anything else returns whatever DLatch happens to be
+ // since we're mapping to baud we return the specified baud
+ default: return(BaudRate);
+ }
+ }
+}
+
+
+
+
+WORD Baud32toBaud16(DWORD BaudRate)
+{
+ if(BaudRate >= CBR_115200) {
+ switch(BaudRate) {
+ case CBR_256000: return(W31CBR_256000);
+ case CBR_128000: return(W31CBR_128000);
+ case CBR_115200:
+ default: return(W31CBR_115200);
+ }
+ }
+ else {
+ return(LOWORD(BaudRate));
+ }
+}
+
+
+
+
+
+void DCB16toDCB32(PWOWPORT pWOWPort, LPDCB lpdcb32, PDCB16 pdcb16)
+{
+
+ // zero 32-bit struct -> any flags and fields not explicitly set will be 0
+ RtlZeroMemory((PVOID)lpdcb32, sizeof(DCB));
+
+ lpdcb32->DCBlength = sizeof(DCB);
+ lpdcb32->BaudRate = Baud16toBaud32(pdcb16->BaudRate);
+
+ // 16-bit bitfields may align differently with 32-bit compilers
+ // we use this mechanism to align them the way Win3.1 expects them
+ if(pdcb16->wFlags & W31DCB_fBinary) lpdcb32->fBinary = 1;
+ if(pdcb16->wFlags & W31DCB_fParity) lpdcb32->fParity = 1;
+ if(pdcb16->wFlags & W31DCB_fOutxCtsFlow) lpdcb32->fOutxCtsFlow = 1;
+ if(pdcb16->wFlags & W31DCB_fOutxDsrFlow) lpdcb32->fOutxDsrFlow = 1;
+
+ // set up mechanism for handling event char notification
+ if(pdcb16->wFlags & W31DCB_fChEvt) pWOWPort->fChEvt = TRUE;
+
+ if(pdcb16->wFlags & W31DCB_fDtrFlow) {
+ lpdcb32->fDtrControl = DTR_CONTROL_HANDSHAKE;
+ }
+ else if(pdcb16->wFlags & W31DCB_fDtrDisable) {
+ lpdcb32->fDtrControl = DTR_CONTROL_DISABLE;
+ }
+ else {
+ lpdcb32->fDtrControl = DTR_CONTROL_ENABLE;
+ }
+
+ if(pdcb16->wFlags & W31DCB_fOutX) lpdcb32->fOutX = 1;
+ if(pdcb16->wFlags & W31DCB_fInX) lpdcb32->fInX = 1;
+ if(pdcb16->wFlags & W31DCB_fPeChar) lpdcb32->fErrorChar = 1;
+ if(pdcb16->wFlags & W31DCB_fNull) lpdcb32->fNull = 1;
+
+ if(pdcb16->wFlags & W31DCB_fRtsFlow) {
+ lpdcb32->fRtsControl = RTS_CONTROL_HANDSHAKE;
+ }
+ else if(pdcb16->wFlags & W31DCB_fRtsDisable) {
+ lpdcb32->fRtsControl = RTS_CONTROL_DISABLE;
+ }
+ else {
+ lpdcb32->fRtsControl = RTS_CONTROL_ENABLE;
+ }
+
+ if(pdcb16->wFlags & W31DCB_fDummy2) lpdcb32->fDummy2 = 1;
+
+ // Check the passed in XonLim & XoffLim values against the cbInQ value.
+ // Prodigy's modem detector leaves these values uninitialized.
+ if ((pdcb16->XonLim >= pWOWPort->cbInQ) ||
+ (pdcb16->XoffLim > pWOWPort->cbInQ) ||
+ (pdcb16->XonLim >= pdcb16->XoffLim)) {
+ lpdcb32->XonLim = 0;
+ lpdcb32->XoffLim = (WORD)(pWOWPort->cbInQ - (pWOWPort->cbInQ >> 2));
+ }
+ else {
+ lpdcb32->XonLim = pdcb16->XonLim;
+ lpdcb32->XoffLim = pdcb16->XoffLim;
+ }
+
+ lpdcb32->ByteSize = pdcb16->ByteSize;
+ lpdcb32->Parity = pdcb16->Parity;
+ lpdcb32->StopBits = pdcb16->StopBits;
+
+ // Digiboard driver doesn't want to see XonChar == XoffChar even if
+ // xon/xoff is disabled.
+ if ((pdcb16->XonChar == '\0') && (lpdcb32->XoffChar == '\0')) {
+ lpdcb32->XonChar = pdcb16->XonChar+1;
+ }
+ else {
+ lpdcb32->XonChar = pdcb16->XonChar;
+ }
+
+ lpdcb32->XoffChar = pdcb16->XoffChar;
+ lpdcb32->ErrorChar = pdcb16->PeChar;
+ lpdcb32->EofChar = pdcb16->EofChar;
+ lpdcb32->EvtChar = pdcb16->EvtChar;
+
+ // set up for RLSD, CTS, and DSR timeout support (not supported on NT)
+ pWOWPort->lpComDEB16->MSRMask = 0;
+
+ pWOWPort->RLSDTimeout = pdcb16->RlsTimeout;
+ if(pWOWPort->RLSDTimeout != IGNORE_TIMEOUT)
+ pWOWPort->lpComDEB16->MSRMask |= LOBYTE(MS_RLSD_ON);
+
+ pWOWPort->CTSTimeout = pdcb16->CtsTimeout;
+ if(pWOWPort->CTSTimeout != IGNORE_TIMEOUT)
+ pWOWPort->lpComDEB16->MSRMask |= LOBYTE(MS_CTS_ON);
+
+ pWOWPort->DSRTimeout = pdcb16->DsrTimeout;
+ if(pWOWPort->DSRTimeout != IGNORE_TIMEOUT)
+ pWOWPort->lpComDEB16->MSRMask |= LOBYTE(MS_DSR_ON);
+
+ // these fields remain 0
+ //lpdcb32->fDsrSensitivity = 0;
+ //lpdcb32->fTXContinueOnXoff = 0;
+ //lpdcb32->fAbortOnError = 0;
+ //lpdcb32->wReserved = 0;
+
+}
+
+
+
+void DCB32toDCB16(PDCB16 pdcb16, LPDCB lpdcb32, UINT idComDev, BOOL fChEvt)
+{
+
+ // zero 16-bit struct -> any flags and fields not explicitly set will be 0
+ RtlZeroMemory((PVOID)pdcb16, sizeof(DCB16));
+
+ // set this field no matter what
+ pdcb16->Id = (BYTE)idComDev;
+
+ // if a COMx (Win3.1 leaves the rest 0 for LPT's)
+ if(VALIDCOM(idComDev)) {
+ pdcb16->Id = (BYTE)idComDev;
+
+ // these are the "ComX:96,n,8,1" fields
+ pdcb16->BaudRate = Baud32toBaud16(lpdcb32->BaudRate);
+ pdcb16->ByteSize = lpdcb32->ByteSize;
+ pdcb16->Parity = lpdcb32->Parity;
+ pdcb16->StopBits = lpdcb32->StopBits;
+
+ // 16-bit bitfields may align differently with 32-bit compilers
+ // we use this mechanism to align them the way Win3.1 expects them
+ if(lpdcb32->fBinary) pdcb16->wFlags |= W31DCB_fBinary;
+
+ if(lpdcb32->fRtsControl == RTS_CONTROL_DISABLE) {
+ pdcb16->wFlags |= W31DCB_fRtsDisable;
+ }
+
+ if(lpdcb32->fParity) pdcb16->wFlags |= W31DCB_fParity;
+ if(lpdcb32->fOutxCtsFlow) pdcb16->wFlags |= W31DCB_fOutxCtsFlow;
+ if(lpdcb32->fOutxDsrFlow) pdcb16->wFlags |= W31DCB_fOutxDsrFlow;
+
+ if(lpdcb32->fDtrControl == DTR_CONTROL_DISABLE) {
+ pdcb16->wFlags |= W31DCB_fDtrDisable;
+ }
+
+ if(lpdcb32->fOutX) pdcb16->wFlags |= W31DCB_fOutX;
+ if(lpdcb32->fInX) pdcb16->wFlags |= W31DCB_fInX;
+ if(lpdcb32->fErrorChar) pdcb16->wFlags |= W31DCB_fPeChar;
+ if(lpdcb32->fNull) pdcb16->wFlags |= W31DCB_fNull;
+
+ if(fChEvt) pdcb16->wFlags |= W31DCB_fChEvt;
+
+ if(lpdcb32->fDtrControl == DTR_CONTROL_HANDSHAKE) {
+ pdcb16->wFlags |= W31DCB_fDtrFlow;
+ }
+
+ if(lpdcb32->fRtsControl == RTS_CONTROL_HANDSHAKE) {
+ pdcb16->wFlags |= W31DCB_fRtsFlow;
+ }
+
+ if(lpdcb32->fDummy2) pdcb16->wFlags |= W31DCB_fDummy2;
+
+ pdcb16->XonChar = lpdcb32->XonChar;
+ pdcb16->XoffChar = lpdcb32->XoffChar;
+ pdcb16->XonLim = lpdcb32->XonLim;
+ pdcb16->XoffLim = lpdcb32->XoffLim;
+ pdcb16->PeChar = lpdcb32->ErrorChar;
+ pdcb16->EofChar = lpdcb32->EofChar;
+ pdcb16->EvtChar = lpdcb32->EvtChar;
+
+ }
+
+ // these fields remain 0
+ //pdcb16->fDummy = 0;
+ //pdcb16->TxDelay = 0;
+
+}
+
+
+
+
+BOOL DeletePortTabEntry(PWOWPORT pWOWPort)
+{
+ INT iTab;
+ BOOL fTimeOut;
+
+ iTab = pWOWPort->idComDev;
+ if(VALIDLPT(iTab)) {
+ iTab = GETLPTID(iTab);
+ }
+
+ // flush I/O buffers & attempt to wake up Modem Interrupt thread (if any)
+ pWOWPort->fClose = TRUE;
+ if(VALIDCOM(iTab)) {
+ PurgeComm(pWOWPort->h32, PURGE_TXCLEAR);
+ PurgeComm(pWOWPort->h32, PURGE_RXCLEAR);
+ SetCommMask(pWOWPort->h32, 0); // this should wake up the Mi thread
+
+ // wake up WOWModemIntThread & tell it to exit
+ // (we attempt to block (1.5 second max.) until it does)
+ if(pWOWPort->hMiThread) {
+ WaitForSingleObject(pWOWPort->hMiThread, 1500);
+ CloseHandle(pWOWPort->hMiThread);
+
+ // zero COMDEB
+ RtlZeroMemory((PVOID)pWOWPort->lpComDEB16, sizeof(COMDEB16));
+ }
+
+ //
+ // Wake up WOWCommWriterThread so it will exit, wait up to
+ // 5 sec for it to go away.
+ //
+
+ SetEvent(pWOWPort->hWriteEvent);
+
+ fTimeOut = (WaitForSingleObject(pWOWPort->hWriteThread, 5000) ==
+ WAIT_TIMEOUT);
+
+#ifdef DEBUG
+ if (fTimeOut) {
+ LOGDEBUG(LOG_ALWAYS,
+ ("WOW DeletePortTabEntry: Comm writer thread for port %d refused\n"
+ " to die when asked nicely.\n", (int)pWOWPort->idComDev));
+ }
+#endif
+
+ CloseHandle(pWOWPort->hWriteThread);
+ CloseHandle(pWOWPort->hWriteEvent);
+ free_w(pWOWPort->pchWriteBuf);
+
+ CloseHandle(pWOWPort->hREvent);
+ }
+ // else free the LPT DCB support struct
+ else {
+ free_w(pWOWPort->pdcb16);
+ CloseHandle(pWOWPort->olWrite.hEvent);
+ fTimeOut = FALSE;
+ }
+
+ DeleteCriticalSection(&pWOWPort->csWrite);
+ CloseHandle(pWOWPort->h32);
+
+ free_w(pWOWPort);
+ PortTab[iTab].pWOWPort = NULL;
+
+ return(fTimeOut);
+}
+
+
+
+UINT GetModePortTabIndex(PSZ pszModeStr)
+{
+
+ CHAR szPort[MAXCOMNAMENULL*2];
+
+ if(pszModeStr) {
+ if(GetPortName(pszModeStr, szPort)) {
+ return(GetStrPortTabIndex(szPort));
+ }
+ }
+
+ return((UINT)IE_BADID);
+
+}
+
+
+
+BOOL GetPortName(LPSTR pszMode, LPSTR pszPort)
+{
+
+ INT len;
+ CHAR szTemp[80]; // max len we'll take for DOS style MODE command
+ BOOL bRet = FALSE;
+
+ len = strlen(pszMode);
+ if((len >= 3) && (len < 80)) {
+
+ // Get the first token from the mode string.
+ GetPortStringToken(pszMode, szTemp);
+
+ // map "AUX" or "PRN" to "COM1" or "LPT1" if necessary
+ len = strlen(szTemp);
+ if((len >= 3) && (len <= MAXCOMNAME)) { // "AUX" <= len <= "COMx"
+
+ strcpy(pszPort, szTemp);
+ CharUpper(pszPort);
+
+ // filter out duplicate names for the same thing
+ if(!strcmp(pszPort, "PRN")) {
+ strcpy(pszPort, "LPT1");
+ }
+ else if(!strcmp(pszPort, "AUX")) {
+ strcpy(pszPort, "COM1");
+ }
+
+ bRet = TRUE;
+ }
+ }
+
+ return(bRet);
+
+}
+
+PSZ StripPortName(PSZ psz)
+{
+ CHAR dummy[80]; // max len we'll take for DOS style MODE command
+
+ return(GetPortStringToken(psz, dummy));
+}
+
+//
+// Copy first token to pszToken. Return pointer to next token or NULL if none.
+// This code cloned from Win 3.1, COMDEV.C, field(). HGW 3.0 modem registration
+// passes "COMx,,," instead of "COMx:,,," so we need to handle all seperators.
+//
+
+PSZ GetPortStringToken(PSZ pszSrc, PSZ pszToken)
+{
+ char c;
+
+ // While not the end of the string.
+ while (c = *pszSrc) {
+ pszSrc++;
+
+ //Look for seperators.
+ if ((c == ' ') || (c == ':') || (c == ',')) {
+ *pszToken = '\0';
+
+ while (*pszSrc == ' ') {
+ pszSrc++;
+ }
+
+ if (*pszSrc) {
+ return(pszSrc);
+ }
+
+ return(NULL);
+ }
+
+ *pszToken++ = c;
+ }
+
+ *pszToken = '\0';
+
+ return(NULL);
+}
+
+
+UINT GetStrPortTabIndex(PSZ szPort)
+{
+ UINT iTab;
+
+ for(iTab = COM1; iTab < NUMPORTS; iTab++) {
+ if(!strcmp((LPCTSTR)PortTab[iTab].szPort, (LPCTSTR)szPort)) {
+ return(iTab);
+ }
+ }
+
+ return((UINT)IE_BADID);
+}
+
+
+
+BOOL InitDCB32(LPDCB pdcb32, LPSTR pszModeStr)
+{
+ BOOL bRet = FALSE;
+ LPSTR pszParams;
+
+ // eliminate "COMx:" from mode string leaving ptr to parameters string
+ pszParams = StripPortName(pszModeStr);
+
+ // if there are params... (some apps pass "com1:" -- hence 2nd test)
+ if(pszParams) {
+
+ // initialize everything to 0 (especially the flags)
+ RtlZeroMemory((PVOID)pdcb32, sizeof(DCB));
+
+ // NOTE: 32-bit BuildCommDCB ONLY touches fields associated with psz1
+ if(BuildCommDCB(pszParams, pdcb32)) {
+
+ pdcb32->DCBlength = sizeof(DCB);
+
+ // fill in specific fields a la Win3.1
+ // NOTE: fields are 0 unless explicitly set
+ pdcb32->fBinary = 1;
+ pdcb32->fDtrControl = DTR_CONTROL_ENABLE; //same as fDTRDisable == 0
+ pdcb32->fRtsControl = RTS_CONTROL_ENABLE; //same as fRTSDisable == 0
+
+ pdcb32->XonLim = 10;
+ pdcb32->XoffLim = 10;
+ pdcb32->XonChar = 0x11; // Ctrl-Q
+ pdcb32->XoffChar = 0x13; // Ctrl-S
+
+ bRet = TRUE;
+ }
+ }
+
+ return(bRet);
+}
+
+
+
+VOID InitDEB16(PCOMDEB16 pComDEB16, UINT iTab, WORD QInSize, WORD QOutSize)
+{
+ VPVOID vpBiosData;
+ PWORD16 pwBiosData;
+
+ // Win3.1 init's most the stuff to zero except as handled below
+ RtlZeroMemory((PVOID)pComDEB16, sizeof(COMDEB16));
+
+ // get the I/O base address for the port
+ vpBiosData = (VPVOID)(RM_BIOS_DATA + (iTab * sizeof(WORD)));
+ if(pwBiosData = (PWORD16)GetRModeVDMPointer(vpBiosData)) {
+ pComDEB16->Port = (WORD)*pwBiosData;
+ FREEVDMPTR(pwBiosData);
+ }
+
+ pComDEB16->RecvTrigger = (WORD)-1;
+ pComDEB16->QInSize = QInSize;
+ pComDEB16->QOutSize = QOutSize;
+
+}
+
+/* start thread for Modem interrupt emulation */
+BOOL WOWStartModemIntThread(PWOWPORT pWOWPort)
+{
+ BOOL ret = FALSE;
+ DWORD dwUnused;
+ HANDLE hEvent, hMiThread;
+
+ // set up temporary semaphore to sync with Modem interrupt thread
+ if((hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) {
+ goto ErrorExit0;
+ }
+
+ // use pWOWPort->hMiThread temporarily to help start the thread
+ pWOWPort->hMiThread = hEvent;
+
+ // create the MSR thread
+ if((hMiThread = CreateThread(NULL,
+ 8192,
+ (LPTHREAD_START_ROUTINE)WOWModemIntThread,
+ (PWOWPORT)pWOWPort,
+ 0,
+ (LPDWORD)&dwUnused)) == NULL) {
+ goto ErrorExit1;
+ }
+
+ // block until thread notifies us that it has started
+ WaitForSingleObject(hEvent, INFINITE);
+
+ pWOWPort->hMiThread = hMiThread;
+
+ CloseHandle(hEvent);
+ ret = TRUE;
+
+ goto FunctionExit;
+
+
+// this is the error code path
+ErrorExit1:
+ CloseHandle(hEvent);
+
+ErrorExit0:
+ pWOWPort->hMiThread = NULL;
+
+
+FunctionExit:
+ WOW32ASSERTMSG((ret),("WOW::W32StartModemIntThread failed\n"));
+ return(ret);
+
+}
+
+
+
+// Modem Interrupt thread for SetCommEventMask/EnableCommNotification support
+// Tries to emulate the interrupt handling in ibmint.asm of Win3.1 comm.drv.
+// Our "interrupts" here are the events from the NT serial comm stuff
+VOID WOWModemIntThread(PWOWPORT pWOWPort)
+{
+ BOOL fRing = FALSE;
+ UINT iTab;
+ DWORD dwRing;
+ DWORD dwEvts = 0;
+ DWORD dwEvtOld = 0;
+ DWORD dwEvtWord = 0;
+ DWORD dwMSR = 0;
+ DWORD dwErrCode = 0;
+ DWORD cbTransfer;
+ HANDLE h32;
+ PCOMDEB16 lpComDEB16;
+ OVERLAPPED ol;
+
+ iTab = pWOWPort->idComDev;
+ lpComDEB16 = pWOWPort->lpComDEB16;
+ h32 = pWOWPort->h32;
+
+ // set the current modem status & Event word
+ lpComDEB16->MSRShadow = (BYTE)0;
+ lpComDEB16->EvtWord = (WORD)0;
+ lpComDEB16->ComErr = (WORD)0;
+ lpComDEB16->QInCount = (WORD)0;
+ lpComDEB16->QOutCount = (WORD)0;
+
+ if(VALIDLPT(iTab)) {
+ iTab = GETLPTID(iTab);
+ }
+
+ ol.Internal = 0;
+ ol.InternalHigh = 0;
+ ol.Offset = 0;
+ ol.OffsetHigh = 0;
+ ol.hEvent = CreateEvent(NULL,
+ TRUE,
+ FALSE,
+ (LPTSTR)PortTab[iTab].szPort);
+
+ // activate modem events in the mask, we want to emulate all the interrupts
+ SetCommMask(h32, EV_NTEVENTS);
+
+ // wake up the thread that created this thread in WOWStartModemIntThread()
+ SetEvent(pWOWPort->hMiThread);
+
+ while(!pWOWPort->fClose) {
+
+ // wait for an event - hopefully this will be somewhat similar to
+ // the TimerProc in ibmint.asm which gets called every 100ms
+ if(!WaitCommEvent(h32, &dwEvts, &ol)) {
+
+ if(GetLastError() == ERROR_IO_PENDING) {
+
+ // ...block here 'til event specified in WaitCommEvent() occurs
+ if(!GetOverlappedResult(h32, &ol, &cbTransfer, TRUE)) {
+ LOGDEBUG(0, ("WOW::WUCOMM: WOWModemIntThread: Wait failed\n"));
+ }
+ }
+ else {
+ LOGDEBUG(0, ("WOW::WUCOMM: WOWModemIntThread : Overlap failed\n"));
+ }
+ }
+ ResetEvent(ol.hEvent);
+
+ // Get current MSR state, current state of delta bits isn't accurate for us
+ GetCommModemStatus(h32, &dwMSR);
+
+ dwMSR &= MSR_STATEONLY; // throw away delta bits
+
+
+ // set the DELTA bits in the shadow MSR
+ if(dwEvts & EV_CTS) dwMSR |= MSR_DCTS;
+
+ if(dwEvts & EV_DSR) dwMSR |= MSR_DDSR;
+
+ if(dwEvts & EV_RLSD) dwMSR |= MSR_DDCD;
+
+ if(dwEvts & EV_RING) {
+ fRing = TRUE;
+ dwRing = EV_RING;
+ }
+ else if(fRing) {
+ fRing = FALSE;
+ dwMSR |= MSR_TERI;
+ dwRing = EV_RingTe;
+ }
+ else {
+ dwRing = 0;
+ }
+
+ // Form the events
+ dwEvtOld = (DWORD)lpComDEB16->EvtWord;
+ dwEvtWord = 0;
+ dwEvtWord = dwRing | (dwEvts & (EV_ERR | EV_BREAK | EV_RXCHAR | EV_TXEMPTY | EV_CTS | EV_DSR | EV_RLSD | EV_RXFLAG));
+
+ // we have to figure the state bits out from the MSR
+
+ if(dwMSR & MS_CTS_ON) dwEvtWord |= EV_CTSS;
+ if(dwMSR & MS_DSR_ON) dwEvtWord |= EV_DSRS;
+ if(dwMSR & MS_RLSD_ON) dwEvtWord |= EV_RLSDS;
+
+ // One of the major tasks of this routine is to update the MSRShadow
+ // and EvtWord in the COMDEB16 structure.
+ //
+
+ //apply the msr as well
+ lpComDEB16->MSRShadow = LOBYTE(LOWORD(dwMSR));
+
+ // apply the event mask the app specified
+ lpComDEB16->EvtWord |= LOWORD(dwEvtWord) & lpComDEB16->EvtMask;
+
+ // The following code simluates the COM Notifcation functionality of
+ // Win 3.1.
+ //
+ // Notifications:
+ //
+ // if they want receive transmit notification & it's time to notify
+ // if there wasn't an Rx overflow continue...
+
+ if( lpComDEB16->NotifyHandle ) {
+
+ // get current error code & queue counts
+ WOWGetCommError(pWOWPort);
+
+ if((dwEvtWord & ( EV_RXCHAR | EV_RXFLAG )) &&
+ !(pWOWPort->dwErrCode & CE_RXOVER)) {
+
+ // if they want receive notification & it's time to notify
+ // apps should set RecvTrigger to -1 if they don't want notification
+ if((((SHORT)lpComDEB16->RecvTrigger) != -1) &&
+ (lpComDEB16->QInCount >= lpComDEB16->RecvTrigger)) {
+
+ // if the app hasn't already been notified of this ...
+ if(!(lpComDEB16->NotifyFlags & CN_RECEIVEHI)) {
+
+ PostMessage(HWND32(lpComDEB16->NotifyHandle),
+ WOW_WM_COMMNOTIFY,
+ MAKEWPARAM((WORD)pWOWPort->idComDev, 0),
+ MAKELPARAM(CN_RECEIVE, 0));
+
+ lpComDEB16->NotifyFlags |= CN_RECEIVEHI;
+ }
+ }
+ else {
+ lpComDEB16->NotifyFlags &= ~CN_RECEIVEHI;
+ }
+ }
+
+ // if they want receive transmit notification & it's time to notify
+ if(lpComDEB16->QOutCount < (SHORT)lpComDEB16->SendTrigger) {
+
+ // if the app hasn't already been notified of this ...
+ if(!(lpComDEB16->NotifyFlags & CN_TRANSMITHI)) {
+
+ PostMessage(HWND32(lpComDEB16->NotifyHandle),
+ WOW_WM_COMMNOTIFY,
+ MAKEWPARAM((WORD)pWOWPort->idComDev, 0),
+ MAKELPARAM(CN_TRANSMIT, 0));
+
+ lpComDEB16->NotifyFlags |= CN_TRANSMITHI;
+ }
+ }
+ else {
+ lpComDEB16->NotifyFlags &= ~CN_TRANSMITHI;
+ }
+
+ // if we are notifying the app of EV_ event's
+ if((lpComDEB16->NotifyFlags & CN_NOTIFYHI) &&
+ ((DWORD)lpComDEB16->EvtWord != dwEvtOld)) {
+
+ PostMessage(HWND32(lpComDEB16->NotifyHandle),
+ WOW_WM_COMMNOTIFY,
+ MAKEWPARAM((WORD)pWOWPort->idComDev, 0),
+ MAKELPARAM(CN_EVENT, 0));
+ }
+
+ // Now that we've processed all the interrupts, do the TimerProc.
+ // if we are notifying the app of anything in Rx queue
+ // this mimics the notification in the TimerProc (see ibmint.asm)
+ if(((SHORT)lpComDEB16->RecvTrigger != -1) &&
+ (lpComDEB16->QInCount != 0) &&
+ (!(lpComDEB16->NotifyFlags & CN_RECEIVEHI))) {
+
+ PostMessage(HWND32(lpComDEB16->NotifyHandle),
+ WOW_WM_COMMNOTIFY,
+ MAKEWPARAM((WORD)pWOWPort->idComDev, 0),
+ MAKELPARAM(CN_RECEIVE, 0));
+
+ lpComDEB16->NotifyFlags |= CN_RECEIVEHI;
+ }
+ }
+
+ // we've handled all interrupts, give control back to app
+ Sleep(0);
+
+ } // end thread loop
+
+ CloseHandle(ol.hEvent);
+
+ ExitThread(0);
+}
+
+
+
+DWORD WOWGetCommError(PWOWPORT pwp)
+{
+ COMSTAT cs;
+ DWORD dwErr;
+
+ ClearCommError(pwp->h32, &dwErr, &cs);
+
+ EnterCriticalSection(&pwp->csWrite);
+
+ //
+ // We do our own write buffering so we ignore
+ // the cbOutQue returned by ClearCommError, which
+ // only reflects pending writes.
+ //
+ // Number of bytes in our write queue is calculated
+ // using the size of the queue and the amount free
+ // in the queue, minus one. Minus one because
+ // there's one slot in the queue which is never used.
+ //
+
+ cs.cbOutQue = (pwp->cbWriteBuf - pwp->cbWriteFree) - 1;
+
+
+ LeaveCriticalSection(&pwp->csWrite);
+
+
+ // always update the status & preserve any error condition
+ pwp->cs = cs;
+ pwp->dwErrCode |= dwErr;
+ pwp->lpComDEB16->ComErr |= LOWORD(dwErr);
+
+ // always update the queue counts in the DEB
+ pwp->lpComDEB16->QInCount = LOWORD(cs.cbInQue);
+ pwp->lpComDEB16->QOutCount = LOWORD(cs.cbOutQue);
+
+ return(dwErr);
+}
+
+
+
+/* for hung/crashed app support */
+VOID FreeCommSupportResources(DWORD dwThreadID)
+{
+ UINT iTab;
+ PWOWPORT pWOWPort;
+
+ for(iTab = 0; iTab < NUMPORTS; iTab++) {
+ if(pWOWPort = PortTab[iTab].pWOWPort) {
+ if(pWOWPort->dwThreadID == dwThreadID) {
+ DeletePortTabEntry(pWOWPort);
+ break;
+ }
+ }
+ }
+}
+
+
+
+/* functions exported to the VDM */
+/* NOTE: idComDev: COM1 == 0, LPT1 == 0x80 */
+BYTE GetCommShadowMSR(WORD idComDev)
+{
+ BYTE MSR=0;
+ DWORD dwModemStatus;
+ PWOWPORT pWOWPort;
+
+ if (pWOWPort = GETPWOWPTR (idComDev)) {
+
+ if(pWOWPort->hMiThread) {
+ MSR = (BYTE)pWOWPort->lpComDEB16->MSRShadow;
+ }
+ else { // get it the slow way if SetCommEventMask() hasn't been called
+ GetCommModemStatus(pWOWPort->h32, &dwModemStatus);
+ MSR = (BYTE)LOBYTE(LOWORD(dwModemStatus));
+ }
+ }
+
+ return(MSR);
+}
+
+
+
+/* NOTE: idComDev: COM1 == 0, LPT1 == 0x80 */
+HANDLE GetCommHandle(WORD idComDev)
+{
+ PWOWPORT pWOWPort;
+
+ if (pWOWPort = GETPWOWPTR (idComDev)) {
+ return(pWOWPort->h32);
+ }
+
+ else {
+ return(NULL); // will return NULL if bad range of idComDev or if the
+ } // port wasn't initialized through an OpenComm() API call
+}
+
+
+
+//
+// EnqueueCommWrite - stuff characters into the Comm Write queue
+// assoicated with pWOWPort.
+//
+// Returns number of characters queued.
+//
+// This function takes care of entering/leaving the critsec.
+//
+
+USHORT EnqueueCommWrite(PWOWPORT pwp, PUCHAR pch, USHORT cb)
+{
+ USHORT cbWritten = 0;
+ USHORT cbToCopy;
+ USHORT cbChunk;
+ BOOL fQueueEmpty;
+
+ EnterCriticalSection(&pwp->csWrite);
+
+ fQueueEmpty = (pwp->pchWriteHead == pwp->pchWriteTail);
+
+ //
+ // cbToCopy is the total number of bytes that we are going to enqueue
+ //
+
+ cbToCopy = min(cb, pwp->cbWriteFree);
+
+ //
+ // Any write can be accomplished in at most two chunks.
+ // The first writes up until the buffer wraps, while
+ // the second starts at the beginning of the buffer.
+ //
+ // Do the first half, which may do it all.
+ //
+ // Number of bytes for the first chunk is the smaller of
+ // the total number of bytes free in the write buffer and
+ // the number of bytes free before the end of the buffer.
+ //
+
+ cbChunk = min(cbToCopy,
+ (pwp->pchWriteBuf + pwp->cbWriteBuf) - pwp->pchWriteTail);
+
+ RtlCopyMemory(pwp->pchWriteTail, pch, cbChunk);
+ pwp->cbWriteFree -= cbChunk;
+ pwp->pchWriteTail += cbChunk;
+ cbWritten += cbChunk;
+
+ //
+ // Tail pointer may have moved to point just beyond the buffer.
+ //
+
+ if (pwp->pchWriteTail >= pwp->pchWriteBuf + pwp->cbWriteBuf) {
+ WOW32ASSERT(pwp->pchWriteTail == pwp->pchWriteBuf + pwp->cbWriteBuf);
+ pwp->pchWriteTail = pwp->pchWriteBuf;
+ }
+
+ //
+ // Are we done?
+ //
+
+ if (cbWritten < cbToCopy) {
+
+ //
+ // I think this case should only be taken when we've wrapped, so
+ // be sure.
+ //
+ WOW32ASSERT(pwp->pchWriteTail == pwp->pchWriteBuf);
+
+ //
+ // Nope, do the second half.
+ //
+
+ cbChunk = min((cbToCopy - cbWritten), pwp->cbWriteFree);
+
+ RtlCopyMemory(pwp->pchWriteTail, pch + cbWritten, cbChunk);
+ pwp->cbWriteFree -= cbChunk;
+ pwp->pchWriteTail += cbChunk;
+ cbWritten += cbChunk;
+
+ WOW32ASSERT(pwp->pchWriteTail < pwp->pchWriteBuf + pwp->cbWriteBuf);
+
+ }
+
+ //
+ // If the buffer was empty to start with and we made it
+ // non-empty, issue the first WriteFile and signal the
+ // writer thread to wake up.
+ //
+
+ if (fQueueEmpty && cbWritten) {
+
+ pwp->cbWritePending = CALC_COMM_WRITE_SIZE(pwp);
+
+ if (!WriteFile(pwp->h32, pwp->pchWriteHead, pwp->cbWritePending,
+ &pwp->cbWritten, &pwp->olWrite)) {
+
+ if (ERROR_IO_PENDING == GetLastError()) {
+ pwp->fWriteDone = FALSE;
+ } else {
+ pwp->fWriteDone = TRUE;
+ LOGDEBUG(0, ("WOW EnqueueCommWrite: WriteFile to id %u fails (error %u)\n",
+ pwp->idComDev, GetLastError()));
+ }
+
+ } else {
+ pwp->fWriteDone = TRUE;
+ }
+
+ //
+ // Leave the critical section before setting the event. Otherwise
+ // the other thread could wake up when the event is set and immediately
+ // block on the critical section.
+ //
+
+ LeaveCriticalSection(&pwp->csWrite);
+ SetEvent(pwp->hWriteEvent);
+
+ } else {
+ LeaveCriticalSection(&pwp->csWrite);
+ }
+
+ return cbWritten;
+}
+
+
+
+//
+// WOWCommWriteThread created for COM ports only. This thread dequeues
+// characters from the write buffer and writes them to the COM port.
+// This thread uses pwp->hWriteEvent for two purposes:
+//
+// 1. The event is signalled by EnqueueCommWrite when the write
+// buffer had been empty but is not now. This wakes us up
+// so we can write to the port. Note that we will always
+// be in the WaitForSingleObject at the top of the function
+// in this case, since that's where we sleep when the buffer
+// is empty.
+//
+// 2. DeletePortTabEntry signals the event after setting
+// pwp->fClose to tell us the port is closing and we
+// need to clean up and terminate this thread. This
+// thread might be doing anything in this case, but
+// it is careful to check pwp->fClose before sleeping
+// again.
+//
+
+ULONG WOWCommWriterThread(LPVOID pWOWPortStruct)
+{
+ PWOWPORT pwp = (PWOWPORT)pWOWPortStruct;
+ HANDLE ah[2];
+
+ //
+ // Copy event handles into array for WaitForMultipleObjects.
+ //
+
+ ah[0] = pwp->hWriteEvent;
+ ah[1] = pwp->olWrite.hEvent;
+
+WaitForWriteOrder:
+
+ //
+ // pwp->fClose is TRUE when the port is closed.
+ //
+
+ while (!pwp->fClose) {
+
+ //
+ // First wait for something to be written to the buffer.
+ //
+
+ WaitForSingleObject(pwp->hWriteEvent, INFINITE);
+
+ //
+ // Critical section protects write buffer.
+ //
+
+ EnterCriticalSection(&pwp->csWrite);
+
+ //
+ // The buffer is empty when head == tail.
+ //
+
+ while (pwp->pchWriteHead != pwp->pchWriteTail) {
+
+ //
+ // pwp->cbWritePending will be nonzero if
+ // the application thread queued a write to
+ // an empty buffer and then issued the first
+ // WriteFile call.
+ //
+
+ if (pwp->cbWritePending) {
+ if (!pwp->fWriteDone) {
+ LeaveCriticalSection(&pwp->csWrite);
+ goto WaitForWriteCompletion;
+ } else {
+ goto CleanupAfterWriteComplete;
+ }
+ }
+
+ pwp->cbWritePending = CALC_COMM_WRITE_SIZE(pwp);
+
+ //
+ // Leave the critical section before writing. This is
+ // safe because the app thread doesn't change the
+ // head pointer.
+ //
+
+ LeaveCriticalSection(&pwp->csWrite);
+
+ if (!WriteFile(pwp->h32, pwp->pchWriteHead, pwp->cbWritePending,
+ &pwp->cbWritten, &pwp->olWrite)) {
+
+ if (ERROR_IO_PENDING == GetLastError() ) {
+
+WaitForWriteCompletion:
+ //
+ // Wait for the write to complete or for us to
+ // be alerted that the port is closing.
+ //
+
+ while (WAIT_OBJECT_0 == WaitForMultipleObjects(2, ah, FALSE, INFINITE)) {
+
+ //
+ // pwp->hWriteEvent was signaled. This probably
+ // means that the port was closed.
+ //
+
+ if (pwp->fClose) {
+ goto PortClosed;
+ }
+ }
+
+ if (GetOverlappedResult(pwp->h32,
+ &pwp->olWrite,
+ &pwp->cbWritten,
+ TRUE
+ ) )
+ {
+ goto WriteSuccess;
+ }
+ }
+
+
+ LOGDEBUG(0, ("WOWCommWriterThread: WriteFile to id %u fails (error %u)\n",
+ pwp->idComDev, GetLastError()));
+ pwp->cbWritePending = 0;
+ goto WaitForWriteOrder;
+
+ }
+
+
+WriteSuccess:
+
+ //
+ // Update head pointer to reflect portion written.
+ //
+
+ EnterCriticalSection(&pwp->csWrite);
+
+CleanupAfterWriteComplete:
+ WOW32ASSERT(pwp->cbWritten == (WORD)pwp->cbWritten);
+
+ pwp->pchWriteHead += pwp->cbWritten;
+ pwp->cbWriteFree += (WORD)pwp->cbWritten;
+ pwp->cbWritePending = 0;
+
+ //
+ // The following is a sanity check on our buffer manipulations.
+ //
+
+#ifdef DEBUG
+ if (pwp->pchWriteHead >= pwp->pchWriteBuf + pwp->cbWriteBuf) {
+ WOW32ASSERT(pwp->pchWriteHead == pwp->pchWriteBuf + pwp->cbWriteBuf);
+ }
+#endif
+
+ if (pwp->pchWriteHead == pwp->pchWriteBuf + pwp->cbWriteBuf) {
+ pwp->pchWriteHead = pwp->pchWriteBuf;
+ }
+ }
+
+ //
+ // We have exhausted the write buffer, leave the critical section
+ // and loop back to the wait for the buffer to become non-empty.
+ //
+
+ LeaveCriticalSection(&pwp->csWrite);
+ }
+
+PortClosed:
+ CloseHandle(pwp->olWrite.hEvent);
+
+ return 0;
+}
+
+
+
+// Checks status on RLSD, CTS, and DSR for timeout support
+// see MSRWait() in win3.1 comm.drv code
+BOOL MSRWait(PWOWPORT pwp)
+{
+ DWORD dwStartTime, dwElapsedTime, dwLineStatus;
+ DWORD dwErr = 0;
+
+
+ // start the timeout clock (returns msec)
+ dwStartTime = GetTickCount();
+
+ // loop until either all lines are high or a timeout occurs
+ while(!dwErr) {
+
+ // get the current status of the lines
+ GetCommModemStatus(pwp->h32, &dwLineStatus);
+
+ // if all the required lines are up -- we're done
+ if((pwp->lpComDEB16->MSRMask & LOBYTE(dwLineStatus)) == pwp->lpComDEB16->MSRMask)
+ break;
+
+ // get the elapsed time
+ dwElapsedTime = GetTickCount() - dwStartTime;
+
+ if(pwp->RLSDTimeout != IGNORE_TIMEOUT) {
+ // if line is low
+ if(!(dwLineStatus & MS_RLSD_ON)) {
+ if(dwElapsedTime > UINT32(pwp->RLSDTimeout))
+ dwErr |= CE_RLSDTO;
+ }
+ }
+
+ if(pwp->CTSTimeout != IGNORE_TIMEOUT) {
+ // if line is low
+ if(!(dwLineStatus & MS_CTS_ON)) {
+ if(dwElapsedTime > UINT32(pwp->CTSTimeout))
+ dwErr |= CE_CTSTO;
+ }
+ }
+
+ if(pwp->DSRTimeout != IGNORE_TIMEOUT) {
+ // if line is low
+ if(!(dwLineStatus & MS_DSR_ON)) {
+ if(dwElapsedTime > UINT32(pwp->DSRTimeout))
+ dwErr |= CE_DSRTO;
+ }
+ }
+ }
+
+ pwp->dwErrCode |= dwErr;
+ pwp->lpComDEB16->ComErr |= LOWORD(dwErr);
+
+ if(dwErr)
+ return(TRUE);
+ else
+ return(FALSE);
+
+}
diff --git a/private/mvdm/wow32/wucomm.h b/private/mvdm/wow32/wucomm.h
new file mode 100644
index 000000000..36efbc818
--- /dev/null
+++ b/private/mvdm/wow32/wucomm.h
@@ -0,0 +1,315 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUCOMM.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+ * Updated Dec-1992 by Craig Jones (v-cjones)
+--*/
+
+#include "wowcomm.h"
+
+// these limits set as doc'd in Win3.1 Prog. ref. for OpenComm()
+#define NUMCOMS 9 // max avail COM's
+#define NUMLPTS 3 // max available LPT's
+#define NUMPORTS NUMCOMS+NUMLPTS // max # of entries in PortTab[]
+
+// com port indicies into PortTab[]
+#define COM1 0
+#define COM2 1
+#define COM3 2
+#define COM4 3
+#define COM5 4
+#define COM6 5
+#define COM7 6
+#define COM8 7
+#define COM9 8
+#define LPT1 NUMCOMS
+#define LPT2 LPT1+1
+#define LPT3 LPT1+2
+#define AUX COM1
+#define PRN LPT1
+
+// DOS comm IRQ assignments
+#define IRQ3 3
+#define IRQ4 4
+#define IRQ5 5
+#define IRQ7 7
+
+// LPT assignments a la Win3.1
+#define LPTFIRST 0x80 // 0x80 == LPT1
+#define LPTLAST LPTFIRST + NUMLPTS - 1 // 0x82 == LPT3
+
+// other useful deinitions & macros
+#define COMMASK 0x00FF // strip garbage from idComDev
+#define LPTMASK 0x007F // get 0-based LPT #
+#define GETLPTID(id) ((id & LPTMASK) + LPT1) // 0x80 LPT to PortTab[] index
+#define TABIDTOLPT(id) (id + LPTFIRST - NUMCOMS) // PortTab[] index to LPT 0x80
+#define VALIDCOM(id) (((id >= COM1) && (id < NUMCOMS)) ? TRUE : FALSE)
+#define VALIDLPT(id) (((id >= LPTFIRST) && (id <= LPTLAST)) ? TRUE : FALSE)
+
+#define GETPWOWPTR(id) (VALIDCOM(id) ? PortTab[id].pWOWPort : (VALIDLPT(id) ? PortTab[GETLPTID(id)].pWOWPort : NULL))
+
+#define RM_BIOS_DATA 0x00400000 // bios data real mode seg:0
+
+// for Win3.1 compatibility in EscapeCommFunction() API thunk support
+#define RESETDEV 7
+#define GETMAXLPT 8
+#define GETMAXCOM 9
+#define GETBASEIRQ 10
+
+// notifications for EnableCommNotification() support
+#define CN_RECEIVE 0x0001
+#define CN_TRANSMIT 0x0002
+#define CN_EVENT 0x0004
+#define CN_RECEIVEHI 0x0100
+#define CN_TRANSMITHI 0x0200
+#define CN_NOTIFYHI 0x0400
+
+#define WOW_WM_COMMNOTIFY 0x0044
+
+// set all the events that can be masked on NT (a sub-set of Win3.1)
+#define EV_NTEVENTS (EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_TXEMPTY | \
+ EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_RING)
+
+// constants for how Win3.1 expects to see the MSR
+#define MSR_DELTAONLY 0x0000000F // strip off MSR state bits
+#define MSR_STATEONLY 0x000000F0 // strip off MSR delta bits
+#define MSR_DCTS 0x01 // bit for delta CTS
+#define MSR_DDSR 0x02 // bit for delta DSR
+#define MSR_TERI 0x04 // bit for TERI
+#define MSR_DDCD 0x08 // bit for delta DCD
+#define MSR_CTS 0x10 // bit for CTS
+#define MSR_DSR 0x20 // bit for DSR
+#define MSR_RI 0x40 // bit for RI
+#define MSR_DCD 0x80 // bit for DCD
+
+// Win3.1 constants for RLSD, CTS, and DSR timeout support
+#define CE_RLSDTO 0x0080
+#define CE_CTSTO 0x0020
+#define CE_DSRTO 0x0040
+
+// constants for the Event Word
+#define EV_CTSS 0x00000400 // bit for Win3.1 showing CTS state
+#define EV_DSRS 0x00000800 // bit for Win3.1 showing DSR state
+#define EV_RLSDS 0x00001000 // bit for Win3.1 showing RLSD state
+#define EV_RingTe 0x00002000 // bit for Win3.1 showing RingTe state
+
+#define ERR_XMIT 0x4000 // can't xmit a char Win3.1
+#define INFINITE_TIMEOUT 0xFFFF // infinite timeout Win3.1
+#define IGNORE_TIMEOUT 0x0000 // Win3.1 ignore RLSD, CTS, & DSR timeouts
+
+#define COMBUF 2 // max. # of bytes we'll queue for WriteComm()
+
+#define MAXCOMNAME 4 // max length of a comm device name
+#define MAXCOMNAMENULL MAXCOMNAME+1 // length of a comm device name + NULL
+
+// for 16-bit to 32-bit comm support
+typedef struct _WOWPORT {
+ UINT idComDev; // idComDev returned to app as handle of port
+ HANDLE h32; // NT file handle used instead of idComDev
+ HANDLE hREvent; // structure for overlapped reads
+ CRITICAL_SECTION csWrite; // critsect controls following 4 variables.
+ PUCHAR pchWriteHead; // oldest byte not yet written to port.
+ PUCHAR pchWriteTail; // first byte available in buffer.
+ WORD cbWriteFree; // number of bytes available in write buffer.
+ WORD cbWritePending; // number of bytes now in WriteFile()
+ PUCHAR pchWriteBuf; // write buffer
+ WORD cbWriteBuf; // size of the write buffer. One byte unused.
+ HANDLE hWriteThread; // thread handle for COM writer.
+ HANDLE hWriteEvent; // signalled by app thread when empty buffer
+ // made non-empty to wake up writer thread.
+ OVERLAPPED olWrite; // Overlapped structure used for writes.
+ BOOL fWriteDone; // Indicates app thread completed first write.
+ DWORD cbWritten; // Valid when fWriteDone == TRUE.
+ DWORD dwThreadID; // app's thread id for crashed/hung app support
+ DWORD dwErrCode; // most recent error for this idComDev
+ COMSTAT cs; // struct for error handling
+ BOOL fChEvt; // TRUE if app set fChEvt in DCB struct
+ // 16-bit DCB for LPT support only
+ PDCB16 pdcb16; // save DCB for LPT ports
+ // for UngetCommChar() support
+ BOOL fUnGet; // flag specifying an ungot char is pending
+ UCHAR cUnGet; // ungot char in "buffer" only if fUnGet is set
+ // for SetCommEventMask()/EnableCommNotification() support
+ HANDLE hMiThread; // thread handle for Modem interrupt support
+ BOOL fClose; // flag to close auxiliary threads
+ // for SetCommEventMask() support only
+ DWORD dwComDEB16; // DWORD obtained by call to GlobalDosAlloc()
+ PCOMDEB16 lpComDEB16; // flat address to above
+ // for XonLim & XoffLim checking in SetCommState
+ DWORD cbInQ; // Actual size of in Queue set in WU32OpenComm
+ // for RLSD, CTS, DSR timeout support
+ WORD RLSDTimeout; // max time in msec to wait for RLSD (0->ignore)
+ WORD CTSTimeout; // max time in msec to wait for CTS (0->ignore)
+ WORD DSRTimeout; // max time in msec to wait for DSR (0->ignore)
+} WOWPORT, *PWOWPORT;
+
+// Table of above structs, one entry needed for each comm port
+typedef struct _PORTTAB {
+ CHAR szPort[MAXCOMNAMENULL]; // port name
+ PWOWPORT pWOWPort; // pointer to Comm Mapping struct
+} PORTTAB, *PPORTTAB;
+
+//
+// Macro to calculate the size of chunk to write from the write
+// to the filesystem.
+//
+// This is either the entire pending part of the
+// buffer, or, if the buffer wraps, it is the portion
+// between the head and the end of the buffer.
+//
+// In order to keep COMSTAT.cbOutQue moving at a reasonable
+// pace, we restrict ourselves to writing at most 1024 bytes
+// at a time. This is because ProComm for Windows uses the
+// cbOutQue value in displaying its progress, so if we allow
+// larger writes it will only update every 5-10k (assuming
+// ProComm's default 16k write buffer),
+//
+
+#define CALC_COMM_WRITE_SIZE(pwp) \
+ min(1024, \
+ (pwp->pchWriteHead < pwp->pchWriteTail) \
+ ? pwp->pchWriteTail - pwp->pchWriteHead \
+ : (pwp->pchWriteBuf + pwp->cbWriteBuf) - \
+ pwp->pchWriteHead \
+ );
+
+
+// Win3.1 timesout Tx after approx. 65000 msec (65 sec)
+#define WRITE_TIMEOUT 65000
+
+// bitfields of the 16-bit COMSTAT.status
+#define W31CS_fCtsHold 0x01
+#define W31CS_fDsrHold 0x02
+#define W31CS_fRlsdHold 0x04
+#define W31CS_fXoffHold 0x08
+#define W31CS_fSentHold 0x10
+#define W31CS_fEof 0x20
+#define W31CS_fTxim 0x40
+
+// Win3.1 Baud Rate constants
+#define W31CBR_110 0xFF10
+#define W31CBR_300 0xFF11
+#define W31CBR_600 0xFF12
+#define W31CBR_1200 0xFF13
+#define W31CBR_2400 0xFF14
+#define W31CBR_4800 0xFF15
+#define W31CBR_9600 0xFF16
+#define W31CBR_14400 0xFF17
+#define W31CBR_19200 0xFF18
+#define W31CBR_reserved1 0xFF19
+#define W31CBR_reserved2 0xFF1A
+#define W31CBR_38400 0xFF1B
+#define W31CBR_reserved3 0xFF1C
+#define W31CBR_reserved4 0xFF1D
+#define W31CBR_reserved5 0xFF1E
+#define W31CBR_56000 0xFF1F
+
+// these are defined in Win3.1 windows.h but aren't supported in comm.drv
+#define W31CBR_128000 0xFF23
+#define W31CBR_256000 0xFF27
+
+// special way to say 115200
+#define W31CBR_115200 0xFEFF
+
+// constants for conversions from Win3.1 baud specifications to 32-bit baud
+#define W31_DLATCH_110 1047
+#define W31_DLATCH_300 384
+#define W31_DLATCH_600 192
+#define W31_DLATCH_1200 96
+#define W31_DLATCH_2400 48
+#define W31_DLATCH_4800 24
+#define W31_DLATCH_9600 12
+#define W31_DLATCH_14400 8
+#define W31_DLATCH_19200 6
+#define W31_DLATCH_38400 3
+#define W31_DLATCH_56000 2
+#define W31_DLATCH_115200 1
+
+// Win3.1 flags for DCB structure
+#define W31DCB_fBinary 0x0001
+#define W31DCB_fRtsDisable 0x0002
+#define W31DCB_fParity 0x0004
+#define W31DCB_fOutxCtsFlow 0x0008
+#define W31DCB_fOutxDsrFlow 0x0010
+#define W31DCB_fDummy (0x0020 | 0x0040)
+#define W31DCB_fDtrDisable 0x0080
+#define W31DCB_fOutX 0x0100
+#define W31DCB_fInX 0x0200
+#define W31DCB_fPeChar 0x0400
+#define W31DCB_fNull 0x0800
+#define W31DCB_fChEvt 0x1000
+#define W31DCB_fDtrFlow 0x2000
+#define W31DCB_fRtsFlow 0x4000
+#define W31DCB_fDummy2 0x8000
+
+
+
+//+++ DEBUG SUPPORT
+
+#ifdef DEBUG
+
+#define COMMDEBUG(lpszformat) LOGDEBUG(1, lpszformat)
+
+// for watching the modem events
+#define DEBUGWATCHMODEMEVENTS(dwE, dwM, dwS, pcE16, pcM16) { \
+ if(dwS) { \
+ if((dwE != (DWORD)pcE16) || (dwM != (DWORD)pcM16)) { \
+ dwE = (DWORD)pcE16; \
+ dwM = (DWORD)pcM16; \
+ COMMDEBUG(("\nEvt:0x%4X MSR:0x%2X\n", dwE, dwM)); \
+ } \
+ else { \
+ COMMDEBUG((".")); \
+ } \
+ } \
+}
+
+// prototype for real-time debug output
+void CommIODebug(ULONG fhCommIO, HANDLE hCommIO, LPSZ lpsz, ULONG cb, LPSZ lpszFile);
+
+
+#else // endif DEBUG
+
+#define COMMDEBUG(lpszFormat)
+#define DEBUGWATCHMODEMEVENTS(dwE, dwM, dwS, pcE16, pcM16)
+#define CommIODebug(fhCommIO, hCommIO, lpsz, cb, lpszFile)
+
+#endif // endif !DEBUG
+
+//--- DEBUG SUPPORT
+
+
+
+
+// API support function prototypes
+ULONG FASTCALL WU32BuildCommDCB(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ClearCommBreak(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CloseComm(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EnableCommNotification(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EscapeCommFunction(PVDMFRAME pFrame);
+ULONG FASTCALL WU32FlushComm(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetCommError(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetCommEventMask(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetCommState(PVDMFRAME pFrame);
+ULONG FASTCALL WU32OpenComm(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ReadComm(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetCommBreak(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetCommEventMask(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetCommState(PVDMFRAME pFrame);
+ULONG FASTCALL WU32TransmitCommChar(PVDMFRAME pFrame);
+ULONG FASTCALL WU32UngetCommChar(PVDMFRAME pFrame);
+ULONG FASTCALL WU32WriteComm(PVDMFRAME pFrame);
+
+// prototypes for functions exported to the VDM
+BYTE GetCommShadowMSR(WORD idComDev);
+HANDLE GetCommHandle(WORD idComDev);
+
+// prototype for crashed/hung app cleanup support
+VOID FreeCommSupportResources(DWORD dwThreadID);
diff --git a/private/mvdm/wow32/wucursor.c b/private/mvdm/wow32/wucursor.c
new file mode 100644
index 000000000..b440f2aa6
--- /dev/null
+++ b/private/mvdm/wow32/wucursor.c
@@ -0,0 +1,395 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUCURSOR.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+MODNAME(wucursor.c);
+
+/*++
+ void ClipCursor(<lpRect>)
+ LPRECT <lpRect>;
+
+ The %ClipCursor% function confines the cursor to the rectangle on the
+ display screen given by the <lpRect> parameter. If a subsequent cursor
+ position, given with the %SetCursorPos% function or the mouse, lies outside
+ the rectangle, Windows automatically adjusts the position to keep the cursor
+ inside. If <lpRect> is NULL, the cursor is free to move anywhere on the
+ display screen.
+
+ <lpRect>
+ Points to a %RECT% structure that contains the screen coordinates
+ of the upper-left and lower-right corners of the confining rectangle.
+
+ This function does not return a value.
+
+ The cursor is a shared resource. An application that has confined the cursor
+ to a given rectangle must free it before relinquishing control to another
+ application.
+--*/
+
+ULONG FASTCALL WU32ClipCursor(PVDMFRAME pFrame)
+{
+ RECT t1, *p1;
+ register PCLIPCURSOR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CLIPCURSOR16), parg16);
+ p1 = GETRECT16(parg16->f1, &t1);
+
+ ClipCursor(
+ p1
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ HCURSOR CreateCursor(<hInstance>, <nXhotspot>, <nYhotspot>, <nWidth>,
+ <nHeight>, <lpANDbitPlane>, <lpXORbitPlane>)
+ HANDLE <hInstance>;
+ int <nXhotspot>;
+ int <nYhotspot>;
+ int <nWidth>;
+ int <nHeight>;
+ LPSTR <lpANDbitPlane>;
+ LPSTR <lpXORbitPlane>;
+
+ The %CreateCursor% function creates a cursor that has specified width,
+ height, and bit patterns.
+
+ <hInstance>
+ Identifies an instance of the module creating the cursor.
+
+ <nXhotspot>
+ Specifies the horizontal position of the cursor hotspot.
+
+ <nYhotspot>
+ Specifies the vertical position of the cursor hotspot.
+
+ <nWidth>
+ Specifies the width in pixels of the cursor.
+
+ <nHeight>
+ Specifies the height in pixels of the cursor.
+
+ <lpANDbitPlane>
+ Points to an array of bytes containing the bit values for the AND mask
+ of the cursor. This can be the bits of a device-dependent monochrome
+ bitmap.
+
+ <lpXORbitPlane>
+ Points to an array of bytes containing the bit values for the XOR mask
+ of the cursor. This can be the bits of a device-dependent monochrome
+ bitmap.
+
+ The return value identifies the cursor if the function was successful.
+ Otherwise, it is NULL.
+--*/
+
+ULONG FASTCALL WU32CreateCursor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATECURSOR16 parg16;
+ int nWidth;
+ int nHeight;
+ int nPlanes;
+ int nBitsPixel;
+ DWORD nBytesAND;
+ DWORD nBytesXOR;
+ LPBYTE lpBitsAND;
+ LPBYTE lpBitsXOR;
+ int ScanLen16;
+
+ HANDLE h32;
+ HAND16 h16;
+ HAND16 hInst16;
+
+ GETARGPTR(pFrame, sizeof(CREATECURSOR16), parg16);
+ hInst16 = parg16->f1;
+ nWidth = INT32(parg16->f4);
+ nHeight = INT32(parg16->f5);
+
+ nPlanes = 1; /* MONOCHROME BITMAP */
+ nBitsPixel = 1; /* MONOCHROME BITMAP */
+
+ /*
+ ** Convert the AND mask bits
+ */
+ ScanLen16 = (((nWidth*nBitsPixel)+15)/16) * 2 ; // bytes/scan in 16 bit world
+ nBytesAND = ScanLen16*nHeight*nPlanes;
+
+ GETVDMPTR(parg16->f6, nBytesAND, lpBitsAND);
+
+
+ /*
+ ** Convert the XOR mask bits
+ */
+ ScanLen16 = (((nWidth*nBitsPixel)+15)/16) * 2 ; // bytes/scan in 16 bit world
+ nBytesXOR = ScanLen16*nHeight*nPlanes;
+
+ GETVDMPTR(parg16->f7, nBytesXOR, lpBitsXOR);
+
+
+ h32 = (HANDLE)CreateCursor(HMODINST32(hInst16),INT32(parg16->f2),
+ INT32(parg16->f3),
+ nWidth, nHeight, lpBitsAND, lpBitsXOR);
+
+ if (h32) {
+ h16 = (HAND16)W32Create16BitCursorIcon(hInst16,
+ INT32(parg16->f2), INT32(parg16->f3),
+ nWidth, nHeight, nPlanes, nBitsPixel,
+ lpBitsAND, lpBitsXOR,
+ nBytesAND, nBytesXOR);
+
+ ul = SetupCursorIconAlias(hInst16, h32, h16,
+ HANDLE_TYPE_CURSOR, NULL, (WORD)NULL);
+ } else {
+ ul = 0;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL DestroyCursor(<hCursor>)
+ HCURSOR <hCursor>;
+
+ The %DestroyCursor% function destroys a cursor that was previously created
+ by the %CreateCursor% function and frees any memory that the cursor
+ occupied. It should not be used to destroy any cursor that was not created
+ with the %CreateCursor% function.
+
+ <hCursor>
+ Identifies the cursor to be destroyed. The cursor must not be in current
+ use.
+
+ The return value is TRUE if the function was successful. It is FALSE if
+ the function failed.
+--*/
+
+ULONG FASTCALL WU32DestroyCursor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDESTROYCURSOR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DESTROYCURSOR16), parg16);
+
+ if (ul = GETBOOL16(DestroyCursor(HCURSOR32(parg16->f1))))
+ FREEHCURSOR16(parg16->f1);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HCURSOR SetCursor(<hCursor>)
+ HCURSOR <hCursor>;
+
+ The %SetCursor% function sets the cursor shape to the shape specified by the
+ <hCursor> parameter. The cursor is set only if the new shape is different
+ from the current shape. Otherwise, the function returns immediately. The
+ %SetCursor% function is quite fast if the cursor identified by the <hCursor>
+ parameter is the same as the current cursor.
+
+ If <hCursor> is NULL, the cursor is removed from the screen.
+
+ <hCursor>
+ Identifes the cursor resource. The resource must have been loaded
+ previously by using the %LoadCursor% function.
+
+ The return value identifies the cursor resource that defines the previous
+ cursor shape. It is NULL if there is no previous shape.
+
+ The cursor is a shared resource. A window that uses the cursor should set
+ the shape only when the cursor is in its client area or when it is capturing
+ all mouse input. In systems without a mouse, the window should restore the
+ previous cursor shape before the cursor leaves the client area or before the
+ window relinquishes control to another window.
+
+ Any application that needs to change the shape of the cursor while it is in
+ a window must make sure the class cursor for the given window's class is set
+ to NULL. If the class cursor is not NULL, Windows restores the previous
+ shape each time the mouse is moved.
+--*/
+
+ULONG FASTCALL WU32SetCursor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETCURSOR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCURSOR16), parg16);
+
+ ul = GETHCURSOR16(SetCursor(
+ HCURSOR32(parg16->f1)
+ ));
+
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void SetCursorPos(<X>, <Y>)
+ int <X>;
+ int <Y>;
+
+ The %SetCursorPos% function moves the cursor to the screen coordinates given
+ by the <X> and <Y> parameters. If the new coordinates are not within the
+ screen rectangle set by the most recent %ClipCursor% function, Windows
+ automatically adjusts the coordinates so that the cursor stays within the
+ rectangle.
+
+ <X>
+ Specifies the new x-coordinate (in screen coordinates) of the cursor.
+
+ <Y>
+ Specifies the new <y>-coordinate (in screen coordinates) of the
+ cursor.
+
+ This function does not return a value.
+
+ The cursor is a shared resource. A window should move the cursor only when
+ the cursor is in its client area.
+--*/
+
+ULONG FASTCALL WU32SetCursorPos(PVDMFRAME pFrame)
+{
+ register PSETCURSORPOS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCURSORPOS16), parg16);
+
+ SetCursorPos(
+ INT32(parg16->f1),
+ INT32(parg16->f2)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ int ShowCursor(<fShow>)
+ BOOL <fShow>;
+
+ The %ShowCursor% function shows or hides the cursor. When the %ShowCursor%
+ function is called, an internal display counter is incremented by one if the
+ <fShow> parameter is TRUE, or decremented by one if the <fShow> parameter is
+ FALSE. If the internal display counter is greater then or equal to zero, the
+ cursor is displayed. If the counter is less then zero, the cursor is
+ hidden. Calls to the %ShowCursor% function are accumulative: for each call
+ to hide the cursor, a corresponding call must be made to show the cursor.
+
+ <fShow>
+ Specifies whether the display count is to be increased or decreased. The
+ display count is increased if fShow is TRUE. Otherwise, it is
+ decreased.
+
+ The return value specifies the new display count.
+
+ When Windows is first started, the display count is zero if a mouse is
+ installed or -1 if no mouse is installed.
+
+ The cursor is a shared resource. A window that hides the cursor should show
+ the cursor before the cursor leaves its client area, or before the window
+ relinquishes control to another window.
+--*/
+
+ULONG FASTCALL WU32ShowCursor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSHOWCURSOR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SHOWCURSOR16), parg16);
+
+ ul = GETINT16(ShowCursor(
+ BOOL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// This handles both LoadIcon and LoadCursor
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32LoadCursor(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ PSZ psz2;
+ LPBYTE pResData = NULL;
+ WCHAR pszModName[MAX_PATH];
+ register PLOADCURSOR16 parg16;
+ BOOL fIsCursor;
+ HAND16 hInst16;
+ HAND16 hRes16;
+
+ LPWSTR lpUniName_CursorIcon;
+
+ GETARGPTR(pFrame, sizeof(LOADCURSOR16), parg16);
+ GETPSZIDPTR(parg16->f2, psz2);
+ GETMISCPTR (parg16->f3, pResData);
+
+ fIsCursor = ((WORD)parg16->f7 == (WORD)RT_CURSOR);
+ hInst16 = FETCHWORD(parg16->f1);
+ hRes16 = parg16->f5;
+ wsprintfW(pszModName, L"\001%8lx", HINSTRES32(hInst16));
+
+ if (HIWORD(psz2) != (WORD) NULL) {
+ if (!(MBToWCS(psz2, -1, &lpUniName_CursorIcon, -1, TRUE))) {
+ FREEMISCPTR(pResData);
+ FREEPSZIDPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+ }
+ }
+ else {
+ lpUniName_CursorIcon = (LPWSTR)psz2;
+ }
+
+ ul = (ULONG) (pfnOut.pfnServerLoadCreateCursorIcon)(HINSTRES32(hInst16),
+ (LPTSTR) pszModName,
+ parg16->f6,
+ (LPCTSTR) lpUniName_CursorIcon,
+ parg16->f4,
+ pResData,
+ (LPTSTR) parg16->f7,
+ 0);
+
+ if (ul)
+ ul = SetupResCursorIconAlias(hInst16, (HAND32)ul,
+ psz2, hRes16,
+ fIsCursor ? HANDLE_TYPE_CURSOR : HANDLE_TYPE_ICON);
+
+
+
+ if (HIWORD(psz2) != (WORD) NULL) {
+ LocalFree (lpUniName_CursorIcon);
+ }
+
+ FREEMISCPTR(pResData);
+ FREEPSZIDPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wucursor.h b/private/mvdm/wow32/wucursor.h
new file mode 100644
index 000000000..9571e01f4
--- /dev/null
+++ b/private/mvdm/wow32/wucursor.h
@@ -0,0 +1,22 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUCURSOR.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WU32ClipCursor(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CreateCursor(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DestroyCursor(PVDMFRAME pFrame);
+ULONG FASTCALL WU32LoadCursor(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetCursor(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetCursorPos(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ShowCursor(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wudlg.c b/private/mvdm/wow32/wudlg.c
new file mode 100644
index 000000000..ac725f5eb
--- /dev/null
+++ b/private/mvdm/wow32/wudlg.c
@@ -0,0 +1,1489 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUDLG.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wudlg.c);
+
+extern DOSWOWDATA DosWowData;
+
+// SendDlgItemMessage cache
+extern HWND hdlgSDIMCached ;
+
+LONG W32DialogFunc(HWND hdlg, UINT uMsg, DWORD uParam, LPARAM lParam)
+{
+ BOOL fSuccess;
+ register PWW pww;
+ WM32MSGPARAMEX wm32mpex;
+ BOOL fMessageNeedsThunking;
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+ extern INT fWMsgProfRT;
+ DWORD dwTics;
+#endif // WOWPROFILE
+
+ // If the app has GP Faulted we don't want to pass it any more input
+ // This should be removed when USER32 does clean up on task death so
+ // it doesn't call us - mattfe june 24 92
+
+ if (CURRENTPTD()->dwFlags & TDF_IGNOREINPUT) {
+ LOGDEBUG(6,(" W32DialogFunc Ignoring Input Messsage %04X\n",uMsg));
+ WOW32ASSERTMSG(!gfIgnoreInputAssertGiven,
+ "WCD32CommonDialogProc: TDF_IGNOREINPUT hack was used, shouldn't be, "
+ "please email DaveHart with repro instructions. Hit 'g' to ignore this "
+ "and suppress this assertion from now on.\n");
+ gfIgnoreInputAssertGiven = TRUE;
+ goto SilentError;
+ }
+
+ if (!(pww = (PWW) GetWindowLong(hdlg, GWL_WOWWORDS))) {
+ LOGDEBUG(LOG_ALWAYS,(" W32DialogFunc ERROR: cannot find alias for window %08lx\n", hdlg));
+ goto Error;
+ }
+
+ // If pww->vpfnDlgProc is NULL, then something is broken; we
+ // certainly can't continue because we don't know what 16-bit func to call
+
+ if (!pww->vpfnDlgProc) {
+ LOGDEBUG(LOG_ALWAYS,(" W32DialogFunc ERROR: no window proc for message %04x Dlg = %08lx\n", uMsg, hdlg ));
+ goto Error;
+ }
+
+ wm32mpex.Parm16.WndProc.hwnd = GETHWND16(hdlg);
+ wm32mpex.Parm16.WndProc.wMsg = (WORD)uMsg;
+ wm32mpex.Parm16.WndProc.wParam = (WORD)uParam;
+ wm32mpex.Parm16.WndProc.lParam = (LONG)lParam;
+ wm32mpex.Parm16.WndProc.hInst = 0; // Forces AX = SS on WndProc entry,
+ // for Win 3.1 compatibility.
+
+ fMessageNeedsThunking = (uMsg < 0x400) &&
+ (aw32Msg[uMsg].lpfnM32 != WM32NoThunking);
+ if (fMessageNeedsThunking) {
+ LOGDEBUG(3,("%04X (%s)\n", CURRENTPTD()->htask16, (aw32Msg[uMsg].lpszW32)));
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+ dwTics = GetWOWTicDiff(0L);
+#endif // WOWPROFILE
+
+ wm32mpex.fThunk = THUNKMSG;
+ wm32mpex.hwnd = hdlg;
+ wm32mpex.uMsg = uMsg;
+ wm32mpex.uParam = uParam;
+ wm32mpex.lParam = lParam;
+ wm32mpex.pww = pww;
+ wm32mpex.lpfnM32 = aw32Msg[uMsg].lpfnM32;
+ if (!(wm32mpex.lpfnM32)(&wm32mpex)) {
+ LOGDEBUG(LOG_ERROR,(" W32DialogFunc ERROR: cannot thunk 32-bit message %04x\n", uMsg));
+ goto Error;
+ }
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+ if( !fWMsgProfRT ) { // only if not round trip profiling
+ aw32Msg[uMsg].cTics += GetWOWTicDiff(dwTics);
+ }
+#endif // WOWPROFILE
+
+ }
+ else {
+ LOGDEBUG(6,(" No Thunking was required for the 32-bit message %s(%04x)\n", (LPSZ)GetWMMsgName(uMsg), uMsg));
+ }
+
+ BlockWOWIdle(FALSE);
+
+ fSuccess = CallBack16(RET_WNDPROC, &wm32mpex.Parm16, pww->vpfnDlgProc, (PVPVOID)&wm32mpex.lReturn);
+
+ BlockWOWIdle(TRUE);
+
+ // the callback function of a dialog is of type FARPROC whose return value
+ // is of type 'int'. Since dx:ax is copied into lReturn in the above
+ // CallBack16 call, we need to zero out the hiword, otherwise we will be
+ // returning an erroneous value.
+
+ wm32mpex.lReturn = (LONG)((SHORT)(LOWORD(wm32mpex.lReturn)));
+
+ if (fMessageNeedsThunking) {
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+ if( !fWMsgProfRT ) { // only if not round trip profiling
+ dwTics = GetWOWTicDiff(0L);
+ }
+#endif // WOWPROFILE
+
+
+ //
+ // if you send a message to a dialog what gets returned
+ // to the caller is the dlg's msgresult window long.
+ // app dialog functions will call
+ // SetWindowLong(hdlg, DWL_MSGRESULT, n);
+ // during message processing so the right thing gets returned.
+ // scottlu says we only need to do this for wm_gettext, it's
+ // the only message whose result is an output count.
+ //
+
+ if (uMsg == WM_GETTEXT && wm32mpex.lReturn != 0) {
+ wm32mpex.lReturn = GetWindowLong(hdlg, DWL_MSGRESULT);
+ }
+
+ wm32mpex.fThunk = UNTHUNKMSG;
+ (wm32mpex.lpfnM32)(&wm32mpex);
+
+#ifdef WOWPROFILE // for MSG profiling only (debugger extension)
+ aw32Msg[uMsg].cTics += GetWOWTicDiff(dwTics);
+ aw32Msg[uMsg].cCalls++; // increment # times message passed
+#endif // WOWPROFILE
+
+ }
+
+ if (!fSuccess)
+ goto Error;
+
+Done:
+
+ return wm32mpex.lReturn;
+
+Error:
+ LOGDEBUG(6,(" W32DialogFunc WARNING: cannot call back, using default message handling\n"));
+SilentError:
+ wm32mpex.lReturn = 0;
+ goto Done;
+}
+
+
+
+
+/*++
+ void CheckDlgButton(<hDlg>, <nIDButton>, <wCheck>)
+ HWND <hDlg>;
+ int <nIDButton>;
+ WORD <wCheck>;
+
+ The %CheckDlgButton% function places a checkmark next to or removes a
+ checkmark from a button control, or changes the state of a three-state
+ button. The %CheckDlgButton% function sends a BM_SETCHECK message to the
+ button control that has the specified ID in the given dialog box.
+
+ <hDlg>
+ Identifies the dialog box that contains the button.
+
+ <nIDButton>
+ Specifies the button control to be modified.
+
+ <wCheck>
+ Specifies the action to take. If the <wCheck> parameter is
+ nonzero, the %CheckDlgButton% function places a checkmark next to the
+ button; if zero, the checkmark is removed. For three-state buttons, if
+ <wCheck> is 2, the button is grayed; if <wCheck> is 1, it is checked; if
+ <wCheck> is 0, the checkmark is removed.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32CheckDlgButton(PVDMFRAME pFrame)
+{
+ register PCHECKDLGBUTTON16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CHECKDLGBUTTON16), parg16);
+
+ CheckDlgButton(
+ HWND32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ void CheckRadioButton(<hDlg>, <nIDFirstButton>, <nIDLastButton>,
+ <nIDCheckButton>)
+ HWND <hDlg>;
+ int <nIDFirstButton>;
+ int <nIDLastButton>;
+ int <nIDCheckButton>;
+
+ The %CheckRadioButton% function checks the radio button specified by the
+ <nIDCheckButton> parameter and removes the checkmark from all other radio
+ buttons in the group of buttons specified by the <nIDFirstButton> and
+ <nIDLastButton> parameters. The %CheckRadioButton% function sends a
+ BM_SETCHECK message to the radio-button control that has the specified ID in
+ the given dialog box.
+
+ <hDlg>
+ Identifies the dialog box.
+
+ <nIDFirstButton>
+ Specifies the integer identifier of the first radio button in the
+ group.
+
+ <nIDLastButton>
+ Specifies the integer identifier of the last radio button in the
+ group.
+
+ <nIDCheckButton>
+ Specifies the integer identifier of the radio button to be
+ checked.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32CheckRadioButton(PVDMFRAME pFrame)
+{
+ register PCHECKRADIOBUTTON16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CHECKRADIOBUTTON16), parg16);
+
+ CheckRadioButton(
+ HWND32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ WORD32(parg16->f4)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+//***************************************************************************
+// HWND WINAPI CreateDialog(HINSTANCE, LPCSTR, HWND, DLGPROC);
+// HWND WINAPI CreateDialogIndirect(HINSTANCE, const void FAR*, HWND, DLGPROC);
+// HWND WINAPI CreateDialogParam(HINSTANCE, LPCSTR, HWND, DLGPROC, LPARAM);
+// HWND WINAPI CreateDialogIndirectParam(HINSTANCE, const void FAR*, HWND, DLGPROC, LPARAM);
+//
+// int WINAPI DialogBox(HINSTANCE, LPCSTR, HWND, DLGPROC);
+// int WINAPI DialogBoxIndirect(HINSTANCE, HGLOBAL, HWND, DLGPROC);
+// int WINAPI DialogBoxParam(HINSTANCE, LPCSTR, HWND, DLGPROC, LPARAM);
+// int WINAPI DialogBoxIndirectParam(HINSTANCE, HGLOBAL, HWND, DLGPROC, LPARAM);
+//
+// This is a common entry point for all the apis above. We distinguish
+// between 'create' and 'dialogbox' apis by a bool flag (parg16->f7).
+// TRUE implies 'dialogbox' apis else 'create' apis.
+//
+// - nanduri
+//***************************************************************************
+
+ULONG FASTCALL WU32DialogBoxParam(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ DLGDATA DlgData;
+ PVOID pDlg;
+ DWORD cb, cb16;
+ register PDIALOGBOXPARAM16 parg16;
+ BYTE abT[1024];
+
+ GETARGPTR(pFrame, sizeof(DIALOGBOXPARAM16), parg16);
+
+ DlgData.vpfnDlgProc = DWORD32(parg16->f4);
+ DlgData.dwUserInitParam = DWORD32(parg16->f5);
+
+ if (!(cb16 = parg16->f6)) {
+ cb = ConvertDialog16(NULL, DWORD32(parg16->f2), 0, cb16);
+ }
+ else {
+ // The idea is eliminate a call to ConverDialog16
+ //
+ // the maximum size that 32bit dlgtemplate would be is twice
+ // the 16bit dlgtemplate.
+ //
+ // this assumption is true cause - we convert most words to dwords
+ // and ansi strings to unicode strings - since we know that a
+ // DWORD is twice the sizeof a WORD a unicode character is 2bytes
+ // therefore maxsize of dlgtemplate cannot exceed cb * 2.
+ //
+ // - nanduri
+
+ cb = cb16 * max(sizeof(DWORD) / sizeof(WORD), sizeof(WCHAR)/sizeof(BYTE));
+ WOW32ASSERT(cb >= ConvertDialog16(NULL, DWORD32(parg16->f2), 0, cb16));
+ }
+
+ pDlg = (cb > sizeof(abT)) ? malloc_w(cb) : (PVOID)abT;
+ if (cb && pDlg) {
+ cb = ConvertDialog16(pDlg, DWORD32(parg16->f2), cb, cb16);
+
+ if (parg16->f7) {
+ ul = GETINT16(DialogBoxIndirectParamAorW(HMODINST32(parg16->f1),
+ pDlg, HWND32(parg16->f3),
+ (DLGPROC)(DlgData.vpfnDlgProc ? W32DialogFunc: 0),
+ (LPARAM) &DlgData, SCDLG_ANSI));
+ }
+ else {
+ ul = GETHWND16((pfnOut.pfnServerCreateDialog)(HMODINST32(parg16->f1), (LPDLGTEMPLATE)pDlg,
+ cb, HWND32(parg16->f3),
+ (DLGPROC)(DlgData.vpfnDlgProc ? W32DialogFunc: 0),
+ (LPARAM) &DlgData, SCDLG_CLIENT | SCDLG_ANSI | SCDLG_NOREVALIDATE));
+ }
+
+ if (pDlg != (PVOID)abT) {
+ free_w (pDlg);
+ }
+
+ }
+
+ // Invalidate SendDlgItemMessage cache
+ hdlgSDIMCached = NULL ;
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int DlgDirList(<hDlg>, <lpPathSpec>, <nIDListBox>, <nIDStaticPath>,
+ <wFiletype>)
+ HWND <hDlg>;
+ LPSTR <lpPathSpec>;
+ int <nIDListBox>;
+ int <nIDStaticPath>;
+ WORD <wFiletype>;
+
+ The %DlgDirList% function fills a list-box control with a file or directory
+ listing. It fills the list box specified by the <nIDListBox> parameter with
+ the names of all files matching the pathname given by the <lpPathSpec>
+ parameter.
+
+ The %DlgDirList% function shows subdirectories enclosed in square brackets
+ ([ ]), and shows drives in the form [-<x>-], where <x> is the drive letter.
+
+ The <lpPathSpec> parameter has the following form:
+
+ [drive:] [ [\u]directory[\idirectory]...\u] [filename]
+
+ In this example, <drive> is a drive letter, <directory> is a valid directory
+ name, and <filename> is a valid filename that must contain at least one
+ wildcard character. The wildcard characters are a question mark (?), meaning
+ match any character, and an asterisk (*), meaning match any number of
+ characters.
+
+ If the <lpPathSpec> parameter includes a drive and/or directory name, the
+ current drive and directory are changed to the designated drive and
+ directory before the list box is filled. The text control identified by the
+ <nIDStaticPath> parameter is also updated with the new drive and/or
+ directory name.
+
+ After the list box is filled, <lpPathSpec> is updated by removing the drive
+ and/or directory portion of the pathname.
+
+ %DlgDirList% sends LB_RESETCONTENT and LB_DIR messages to the list box.
+
+ <hDlg>
+ Identifies the dialog box that contains the list box.
+
+ <lpPathSpec>
+ Points to a pathname string. The string must be a
+ null-terminated character string.
+
+ <nIDListBox>
+ Specifies the identifier of a list-box control. If <nIDListBox> is
+ zero, %DlgDirList% assumes that no list box exists and does not attempt
+ to fill it.
+
+ <nIDStaticPath>
+ Specifies the identifier of the static-text control used for
+ displaying the current drive and directory. If <nIDStaticPath> is zero,
+ %DlgDirList% assumes that no such text control is present.
+
+ <wFiletype>
+ Specifies the attributes of the files to be displayed. It can be any
+ combination of the following values:
+
+ 0x0000
+ Read/write data files with no additional attributes
+
+ 0x0001
+ Read-only files
+
+ 0x0002
+ Hidden files
+
+ 0x0004
+ System files
+
+ 0x0010
+ Subdirectories
+
+ 0x0020
+ Archives
+
+ 0x2000
+ LB_DIR flag. If the LB_DIR flag is set, Windows places the messages
+ generated by %DlgDirList% in the application's queue; otherwise they are
+ sent directly to the dialog function.
+
+ 0x4000
+ Drives
+
+ 0x8000
+ Exclusive bit. If the exclusive bit is set, only files of the specified
+ type are listed. Otherwise, files of the specified type are listed in
+ addition to normal files.
+
+ The return value specifies the outcome of the function. It is nonzero if a
+ listing was made, even an empty listing. A zero return value implies that
+ the input string did not contain a valid search path.
+
+ The <wFiletype> parameter specifies the DOS attributes of the files to be
+ listed. Table 4.6 describes these attributes.
+--*/
+
+ULONG FASTCALL WU32DlgDirList(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PDLGDIRLIST16 parg16;
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+ GETARGPTR(pFrame, sizeof(DLGDIRLIST16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+
+ //
+ // KidPix passes an invalid filetype flag (0x1000) that Win3.1 doesn't
+ // check for. Win32 does, and fails the API, so mask that flag off here.
+ // John Vert (jvert) 11-Jun-1993
+ //
+
+ ul = GETINT16(DlgDirList(
+ HWND32(parg16->f1),
+ psz2,
+ WORD32(parg16->f3),
+ WORD32(parg16->f4),
+ WORD32(parg16->f5) & DDL_VALID
+ ));
+
+ UpdateDosCurrentDirectory(DIR_NT_TO_DOS);
+
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int DlgDirListComboBox(<hDlg>, <lpPathSpec>, <nIDComboBox>, <nIDStaticPath>,
+ <wFiletype>)
+ HWND <hDlg>;
+ LPSTR <lpPathSpec>;
+ int <nIDComboBox>;
+ int <nIDStaticPath>;
+ WORD <wFiletype>;
+
+ The %DlgDirListComboBox% function fills the list box of a combo-box control
+ with a file or directory listing. It fills the list box of the combo box
+ specified by the <nIDComboBox> parameter with the names of all files
+ matching the pathname given by the <lpPathSpec> parameter.
+
+ The %DlgDirListComboBox% function shows subdirectories enclosed in square
+ brackets ([ ]), and shows drives in the form [-<x>-], where <x> is the drive
+ letter.
+
+ The <lpPathSpec> parameter has the following form:
+
+ [drive:] [ [\u]directory[\idirectory]...\u] [filename]
+
+ In this example, <drive> is a drive letter, <directory> is a valid directory
+ name, and <filename> is a valid filename that must contain at least one
+ wildcard character. The wildcard characters are a question mark (?), meaning
+ match any character, and an asterisk (*), meaning match any number of
+ characters.
+
+ If the <lpPathSpec> parameter includes a drive and/or directory name, the
+ current drive and directory are changed to the designated drive and
+ directory before the list box is filled. The text control identified by the
+ <nIDStaticPath> parameter is also updated with the new drive and/or
+ directory name.
+
+ After the combo-box list box is filled, <lpPathSpec> is updated by removing
+ the drive and/or directory portion of the pathname.
+
+ %DlgDirListComboBox% sends CB_RESETCONTENT and CB_DIR messages to the combo
+ box.
+
+ <hDlg>
+ Identifies the dialog box that contains the combo box.
+
+ <lpPathSpec>
+ Points to a pathname string. The string must be a
+ null-terminated string.
+
+ <nIDComboBox>
+ Specifies the identifier of a combo-box control in a dialog box.
+ If <nIDComboBox> is zero, %DlgDirListComboBox% assumes that no combo box
+ exists and does not attempt to fill it.
+
+ <nIDStaticPath>
+ Specifies the identifier of the static-text control used for
+ displaying the current drive and directory. If <nIDStaticPath> is zero,
+ %DlgDirListComboBox% assumes that no such text control is present.
+
+ <wFiletype>
+ Specifies DOS file attributes of the files to be displayed. It
+ can be any combination of the following values:
+
+ The return value specifies the outcome of the function. It is nonzero if a
+ listing was made, even an empty listing. A zero return value implies that
+ the input string did not contain a valid search path.
+--*/
+
+ULONG FASTCALL WU32DlgDirListComboBox(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PDLGDIRLISTCOMBOBOX16 parg16;
+
+ UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
+
+ GETARGPTR(pFrame, sizeof(DLGDIRLISTCOMBOBOX16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+
+ ul = GETINT16(DlgDirListComboBox(
+ HWND32(parg16->f1),
+ psz2,
+ WORD32(parg16->f3),
+ WORD32(parg16->f4),
+ WORD32(parg16->f5)
+ ));
+
+ UpdateDosCurrentDirectory(DIR_NT_TO_DOS);
+
+
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL DlgDirSelectEx(<hDlg>, <lpString>, <nIDListBox>)
+ HWND <hDlg>;
+ LPSTR <lpString>;
+ int <nIDListBox>;
+
+ The %DlgDirSelectEx% function retrieves the current selection from a list
+ box. It assumes that the list box has been filled by the %DlgDirList%
+ function and that the selection is a drive letter, a file, or a directory
+ name.
+
+ The %DlgDirSelectEx% function copies the selection to the buffer given by the
+ <lpString> parameter. If the current selection is a directory name or drive
+ letter, %DlgDirSelectEx% removes the enclosing square brackets (and hyphens,
+ for drive letters) so that the name or letter is ready to be inserted into a
+ new pathname. If there is no selection, <lpString> does not change.
+
+ %DlgDirSelectEx% sends LB_GETCURSEL and LB_GETTEXT messages to the list box.
+
+ <hDlg>
+ Identifies the dialog box that contains the list box.
+
+ <lpString>
+ Points to a buffer that is to receive the selected pathname.
+
+ <nIDListBox>
+ Specifies the integer ID of a list-box control in the dialog box.
+
+ The return value specifies the status of the current list-box selection. It
+ is TRUE if the current selection is a directory name. Otherwise, it is
+ FALSE.
+
+ The %DlgDirSelectEx% function does not allow more than one filename to be
+ returned from a list box.
+
+ The list box must not be a multiple-selection list box. If it is, this
+ function will not return a zero value and <lpString> will remain unchanged.
+--*/
+
+ULONG FASTCALL WU32DlgDirSelect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PDLGDIRSELECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DLGDIRSELECT16), parg16);
+ ALLOCVDMPTR(parg16->f2, MAX_VDMFILENAME, psz2);
+
+ ul = GETBOOL16(DlgDirSelectEx(
+ HWND32(parg16->f1),
+ psz2,
+ SIZE_BOGUS,
+ WORD32(parg16->f3)
+ ));
+
+ FLUSHVDMPTR(parg16->f2, strlen(psz2)+1, psz2);
+ FREEVDMPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL DlgDirSelectComboBoxEx(<hDlg>, <lpString>, <nIDComboBox>)
+ HWND <hDlg>;
+ LPSTR <lpString>;
+ int <nIDComboBox>;
+
+ The %DlgDirSelectComboBoxEx% function retrieves the current selection from the
+ list box of a combo box created with the CBS_SIMPLE style. It cannot be used
+ with combo boxes created with either the CBS_DROPDOWN or CBS_DROPDOWNLIST
+ style. It assumes that the list box has been filled by the
+ %DlgDirListComboBox% function and that the selection is a drive letter, a
+ file, or a directory name.
+
+ The %DlgDirSelectComboBoxEx% function copies the selection to the buffer given
+ by the <lpString> parameter. If the current selection is a directory name or
+ drive letter, %DlgDirSelectComboBoxEx% removes the enclosing square brackets
+ (and hyphens, for drive letters) so that the name or letter is ready to be
+ inserted into a new pathname. If there is no selection, <lpString> does not
+ change.
+
+ %DlgDirSelectComboBoxEx% sends CB_GETCURSEL and CB_GETLBTEXT messages to the
+ combo box.
+
+ <hDlg>
+ Identifies the dialog box that contains the combo box.
+
+ <lpString>
+ Points to a buffer that is to receive the selected pathname.
+
+ <nIDComboBox>
+ Specifies the integer ID of the combo-box control in the dialog
+ box.
+
+ The return value specifies the status of the current combo-box selection. It
+ is TRUE if the current selection is a directory name. Otherwise, it is
+ FALSE.
+
+ The %DlgDirSelectComboBoxEx% function does not allow more than one filename to
+ be returned from a combo box.
+--*/
+
+ULONG FASTCALL WU32DlgDirSelectComboBox(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PDLGDIRSELECTCOMBOBOX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DLGDIRSELECTCOMBOBOX16), parg16);
+ ALLOCVDMPTR(parg16->f2, MAX_VDMFILENAME, psz2);
+
+ ul = GETBOOL16(DlgDirSelectComboBoxEx(
+ HWND32(parg16->f1),
+ psz2,
+ SIZE_BOGUS,
+ WORD32(parg16->f3)
+ ));
+
+ FLUSHVDMPTR(parg16->f2, strlen(psz2)+1, psz2);
+ FREEVDMPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void EndDialog(<hDlg>, <nResult>)
+ HWND <hDlg>;
+ int <nResult>;
+
+ The %EndDialog% function terminates a modal dialog box and returns the given
+ result to the %DialogBox% function that created the dialog box. The
+ %EndDialog% function is required to complete processing whenever the
+ %DialogBox% function is used to create a modal dialog box. The function must
+ be used in the dialog function of the modal dialog box and should not be
+ used for any other purpose.
+
+ The dialog function can call %EndDialog% at any time, even during the
+ processing of the WM_INITDIALOG message. If called during the WM_INITDIALOG
+ message, the dialog box is terminated before it is shown or before the input
+ focus is set.
+
+ %EndDialog% does not terminate the dialog box immediately. Instead, it sets
+ a flag that directs the dialog box to terminate as soon as the dialog
+ function ends. The %EndDialog% function returns to the dialog function, so
+ the dialog function must return control to Windows.
+
+ <hDlg>
+ Identifies the dialog box to be destroyed.
+
+ <nResult>
+ Specifies the value to be returned from the dialog box to the
+ %DialogBox% function that created it.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32EndDialog(PVDMFRAME pFrame)
+{
+ register PENDDIALOG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENDDIALOG16), parg16);
+
+ EndDialog(
+ HWND32(parg16->f1),
+ INT32(parg16->f2)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ LONG GetDialogBaseUnits(VOID)
+
+ The %GetDialogBaseUnits% function returns the dialog base units used by
+ Windows when creating dialog boxes. An application should use these values
+ to calculate the average width of characters in the system font.
+
+ This function has no parameters.
+
+ The return value specifies the dialog base units. The high-order word
+ contains the height in pixels of the current dialog base height unit derived
+ from the height of the system font, and the low-order word contains the
+ width in pixels of the current dialog base width unit derived from the width
+ of the system font.
+
+ The values returned represent dialog base units before being scaled to
+ actual dialog units. The actual dialog unit in the <x> direction is
+ 1/4th of the width returned by %GetDialogBaseUnits%. The actual dialog
+ unit in the <y> direction is 1/8th of the height returned by the
+ function.
+
+ To determine the actual height and width in pixels of a control, given the
+ height (x) and width (y) in dialog units and the return value
+ (lDlgBaseUnits) from calling %GetDialogBaseUnits%, use the following
+ formula:
+
+ (x * LOWORD(lDlgBaseUnits))/4
+ (y * HIWORD(lDlgBaseUnits))/8
+
+ To avoid rounding problems, perform the multiplication before the division
+ in case the dialog base units are not evenly divisible by four.
+--*/
+
+ULONG FASTCALL WU32GetDialogBaseUnits(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETLONG16(GetDialogBaseUnits());
+
+ RETURN(ul);
+}
+
+
+/*++
+ int GetDlgCtrlID(<hwnd>)
+ HWND <hwnd>;
+
+ The %GetDlgCtrlID% function returns the ID value of the child window
+ identified by the <hwnd> parameter.
+
+ <hwnd>
+ Identifies the child window.
+
+ The return value is the numeric identifier of the child window if the
+ function is successful. If the function fails, or if <hwnd> is not a valid
+ window handle, the return value is NULL.
+
+ Since top-level windows do not have an ID value, the return value of this
+ function is invalid if the <hwnd> parameter identifies a top-level window.
+--*/
+
+ULONG FASTCALL WU32GetDlgCtrlID(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETDLGCTRLID16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETDLGCTRLID16), parg16);
+
+ ul = GETINT16(GetDlgCtrlID(
+ HWND32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ WORD GetDlgItemInt(<hDlg>, <nIDDlgItem>, <lpTranslated>, <bSigned>)
+ HWND <hDlg>;
+ int <nIDDlgItem>;
+ BOOL FAR *<lpTranslated>;
+ BOOL <bSigned>;
+
+ The %GetDlgItemInt% function translates the text of a control in the given
+ dialog box into an integer value. The %GetDlgItemInt% function retrieves the
+ text of the control identified by the <nIDDlgItem> parameter. It translates
+ the text by stripping any extra spaces at the beginning of the text and
+ converting decimal digits, stopping the translation when it reaches the end
+ of the text or encounters any nonnumeric character. If the <bSigned>
+ parameter is TRUE, %GetDlgItemInt% checks for a minus sign (-) at the
+ beginning of the text and translates the text into a signed number.
+ Otherwise, it creates an unsigned value.
+
+ %GetDlgItemInt% returns zero if the translated number is greater than 32,767
+ (for signed numbers) or 65,535 (for unsigned). When errors occur, such as
+ encountering nonnumeric characters and exceeding the given maximum,
+ %GetDlgItemInt% copies zero to the location pointed to by the <lpTranslated>
+ parameter. If there are no errors, <lpTranslated> receives a nonzero value.
+ If <lpTranslated> is NULL, %GetDlgItemInt% does not warn about errors.
+ %GetDlgItemInt% sends a WM_GETTEXT message to the control.
+
+ <hDlg>
+ Identifies the dialog box.
+
+ <nIDDlgItem>
+ Specifies the integer identifier of the dialog-box item to be
+ translated.
+
+ <lpTranslated>
+ Points to the Boolean variable that is to receive the
+ translated flag.
+
+ <bSigned>
+ Specifies whether the value to be retrieved is signed.
+
+ The return value specifies the translated value of the dialog-box item text.
+ Since zero is a valid return value, the <lpTranslated> parameter must be
+ used to detect errors. If a signed return value is desired, it should be
+ cast as an %int% type.
+--*/
+
+ULONG FASTCALL WU32GetDlgItemInt(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ BOOL t3;
+ register PGETDLGITEMINT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETDLGITEMINT16), parg16);
+
+ ul = GETWORD16(GetDlgItemInt(
+ HWND32(parg16->f1),
+ WORD32(parg16->f2), // see comment in wu32getdlgitem
+ &t3,
+ BOOL32(parg16->f4)
+ ));
+
+ PUTBOOL16(parg16->f3, t3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int GetDlgItemText(<hDlg>, <nIDDlgItem>, <lpString>, <nMaxCount>)
+ HWND <hDlg>;
+ int <nIDDlgItem>;
+ LPSTR <lpString>;
+ int <nMaxCount>;
+
+ The %GetDlgItemText% function retrieves the caption or text associated with
+ a control in a dialog box. The %GetDlgItemText% function copies the text to
+ the location pointed to by the <lpString> parameter and returns a count of
+ the number of characters it copies.
+
+ %GetDlgItemText% sends a WM_GETTEXT message to the control.
+
+ <hDlg>
+ Identifies the dialog box that contains the control.
+
+ <nIDDlgItem>
+ Specifies the integer identifier of the dialog-box item whose
+ caption or text is to be retrieved.
+
+ <lpString>
+ Points to the buffer to receive the text.
+
+ <nMaxCount>
+ Specifies the maximum length (in bytes) of the string to be copied
+ to <lpString>. If the string is longer than <nMaxCount>, it is
+ truncated.
+
+ The return value specifies the actual number of characters copied to the
+ buffer. It is zero if no text is copied.
+--*/
+
+ULONG FASTCALL WU32GetDlgItemText(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz3;
+ register PGETDLGITEMTEXT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETDLGITEMTEXT16), parg16);
+ ALLOCVDMPTR(parg16->f3, parg16->f4, psz3);
+
+ ul = GETINT16(GetDlgItemText(
+ HWND32(parg16->f1),
+ WORD32(parg16->f2), // see comment in wu32getdlgitem
+ psz3,
+ WORD32(parg16->f4)
+ ));
+
+ FLUSHVDMPTR(parg16->f3, strlen(psz3)+1, psz3);
+ FREEVDMPTR(psz3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HWND GetNextDlgGroupItem(<hDlg>, <hCtl>, <bPrevious>)
+ HWND <hDlg>;
+ HWND <hCtl>;
+ BOOL <bPrevious>;
+
+ The %GetNextDlgGroupItem% function searches for the next (or previous)
+ control within a group of controls in the dialog box identified by the
+ <hDlg> parameter. A group of controls consists of one or more controls with
+ WS_GROUP style.
+
+ <hDlg>
+ Identifies the dialog box being searched.
+
+ <hCtl>
+ Identifies the control in the dialog box where the search starts.
+
+ <bPrevious>
+ Specifies how the function is to search the group of controls in the
+ dialog box. If the <bPrevious> parameter is zero, the function searches
+ for the previous control in the group. If -<bPrevious> is TRUE, the
+ function searches for the next control in the group.
+
+ The return value identifies the next or previous control in the group.
+
+ If the current item is the last item in the group and <bPrevious> is FALSE,
+ the %GetNextDlgGroupItem% function returns the window handle of the first
+ item in the group. If the current item is the first item in the group and
+ <bPrevious> is TRUE, %GetNextDlgGroupItem% returns the window handle of the
+ last item in the group.
+--*/
+
+ULONG FASTCALL WU32GetNextDlgGroupItem(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETNEXTDLGGROUPITEM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETNEXTDLGGROUPITEM16), parg16);
+
+ ul = GETHWND16(GetNextDlgGroupItem(HWND32(parg16->f1),
+ HWND32(parg16->f2),
+ BOOL32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HWND GetNextDlgTabItem(<hDlg>, <hCtl>, <bPrevious>)
+ HWND <hDlg>;
+ HWND <hCtl>;
+ BOOL <bPrevious>;
+
+ The %GetNextDlgTabItem% function obtains the handle of the first control
+ that has the WS_TABSTOP style that precedes (or follows) the control
+ identified by the <hCtl> parameter.
+
+ <hDlg>
+ Identifies the dialog box being searched.
+
+ <hCtl>
+ Identifies the control to be used as a starting point for the
+ search.
+
+ <bPrevious>
+ Specifies how the function is to search the dialog box. If the
+ <bPrevious> parameter is FALSE, the function searches for the previous
+ control in the dialog box. If <bPrevious> is TRUE, the function searches
+ for the next control in the dialog box. Identifies the control to be
+ used as a starting point for the search.
+
+ The return value identifies the previous (or next) control that has the
+ WS_TABSTOP style set.
+--*/
+
+ULONG FASTCALL WU32GetNextDlgTabItem(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETNEXTDLGTABITEM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETNEXTDLGTABITEM16), parg16);
+
+ ul = GETHWND16(GetNextDlgTabItem(HWND32(parg16->f1),
+ HWND32(parg16->f2),
+ BOOL32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL IsDialogMessage(<hDlg>, <lpMsg>)
+ HWND <hDlg>;
+ LPMSG <lpMsg>;
+
+ The %IsDialogMessage% function determines whether the given message is
+ intended for the modeless dialog box specified by the <hDlg> parameter, and
+ automatically processes the message if it is. When the %IsDialogMessage%
+ function processes a message, it checks for keyboard messages and converts
+ them into selection commands for the corresponding dialog box. For example,
+ the ^TAB^ key selects the next control or group of controls, and the ^DOWN^
+ key selects the next control in a group.
+
+ If a message is processed by %IsDialogMessage%, it must not be passed to the
+ %TranslateMessage% or %DispatchMessage% function. This is because
+ %IsDialogMessage% performs all necessary translating and dispatching of
+ messages.
+
+ %IsDialogMessage% sends WM_GETDLGCODE messages to the dialog function to
+ determine which keys should be processed.
+
+ <hDlg>
+ Identifies the dialog box.
+
+ <lpMsg>
+ Points to an %MSG% structure that contains the message to
+ be checked.
+
+ The return value specifies whether or not the given message has been
+ processed. It is TRUE if the message has been processed. Otherwise, it is
+ FALSE.
+
+ Although %IsDialogMessage% is intended for modeless dialog boxes, it can be
+ used with any window that contains controls to provide the same keyboard
+ selection as in a dialog box.
+--*/
+
+ULONG FASTCALL WU32IsDialogMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ MSG t2;
+ register PISDIALOGMESSAGE16 parg16;
+ MSGPARAMEX mpex;
+ PMSG16 pMsg16;
+
+ GETARGPTR(pFrame, sizeof(ISDIALOGMESSAGE16), parg16);
+ GETMISCPTR(parg16->f2, pMsg16);
+
+ mpex.Parm16.WndProc.hwnd = pMsg16->hwnd;
+ mpex.Parm16.WndProc.wMsg = pMsg16->message;
+ mpex.Parm16.WndProc.wParam = pMsg16->wParam;
+ mpex.Parm16.WndProc.lParam = pMsg16->lParam;
+ mpex.iMsgThunkClass = WOWCLASS_UNKNOWN;
+
+ ThunkMsg16(&mpex);
+
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ GETARGPTR(pFrame, sizeof(ISDIALOGMESSAGE16), parg16);
+
+ t2.message = mpex.uMsg;
+ t2.wParam = mpex.uParam;
+ t2.lParam = mpex.lParam;
+ t2.hwnd = HWND32(FETCHWORD(pMsg16->hwnd));
+ t2.time = FETCHLONG(pMsg16->time);
+ t2.pt.x = FETCHSHORT(pMsg16->pt.x);
+ t2.pt.y = FETCHSHORT(pMsg16->pt.y);
+
+ ul = GETBOOL16(IsDialogMessage(
+ HWND32(parg16->f1),
+ &t2
+ ));
+
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ mpex.uMsg = t2.message;
+ mpex.uParam = t2.wParam;
+ mpex.lParam = t2.lParam;
+ (mpex.lpfnUnThunk16)(&mpex);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ WORD IsDlgButtonChecked(<hDlg>, <nIDButton>)
+ HWND <hDlg>;
+ int <nIDButton>;
+
+ The %IsDlgButtonChecked% function determines whether a button control has a
+ checkmark next to it, and whether a three-state button control is grayed,
+ checked, or neither. The %IsDlgButtonChecked% function sends a BM_GETCHECK
+ message to the button control.
+
+ <hDlg>
+ Identifies the dialog box that contains the button control.
+
+ <nIDButton>
+ Specifies the integer identifier of the button control.
+
+ The return value specifies the outcome of the function. It is nonzero if the
+ given control has a checkmark next to it. Otherwise, it is zero. For
+ three-state buttons, the return value is 2 if the button is grayed, 1 if the
+ button has a checkmark next to it, and zero otherwise.
+--*/
+
+ULONG FASTCALL WU32IsDlgButtonChecked(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISDLGBUTTONCHECKED16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISDLGBUTTONCHECKED16), parg16);
+
+ ul = GETWORD16(IsDlgButtonChecked(
+ HWND32(parg16->f1),
+ WORD32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void MapDialogRect(<hDlg>, <lpRect>)
+ HDLG <hDlg>;
+ LPRECT <lpRect>;
+
+ The %MapDialogRect% function converts the dialog-box units given in the
+ <lpRect> parameter to screen units. Dialog-box units are stated in terms of
+ the current dialog base unit derived from the average width and height of
+ characters in the system font. One horizontal unit is one-fourth of the
+ dialog base width unit, and one vertical unit is one-eighth of the dialog
+ base height unit. The %GetDialogBaseUnits% function returns the dialog base
+ units in pixels.
+
+ The %MapDialogRect% function replaces the dialog-box units in <lpRect> with
+ screen units (pixels), so that the rectangle can be used to create a dialog
+ box or position a control within a box.
+
+ <hDlg>
+ Identifies a dialog box.
+
+ <lpRect>
+ Points to a %RECT% structure that contains the dialog-box
+ coordinates to be converted.
+
+ This function does not return a value.
+
+ The <hDlg> parameter must be created by using the %CreateDialog% or
+ %DialogBox% function.
+--*/
+
+ULONG FASTCALL WU32MapDialogRect(PVDMFRAME pFrame)
+{
+ RECT t2;
+ register PMAPDIALOGRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(MAPDIALOGRECT16), parg16);
+ WOW32VERIFY(GETRECT16(parg16->f2, &t2));
+
+ MapDialogRect(
+ HWND32(parg16->f1),
+ &t2
+ );
+
+ PUTRECT16(parg16->f2, &t2);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ int MessageBox(<hwndParent>, <lpText>, <lpCaption>, <wType>)
+ HWND <hwndParent>;
+ LPSTR <lpText>;
+ LPSTR <lpCaption>;
+ WORD <wType>;
+
+ The %MessageBox% function creates and displays a window that contains an
+ application-supplied message and caption, plus any combination of the
+ predefined icons and push buttons described in the following list.
+
+ <hwndParent>
+ Identifies the window that owns the message box.
+
+ <lpText>
+ Points to a null-terminated string containing the message to be
+ displayed.
+
+ <lpCaption>
+ Points to a null-terminated string to be used for the dialog-box
+ caption. If the <lpCaption> parameter is NULL, the default caption Error
+ is used.
+
+ <wType>
+ Specifies the contents of the dialog box. It can be any
+ combination of the following values:
+
+ MB_ABORTRETRYIGNORE
+ Message box contains three push buttons: Abort, Retry, and Ignore.
+
+ MB_APPLMODAL
+ The user must respond to the message box before continuing work in the
+ window identified by the <hwndParent> parameter. However, the user can
+ move to the windows of other applications and work in those windows.
+ MB_APPLMODAL is the default if neither MB_SYSTEMMODAL nor MB_TASKMODAL
+ are specified.
+
+ MB_DEFBUTTON1
+ First button is the default. Note that the first button is always the
+ default unless MB_DEFBUTTON2 or MB_DEFBUTTON3 is specified.
+
+ MB_DEFBUTTON2
+ Second button is the default.
+
+ MB_DEFBUTTON3
+ Third button is the default.
+
+ MB_ICONASTERISK
+ Same as MB_ICONINFORMATION.
+
+ MB_ICONEXCLAMATION
+ An exclamation-point icon appears in the message box.
+
+ MB_ICONHAND
+ Same as MB_ICONSTOP.
+
+ MB_ICONINFORMATION
+ An icon consisting of a lowercase i in a circle appears in the message
+ box.
+
+ MB_ICONQUESTION
+ A question-mark icon appears in the message box.
+
+ MB_ICONSTOP
+ A stop sign icon appears in the message box.
+
+ MB_OK
+ Message box contains one push button: OK.
+
+ MB_OKCANCEL
+ Message box contains two push buttons: OK and Cancel.
+
+ MB_RETRYCANCEL
+ Message box contains two push buttons: Retry and Cancel.
+
+ MB_SYSTEMMODAL
+ All applications are suspended until the user responds to the message
+ box. Unless the application specifies MB_ICONHAND, the message box does
+ not become modal until after it is created; consequently, the parent
+ window and other windows continue to receive messages resulting from its
+ activation. System-modal message boxes are used to notify the user of
+ serious, potentially damaging errors that require immediate attention
+ (for example, running out of memory).
+
+ MB_TASKMODAL
+ Same as MB_APPMODAL except that all the top-level windows belonging to
+ the current task are disabled if the <hwndOwner> parameter is NULL. This
+ flag should be used when the calling application or library does not
+ have a window handle available, but still needs to prevent input to
+ other windows in the current application without suspending other
+ applications.
+
+ MB_YESNO
+ Message box contains two push buttons: Yes and No.
+
+ MB_YESNOCANCEL
+ Message box contains three push buttons: Yes, No, and Cancel.
+
+ The return value specifies the outcome of the function. It is zero if there
+ is not enough memory to create the message box. Otherwise, it is one of the
+ following menu-item values returned by the dialog box:
+
+ IDABORT Abort button pressed.
+ IDCANCEL Cancel button pressed.
+ IDIGNORE Ignore button pressed.
+ IDNO No button pressed.
+ IDOK OK button pressed.
+ IDRETRY Retry button pressed.
+ IDYES Yes button pressed.
+
+ If a message box has a Cancel button, the IDCANCEL value will be returned if
+ either the ^ESCAPE^ key or Cancel button is pressed. If the message box has
+ no Cancel button, pressing the ^ESCAPE^ key has no effect.
+
+ When a system-modal message box is created to indicate that the system is
+ low on memory, the strings passed as the <lpText> and <lpCaption> parameters
+ should not be taken from a resource file, since an attempt to load the
+ resource may fail.
+
+ When an application calls the %MessageBox% function and specifies the
+ MB_ICONHAND and MB_SYSTEMMODAL flags for the <wType> parameter, Windows will
+ display the resulting message box regardless of available memory. When these
+ flags are specified, Windows limits the length of the message-box text to
+ one line.
+
+ If a message box is created while a dialog box is present, use the handle of
+ the dialog box as the <hwndParent> parameter. The <hwndParent> parameter
+ should not identify a child window, such as a dialog-box control.
+--*/
+
+ULONG FASTCALL WU32MessageBox(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ PSZ psz3;
+ register PMESSAGEBOX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(MESSAGEBOX16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+ GETPSZPTR(parg16->f3, psz3);
+
+ ul = GETINT16(MessageBox(
+ HWND32(parg16->f1),
+ psz2,
+ psz3,
+ WORD32(parg16->f4)
+ ));
+
+ FREEPSZPTR(psz2);
+ FREEPSZPTR(psz3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void SetDlgItemInt(<hDlg>, <nIDDlgItem>, <wValue>, <bSigned>)
+ HWND <hDlg>;
+ int <nIDDlgItem>;
+ WORD <wValue>;
+ BOOL <bSigned>;
+
+ The %SetDlgItemInt% function sets the text of a control in the given dialog
+ box to the string that represents the integer value given by the <wValue>
+ parameter. The %SetDlgItemInt% function converts <wValue> to a string that
+ consists of decimal digits, and then copies the string to the control. If
+ the <bSigned> parameter is TRUE, <wValue> is assumed to be signed. If
+ <wValue> is signed and less than zero, the function places a minus sign
+ before the first digit in the string.
+
+ %SetDlgItemInt% sends a WM_SETTEXT message to the given control.
+
+ <hDlg>
+ Identifies the dialog box that contains the control.
+
+ <nIDDlgItem>
+ Specifies the control to be modified.
+
+ <wValue>
+ Specifies the value to be set.
+
+ <bSigned>
+ Specifies whether or not the integer value is signed.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32SetDlgItemInt(PVDMFRAME pFrame)
+{
+ register PSETDLGITEMINT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETDLGITEMINT16), parg16);
+
+ SetDlgItemInt(
+ HWND32(parg16->f1),
+ WORD32(parg16->f2), // see comment in wu32getdlgitem
+ (parg16->f4) ? INT32(parg16->f3) : WORD32(parg16->f3),
+ BOOL32(parg16->f4)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ void SetDlgItemText(<hDlg>, <nIDDlgItem>, <lpString>)
+ HWND <hDlg>;
+ int <nIDDlgItem>;
+ LPSTR <lpString>;
+
+ The %SetDlgItemText% function sets the caption or text of a control in the
+ dialog box specified by the <hDlg> parameter. The %SetDlgItemText% function
+ sends a WM_SETTEXT message to the given control.
+
+ <hDlg>
+ Identifies the dialog box that contains the control.
+
+ <nIDDlgItem>
+ Specifies the control whose text is to be set.
+
+ <lpString>
+ Points to the null-terminated string that is to be copied to the
+ control.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32SetDlgItemText(PVDMFRAME pFrame)
+{
+ PSZ psz3;
+ register PSETDLGITEMTEXT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETDLGITEMTEXT16), parg16);
+ GETPSZPTR(parg16->f3, psz3);
+
+ SetDlgItemText(
+ HWND32(parg16->f1),
+ WORD32(parg16->f2), // see comment in wu32getdlgitem
+ psz3
+ );
+
+ FREEPSZPTR(psz3);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ No REF header file
+--*/
+
+ULONG FASTCALL WU32SysErrorBox(PVDMFRAME pFrame)
+{
+ DWORD dwExitCode;
+ PSZ pszText;
+ PSZ pszCaption;
+ register PSYSERRORBOX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SYSERRORBOX16), parg16);
+
+ // WARNING - If things go wrong during boot, this routine can be called in
+ // real mode (v86 mode). So be very careful which GetPtr routines you
+ // use to convert from 16:16 to flat pointers
+
+ pszText = WOWGetVDMPointer(FETCHDWORD(parg16->vpszText),0,fWowMode);
+ pszCaption = WOWGetVDMPointer(FETCHDWORD(parg16->vpszCaption),0,fWowMode);
+
+ LOGDEBUG(5,(" SYSERRORBOX: %s\n", pszText));
+
+ dwExitCode = WOWSysErrorBox(
+ pszCaption,
+ pszText,
+ parg16->sBtn1,
+ parg16->sBtn2,
+ parg16->sBtn3
+ );
+
+ FREEPSZPTR(pszCaption);
+ FREEPSZPTR(pszText);
+ FREEARGPTR(parg16);
+ RETURN(dwExitCode);
+}
diff --git a/private/mvdm/wow32/wudlg.h b/private/mvdm/wow32/wudlg.h
new file mode 100644
index 000000000..0181f35e5
--- /dev/null
+++ b/private/mvdm/wow32/wudlg.h
@@ -0,0 +1,42 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUDLG.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* Function prototypes
+ */
+LONG W32DialogFunc(HWND hdlg, UINT uMsg, DWORD uParam, LONG lParam);
+
+ULONG FASTCALL WU32CheckDlgButton(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CheckRadioButton(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DialogBoxParam(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DlgDirList(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DlgDirListComboBox(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DlgDirSelect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DlgDirSelectComboBox(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EndDialog(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetDialogBaseUnits(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetDlgCtrlID(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetDlgItem(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetDlgItemInt(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetDlgItemText(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetNextDlgGroupItem(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetNextDlgTabItem(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsDialogMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsDlgButtonChecked(PVDMFRAME pFrame);
+ULONG FASTCALL WU32MapDialogRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32MessageBox(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetDlgItemInt(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetDlgItemText(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SysErrorBox(PVDMFRAME pFrame);
+
diff --git a/private/mvdm/wow32/wuhook.c b/private/mvdm/wow32/wuhook.c
new file mode 100644
index 000000000..a08962b5c
--- /dev/null
+++ b/private/mvdm/wow32/wuhook.c
@@ -0,0 +1,642 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUHOOK.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wuhook.c);
+
+
+/*++
+ FARPROC SetWindowsHook(<nFilterType>, <lpFilterFunc>)
+ int <nFilterType>;
+ FARPROC <lpFilterFunc>;
+
+ The %SetWindowsHook% function installs a filter function in a chain. A
+ filter function processes events before they are sent to an application's
+ message loop in the WinMain function. A chain is a linked list of filter
+ functions of the same type.
+
+ <nFilterType>
+ Specifies the system hook to be installed. It can be any one of the
+ following values:
+
+ WH_CALLWNDPROC Installs a window-function filter.
+ WH_GETMESSAGE Installs a message filter.
+ WH_JOURNALPLAYBACK Installs a journaling playback filter.
+ WH_JOURNALRECORD Installs a journaling record filter.
+ WH_KEYBOARD Installs a keyboard filter.
+ WH_MSGFILTER Installs a message filter.
+ WH_SYSMSGFILTER Installs a system-wide message filter.
+
+ <lpFilterFunc>
+ Is the procedure-instance address of the filter function to be
+ installed. See the following Comments section for details.
+
+ The return value points to the procedure-instance address of the previously
+ installed filter (if any). It is NULL if there is no previous filter. The
+ application or library that calls the %SetWindowsHook% function should save
+ this return value in the library's data segment. The fourth argument of the
+ %DefHookProc% function points to the location in memory where the library
+ saves this return value.
+
+ The return value is -1 if the function fails.
+
+ The WH_CALLWNDPROC hook will affect system performance. It is supplied for
+ debugging purposes only.
+
+ The system hooks are a shared resource. Installing a hook affects all
+ applications. Most hook functions must be in libraries. The only exception
+ is WH_MSGFILTER, which is task-specific. System hooks should be restricted
+ to special-purpose applications or as a development aid during debugging of
+ an application. Libraries that no longer need the hook should remove the
+ filter function.
+
+ To install a filter function, the %SetWindowsHook% function must receive a
+ procedure-instance address of the function, and the function must be
+ exported in the library's module-definition file. Libraries can pass the
+ procedure address directly. Tasks must use %MakeProcInstance% to get a
+ procedure-instance address. Dynamic-link libraries must use %GetProcAddress%
+ to get a procedure-instance address.
+
+ The following section describes how to support the individual hook
+ functions.
+
+ WH_CALLWNDPROC:
+
+ Windows calls the WH_CALLWNDPROC filter function whenever the %SendMessage%
+ function is called. Windows does not call the filter function when the
+ %PostMessage% function is called.
+
+ The filter function must use the Pascal calling convention and must be
+ declared %FAR%. The filter function must have the following form:
+
+ Filter Function:
+
+ DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
+ int <nCode>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ <FilterFunc> is a placeholder for the application- or library-supplied
+ function name. The actual name must be exported by including it in an
+ %EXPORTS% statement in the library's module-definition file.
+
+ <nCode>
+ Specifies whether the filter function should process the message or call
+ the DefHookProc function. If the nCode parameter is less than zero, the
+ filter function should pass the message to DefHookProc without further
+ processing. <wParam> Specifies whether the message is sent by the
+ current task. It is nonzero if the message is sent; otherwise, it is
+ NULL.
+
+ <lParam>
+ Points to a structure that contains details about the message
+ intercepted by the filter. The following shows the order, type, and
+ description of each field of the structure:
+
+ %lParam%
+ %WORD% Contains the low-order word of the <lParam> parameter of the
+ message received by the filter.
+
+ %wParam%
+ %WORD% Contains the <wParam> parameter of the message received by the
+ filter.
+
+ %wMsg%
+ %WORD% Contains the message received by the filter.
+
+ %hwnd%
+ %WORD% Contains the window handle of the window that is to receive the
+ message.
+
+ The WH_CALLWNDPROC filter function can examine or modify the message as
+ desired. Once it returns control to Windows, the message, with any
+ modifications, is passed on to the window function. The filter function does
+ not require a return value.
+
+ WH_GETMESSAGE:
+
+ Windows calls the WH_GETMESSAGE filter function whenever the %GetMessage%
+ function is called. Windows calls the filter function immediately after
+ %GetMessage% has retrieved a message from an application queue. The filter
+ function must use the Pascal calling convention and must be declared %FAR%.
+ The filter function must have the following form:
+
+ Filter Function:
+
+ DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
+ int <nCode>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ <FilterFunc> is a placeholder for the library-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the library's module-definition file.
+
+ <nCode>
+ Specifies whether the filter function should process the message or call
+ the DefHookProc function. If the <nCode> parameter is less than zero, the
+ filter function should pass the message to DefHookProc without further
+ processing.
+
+ <wParam>
+ Specifies a NULL value.
+
+ <lParam>
+ Points to a message structure.
+
+ The WH_GETMESSAGE filter function can examine or modify the message as
+ desired. Once it returns control to Windows, the %GetMessage% function
+ returns the message, with any modifications, to the application that
+ originally called it. The filter function does not require a return value.
+
+ WH_JOURNALPLAYBACK:
+
+ Windows calls the WH_JOURNALPLAYBACK filter function whenever a request for
+ an event message is made. The function is intended to be used to supply a
+ previously recorded event message.
+
+ The filter function must use the Pascal calling convention and must be
+ declared %FAR%. The filter function must have the following form:
+
+ DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
+ int <nCode>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ <FilterFunc> is a placeholder for the library-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the library's module-definition file.
+
+ <nCode>
+ Specifies whether the filter function should process the message or call
+ the DefHookProc function. If the nCode parameter is less then zero, the
+ filter function should pass the message to DefHookProc without further
+ processing.
+
+ <wParam>
+ Specifies a NULL value.
+
+ <lParam>
+ Points to the message being processed by the filter function.
+
+ The WH_JOURNALPLAYBACK function should copy an event message to the <lParam>
+ parameter. The message must have been previously recorded by using the
+ WH_JOURNALRECORD filter. It should not modify the message. The return value
+ should be the amount of time (in clock ticks) Windows should wait before
+ processing the message. This time can be computed by calculating the
+ difference between the %time% fields in the current and previous event
+ messages. If the function returns zero, the message is processed
+ immediately. Once it returns control to Windows, the message continues to be
+ processed. If the <nCode> parameter is HC_SKIP, the filter function should
+ prepare to return the next recorded event message on its next call.
+
+ While the WH_JOURNALPLAYBACK function is in effect, Windows ignores all
+ mouse and keyboard input.
+
+ WH_JOURNALRECORD:
+
+ Windows calls the WH_JOURNALRECORD filter function whenever it processes a
+ message from the event queue. The filter can be used to record the event for
+ later playback.
+
+ The filter function must use the Pascal calling convention and must be
+ declared %FAR%. The filter function must have the following form:
+
+ DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>,<lParam>)
+ int <nCode>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ <FilterFunc> is a placeholder for the library-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the library's module-definition file.
+
+ <nCode>
+ Specifies whether the filter function should process the message or call
+ the DefHookProc function. If the nCode parameter is less than zero, the
+ filter function should pass the message to DefHookProc without further
+ processing.
+
+ <wParam>
+ Specifies a NULL value.
+
+ <lParam>
+ Points to a message structure.
+
+ The WH_JOURNALRECORD function should save a copy of the event message for
+ later playback. It should not modify the message. Once it returns control to
+ Windows, the message continues to be processed. The filter function does not
+ require a return value.
+
+ WH_KEYBOARD:
+
+ Windows calls the WH_KEYBOARD filter function whenever the application calls
+ the %GetMessage% or %PeekMessage% function and there is a keyboard event
+ (WM_KEYUP or WM_KEYDOWN) to process.
+
+ The filter function must use the Pascal calling convention and must be
+ declared %FAR%. The filter function must have the following form:
+
+ DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
+ int <nCode>;
+ WORD <wParam>; DWORD <lParam>;
+
+ <FilterFunc> is a placeholder for the library-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the library's module-definition file.
+
+ <nCode>
+ Specifies whether the filter function should process the message or call
+ the DefHookProc function. If this value is HC_NOREMOVE, the application
+ is using the PeekMessage function with the PM_NOREMOVE option and the
+ message will not be removed from the system queue. If this value is less
+ than zero, the filter function should pass the message to DefHookProc
+ without further processing.
+
+ <wParam>
+ Specifies the virtual-key code of the given key.
+
+ <lParam>
+ Specifies the repeat count, scan code, key-transition code, previous key
+ state, and context code, as shown in the following list. Bit 1 is the
+ low-order bit:
+
+ 0-15
+ (low-order word) Repeat count (the number of times the keystroke is
+ repeated as a result of the user holding down the key).
+
+ 16-23
+ (low byte of high-order word) Scan code (OEM-dependent value).
+
+ 24
+ Extended key (1 if it is an extended key).
+
+ 25-26
+ Not used.
+
+ 27-28
+ (Context code (1 if the ^ALT^ key was held down while the key was
+ pressed, 0 otherwise) Used internally by Windows.
+
+ 30
+ Previous key state (1 if the key was held down before the message was
+ sent, 0 if the key was up).
+
+ 31
+ Transition state (1 if the key is being released, 0 if the key is being
+ pressed).
+
+ The return value specifies what should happen to the message. It is zero if
+ the message should be processed by Windows; it is 1 if the message should be
+ discarded.
+
+ WH_MSGFILTER:
+
+ Windows calls the WH_MSGFILTER filter function whenever a dialog box,
+ message box, or menu has retrieved a message, and before it has processed
+ that message. The filter allows an application to process or modify the
+ messages.
+
+ This is the only task-specific filter. A task may install this filter.
+
+ The WH_MSGFILTER filter function must use the Pascal calling convention and
+ must be declared %FAR%. The filter function must have the following form:
+
+ DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
+ int <nCode>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ <FilterFunc> is a placeholder for the library- or application-supplied
+ function name. The actual name must be exported by including it in an
+ %EXPORTS% statement in the application's module-definition file.
+
+ <nCode>
+ Specifies the type of message being processed. It must be one of the
+ following values:
+
+ MSGF_MENU
+ Processing keyboard and mouse messages in a menu.
+
+ MSGF_MENU
+ Processing keyboard and mouse messages in a menu.
+
+ If the <nCode> parameter is less than zero, the filter function must
+ pass the message to %DefHookProc% without further processing and return
+ the value returned by %DefHookProc%.
+
+ <wParam>
+ Specifies a NULL value.
+
+ <lParam>
+ Points to the message structure.
+
+ The return value specifies the outcome of the function. It is nonzero if the
+ hook function processes the message. Otherwise, it is zero.
+
+ WH_SYSMSGFILTER:
+
+ Windows calls the WH_SYSMSGFILTER filter function whenever a dialog box,
+ message box, or menu has retrieved a message and before it has processed
+ that message. The filter allows an application to process or modify messages
+ for any application in the system.
+
+ The filter function must use the Pascal calling convention and must be
+ declared %FAR%. The filter function must have the following form:
+
+ DWORD FAR PASCAL <FilterFunc>(<nCode>, <wParam>, <lParam>)
+ int <nCode>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ <FilterFunc> is a placeholder for the library-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the library's module-definition file.
+
+ <nCode>
+ Specifies the type of message being processed. It must be one of the
+ following values:
+
+ MSGF_MENU
+ Processing keyboard and mouse messages in menu.
+
+ MSGF_MESSAGEBOX
+ Processing messages inside the %MessageBox% function.
+
+ If the <nCode> parameter is less than zero, the filter function must
+ pass the message to %DefHookProc% without further processing and return
+ the value returned by %DefHookProc%.
+
+ <wParam>
+ Specifies a NULL value.
+
+ <lParam>
+ Points to the message structure.
+
+ The return value specifies the outcome of the function. It is nonzero if the
+ hook function processes the message. Otherwise, it is zero.
+--*/
+
+ULONG FASTCALL WU32SetWindowsHookInternal(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETWINDOWSHOOKINTERNAL16 parg16;
+ HOOKSTATEDATA HkData;
+ HAND16 hMod16;
+ INT iHook;
+ DWORD Proc16;
+ DWORD ThreadId;
+ PTD ptd = CURRENTPTD();
+
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWSHOOKINTERNAL16), parg16);
+ hMod16 = FETCHWORD(parg16->f1);
+ iHook = INT32(parg16->f2);
+ Proc16 = DWORD32(parg16->f3);
+
+ //
+ // HACKHACK - Work around MS Mail 3.0's journal record hook.
+ // This hook is used only to keep track of the input
+ // activity in the system. When the hook is called,
+ // Mail simply stores the current time. Later, on
+ // expiration of a timer, Mail determines whether or
+ // not to start background database compression, using
+ // the amount of time since input was received as a
+ // determining factor. If the hook hasn't been called
+ // in a while, Mail is more likely to start slow
+ // compression or switch to fast compression.
+ //
+ // The problem is that WH_JOURNALRECORD causes all
+ // threads in the system to share one input queue,
+ // thereby meaning that any app that stops processing
+ // input hangs the entire UI.
+ //
+ // For now, just disable the hook.
+ //
+
+ if (WH_JOURNALRECORD == iHook &&
+ (ptd->dwWOWCompatFlags & WOWCF_FAKEJOURNALRECORDHOOK)) {
+ return 0;
+ }
+
+ /*
+ ** Micrografx Draw installs a hook, then when minimized, it unhooks the
+ ** hook by re-hooking the return value from the original hook call.
+ ** This works in Win 3.1 because the hook return value is a proc address.
+ ** We can detect this by looking at the HIWORD of the proc address. If
+ ** it is NULL, we assume they are passing us a hook handle instead of
+ ** a proc address. If this is the case, then what they really want is
+ ** unhooking. -BobDay
+ */
+ if ( HIWORD(Proc16) == HOOK_ID ) {
+ ul = GETBOOL16(UnhookWindowsHookEx(W32FreeHHookOfIndex(GETHHOOKINDEX(Proc16))));
+ FREEARGPTR(parg16);
+ return( ul );
+ }
+
+ if (!(ul = (ULONG)W32IsDuplicateHook(iHook, Proc16, ptd->htask16))) {
+ if (W32GetThunkHookProc(iHook, Proc16, &HkData)) {
+
+ // We pass threadid=0, for all hooks except WH_MSGFILTER.
+ // because it is the only task-specific filter in WIN30.
+ //
+ // The understanding between USER and WOW is this:
+ // When a WOW thread sets a hook, with thread ID = 0,
+ // USER does the following:
+ // If Journal Hooks are being set, USER will set the
+ // WOW hook 'globally', ie. system wide.
+ //
+ // For all the other hooks, USER sets the hook for all
+ // 'WOW' threads i.e., the hook is global for the WOW
+ // process.
+ //
+ // If the threadiD != 0, then no special processing is done.
+ // the hook is set only for that particular thread.
+ //
+
+ if (iHook == (INT)WH_MSGFILTER)
+ ThreadId = (DWORD)THREADID32(HkData.TaskId);
+ else
+ ThreadId = 0;
+
+ ul = (ULONG)SetWindowsHookEx(iHook, (HOOKPROC)HkData.Proc32,
+ (HINSTANCE)HkData.hMod, ThreadId);
+ HkData.hHook = (HANDLE)ul;
+ HkData.hMod16 = hMod16;
+
+ // Excel looks at the hiword; so instead of passing back just an
+ // index we make the hiword a hook identifier.
+ if (ul == (ULONG)NULL)
+ HkData.InUse = FALSE;
+ else
+ ul = MAKEHHOOK(HkData.iIndex);
+
+ W32SetHookStateData(&HkData);
+ }
+ else
+ ul = (ULONG)NULL;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL UnhookWindowsHook(<nHook>, <lpfnHook>)
+
+ The %UnhookWindowsHook% function removes the Windows hook function pointed
+ to by the <lpfnHook> parameter from a chain of hook functions. A Windows
+ hook function processes events before they are sent to an application's
+ message loop in the WinMain function.
+
+ <nHook>
+ int Specifies the type of hook function removed. It may be one of the
+ following values:
+
+ WH_CALLWNDPROC
+ Installs a window-function filter.
+
+ WH_GETMESSAGE
+ Installs a message filter.
+
+ WH_JOURNALPLAYBACK
+ Installs a journaling playback filter.
+
+ WH_JOURNALRECORD
+ Installs a journaling record filter.
+
+ WH_KEYBOARD
+ Install a keyboard filter.
+
+ WH_MSGFILTER
+ Installs a message filter.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ hook function is successfully removed. Otherwise, it is FALSE.
+--*/
+
+ULONG FASTCALL WU32UnhookWindowsHook(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PUNHOOKWINDOWSHOOK16 parg16;
+ INT iHook;
+ DWORD Proc16;
+
+ GETARGPTR(pFrame, sizeof(UNHOOKWINDOWSHOOK16), parg16);
+ iHook = INT32(parg16->f1);
+ Proc16 = DWORD32(parg16->f2);
+
+
+ ul = GETBOOL16(UnhookWindowsHookEx(W32FreeHHook(iHook, Proc16)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ CallNextHookEx - similar to DefHookProc
+--*/
+
+ULONG FASTCALL WU32CallNextHookEx(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PCALLNEXTHOOKEX16 parg16;
+ HOOKSTATEDATA HkData;
+ ULONG hHook16;
+ INT nCode;
+ LONG wParam;
+ LONG lParam;
+ DWORD iHookCode;
+
+ GETARGPTR(pFrame, sizeof(CALLNEXTHOOKEX16), parg16);
+
+
+ hHook16 = DWORD32(parg16->f1);
+ nCode = INT32(parg16->f2);
+ wParam = WORD32(parg16->f3);
+ lParam = DWORD32(parg16->f4);
+
+ if (ISVALIDHHOOK(hHook16)) {
+ iHookCode = GETHHOOKINDEX(hHook16);
+ HkData.iIndex = (INT)iHookCode;
+ if ( W32GetHookStateData( &HkData ) ) {
+ ul = (ULONG)WU32StdDefHookProc(nCode, wParam, lParam, iHookCode);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ SetWindowsHookEx - similar to SetWindowsHook.
+
+--*/
+
+ULONG FASTCALL WU32SetWindowsHookEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETWINDOWSHOOKEX16 parg16;
+ HOOKSTATEDATA HkData;
+ INT iHook;
+ DWORD Proc16;
+
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWSHOOKEX16), parg16);
+ iHook = INT32(parg16->f1);
+ Proc16 = DWORD32(parg16->f2);
+
+ if (W32GetThunkHookProc(iHook, Proc16, &HkData)) {
+ ul = (ULONG)SetWindowsHookEx(iHook, (HOOKPROC)HkData.Proc32,
+ (HINSTANCE)HkData.hMod, (DWORD)THREADID32(parg16->f4));
+ HkData.hHook = (HANDLE)ul;
+ if (ul == (ULONG)NULL) {
+ HkData.InUse = FALSE;
+ } else {
+ ul = MAKEHHOOK(HkData.iIndex);
+ HkData.hMod16 = GetExePtr16(parg16->f3);
+ }
+
+ W32SetHookStateData(&HkData);
+ }
+ else
+ ul = (ULONG)NULL;
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ UnhookWindowsHookEx - similar to unhookwindowshook
+
+--*/
+
+ULONG FASTCALL WU32UnhookWindowsHookEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PUNHOOKWINDOWSHOOKEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(UNHOOKWINDOWSHOOKEX16), parg16);
+
+ ul = GETBOOL16(UnhookWindowsHookEx(W32FreeHHookOfIndex(GETHHOOKINDEX(INT32(parg16->f1)))));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wuhook.h b/private/mvdm/wow32/wuhook.h
new file mode 100644
index 000000000..4627f7f14
--- /dev/null
+++ b/private/mvdm/wow32/wuhook.h
@@ -0,0 +1,26 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUHOOK.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WU32SetWindowsHookInternal(PVDMFRAME pFrame);
+ULONG FASTCALL WU32UnhookWindowsHook(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CallNextHookEx(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetWindowsHookEx(PVDMFRAME pFrame);
+ULONG FASTCALL WU32UnhookWindowsHookEx(PVDMFRAME pFrame);
+
+
+#define HOOK_ID 0x4B48 // dumps as 'H' 'K'
+#define MAKEHHOOK(index) (MAKELONG(index,HOOK_ID))
+#define GETHHOOKINDEX(hook) (LOWORD(hook))
+#define ISVALIDHHOOK(hook) (HIWORD(hook) == HOOK_ID)
diff --git a/private/mvdm/wow32/wulang.c b/private/mvdm/wow32/wulang.c
new file mode 100644
index 000000000..102a579ab
--- /dev/null
+++ b/private/mvdm/wow32/wulang.c
@@ -0,0 +1,371 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WULANG.C
+ * WOW32 16-bit User API support
+ *
+ *
+ * It thunks the win 3.x language functions to NT. These functions are
+ * mainly used by the programs that are ported to various international
+ * languages.
+ *
+ * History:
+ * Created 19-April-1992 by Chandan Chauhan (ChandanC)
+ *
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wulang.c);
+
+
+/*++
+ LPSTR AnsiLower(<lpString>)
+ LPSTR <lpString>;
+
+ The %AnsiLower% function converts the given character string to
+ lowercase. The conversion is made by the language driver based on the
+ criteria of the current language selected by the user at setup or with the
+ Control Panel.
+
+ <lpString>
+ Points to a null-terminated string or specifies single character. If
+ lpString specifies single character, that character is in the low-order
+ byte of the low-order word, and the high-order word is zero.
+
+ The return value points to a converted character string if the function
+ parameter is a character string. Otherwise, it is a 32-bit value that
+ contains the converted character in the low-order byte of the low-order
+ word.
+--*/
+
+ULONG FASTCALL WU32AnsiLower(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ register PANSILOWER16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ANSILOWER16), parg16);
+ GETPSZIDPTR(parg16->f1, psz1);
+
+ ul = GETLPSTRBOGUS(AnsiLower(psz1));
+
+ if (HIWORD(psz1)) {
+ ul = parg16->f1;
+ }
+
+ FREEPSZIDPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ WORD AnsiLowerBuff(<lpString>, <nLength>)
+ LPSTR <lpString>;
+ WORD <nLength>;
+
+ The %AnsiLowerBuff% function converts character string in a buffer to
+ lowercase. The conversion is made by the language driver based on the
+ criteria of the current language selected by the user at setup or with the
+ Control Panel.
+
+ <lpString>
+ Points to a buffer containing one or more characters.
+
+ <nLength>
+ Specifies the number of characters in the buffer identified by
+ the <lpString> parameter. If <nLength> is zero, the length is
+ 64K (65,536).
+
+ The return value specifies the length of the converted string.
+--*/
+
+ULONG FASTCALL WU32AnsiLowerBuff(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PBYTE pb1;
+ register PANSILOWERBUFF16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ANSILOWERBUFF16), parg16);
+ GETVDMPTR(parg16->f1, SIZETO64K(parg16->f2), pb1);
+
+ ul = GETWORD16(AnsiLowerBuff(pb1, SIZETO64K(parg16->f2)));
+
+ FLUSHVDMPTR(parg16->f1, SIZETO64K(parg16->f2), pb1);
+ FREEVDMPTR(pb1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/*++
+ LPSTR AnsiNext(<lpCurrentChar>)
+ LPSTR <lpCurrentChar>;
+
+ The %AnsiNext% function moves to the next character in a string.
+
+ <lpCurrentChar>
+ Points to a character in a null-terminated string.
+
+ The return value points to the next character in the string, or, if there is
+ no next character, to the null character at the end of the string.
+
+ The %AnsiNext% function is used to move through strings whose characters are
+ two or more bytes each (for example, strings that contain characters from a
+ Japanese character set).
+--*/
+
+ULONG FASTCALL WU32AnsiNext(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ register PANSINEXT16 parg16;
+ DWORD ret;
+
+ GETARGPTR(pFrame, sizeof(ANSINEXT16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+
+ ul = (ULONG) AnsiNext(psz1);
+
+ ul = ul - (ULONG) psz1;
+
+ ret = FETCHDWORD(parg16->f1);
+
+ ul = MAKELONG((LOWORD(ret) + ul),HIWORD(ret));
+
+ FREEPSZPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ LPSTR AnsiPrev(<lpStart>, <lpCurrentChar>)
+ LPSTR <lpStart>;
+ LPSTR <lpCurrentChar>;
+
+ The %AnsiPrev% function moves to the previous character in a string.
+
+ <lpStart>
+ Points to the beginning of the string.
+
+ <lpCurrentChar>
+ Points to a character in a null-terminated string.
+
+ The return value points to the previous character in the string, or to the
+ first character in the string if the <lpCurrentChar> parameter is equal to
+ the <lpStart> parameter.
+
+ The %AnsiPrev% function is used to move through strings whose characters are
+ two or more bytes each (for example, strings that contain characters from a
+ Japanese character set).
+--*/
+
+ULONG FASTCALL WU32AnsiPrev(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ PSZ psz2;
+ register PANSIPREV16 parg16;
+ DWORD ret;
+
+ GETARGPTR(pFrame, sizeof(ANSIPREV16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+ GETPSZPTR(parg16->f2, psz2);
+
+ ul = (ULONG) AnsiPrev(psz1, psz2);
+
+ ul = (ULONG) psz2 - ul;
+
+ ret = FETCHDWORD(parg16->f2);
+
+ ul = MAKELONG((LOWORD(ret) - ul),HIWORD(ret));
+
+ FREEPSZPTR(psz1);
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ LPSTR AnsiUpper(<lpString>)
+ LPSTR <lpString>;
+
+ The %AnsiUpper% function converts the given character string to
+ uppercase. The conversion is made by the language driver based on the
+ criteria of the current language selected by the user at setup or with the
+ Control Panel.
+
+ <lpString>
+ Points to a null-terminated string or specifies single character. If
+ lpString specifies a single character, that character is in the
+ low-order byte of the low-order word, and the high-order word is zero.
+
+ The return value points to a converted character string if the function
+ parameter is a character string; otherwise, it is a 32-bit value that
+ contains the converted character in the low-order byte of the low-order
+ word.
+--*/
+
+ULONG FASTCALL WU32AnsiUpper(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ register PANSIUPPER16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ANSIUPPER16), parg16);
+ GETPSZIDPTR(parg16->f1, psz1);
+
+ ul = GETLPSTRBOGUS(AnsiUpper(psz1));
+
+ if (HIWORD(psz1)) {
+ ul = parg16->f1;
+ }
+
+ FREEPSZIDPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ WORD AnsiUpperBuff(<lpString>, <nLength>)
+ LPSTR <lpString>;
+ WORD <nLength>;
+
+ The %AnsiUpperBuff% function converts a character string in a buffer to
+ uppercase. The conversion is made by the language driver based on the
+ criteria of the current language selected by the user at setup or with the
+ Control Panel.
+
+ <lpString>
+ Points to a buffer containing one or more characters.
+
+ <nLength>
+ Specifies the number of characters in the buffer identified by
+ the <lpString> parameter. If <nLength> is zero, the length is 64K
+ (65,536).
+
+ The return value specifies the length of the converted string.
+--*/
+
+ULONG FASTCALL WU32AnsiUpperBuff(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PBYTE pb1;
+ register PANSIUPPERBUFF16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ANSIUPPERBUFF16), parg16);
+ GETVDMPTR(parg16->f1, SIZETO64K(parg16->f2), pb1);
+
+ ul = GETWORD16(AnsiUpperBuff(pb1, SIZETO64K(parg16->f2)));
+
+ FLUSHVDMPTR(parg16->f1, SIZETO64K(parg16->f2), pb1);
+ FREEVDMPTR(pb1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32lstrcmp(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ PSZ psz2;
+ register PLSTRCMP16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LSTRCMP16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+ GETPSZPTR(parg16->f2, psz2);
+
+ ul = GETINT16(lstrcmp(psz1, psz2));
+
+ FREEPSZPTR(psz1);
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32lstrcmpi(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ PSZ psz2;
+ register PLSTRCMPI16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LSTRCMPI16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+ GETPSZPTR(parg16->f2, psz2);
+
+ ul = GETINT16(lstrcmpi(psz1, psz2));
+
+ FREEPSZPTR(psz1);
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32IsCharAlpha(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISCHARALPHA16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISCHARALPHA16), parg16);
+
+ ul = GETBOOL16(IsCharAlpha(CHAR32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32IsCharAlphaNumeric(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISCHARALPHANUMERIC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISCHARALPHANUMERIC16), parg16);
+
+ ul = GETBOOL16(IsCharAlphaNumeric(CHAR32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32IsCharLower(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISCHARLOWER16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISCHARLOWER16), parg16);
+
+ ul = GETBOOL16(IsCharLower(CHAR32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32IsCharUpper(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISCHARUPPER16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISCHARUPPER16), parg16);
+
+ ul = GETBOOL16(IsCharUpper(CHAR32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wulang.h b/private/mvdm/wow32/wulang.h
new file mode 100644
index 000000000..f8bf4ca36
--- /dev/null
+++ b/private/mvdm/wow32/wulang.h
@@ -0,0 +1,33 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WULANG.H
+ * WOW32 16-bit User API support
+ *
+ *
+ * It thunks the win 3.x language functions to NT. These functions are
+ * mainly used by the programs that are ported to various international
+ * languages.
+ *
+ * History:
+ * Created 19-April-1992 by Chandan Chauhan (ChandanC)
+ *
+--*/
+
+
+ULONG FASTCALL WU32AnsiLower(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnsiLowerBuff(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnsiNext(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnsiPrev(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnsiUpper(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnsiUpperBuff(PVDMFRAME pFrame);
+ULONG FASTCALL WU32lstrcmp(PVDMFRAME pFrame);
+ULONG FASTCALL WU32lstrcmpi(PVDMFRAME pFrame);
+ULONG FASTCALL WU32wvsprintf(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsCharAlpha(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsCharAlphaNumeric(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsCharLower(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsCharUpper(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wuman.c b/private/mvdm/wow32/wuman.c
new file mode 100644
index 000000000..46763a589
--- /dev/null
+++ b/private/mvdm/wow32/wuman.c
@@ -0,0 +1,287 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUMAN.C
+ * WOW32 16-bit User API support (manually-coded thunks)
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wuman.c);
+
+WBP W32WordBreakProc = NULL;
+
+extern DWORD fThunkStrRtns;
+
+
+/* Called By Kernel When Initialization is Complete */
+
+ULONG FASTCALL WU32FinalUserInit(PVDMFRAME pFrame)
+{
+ UNREFERENCED_PARAMETER(pFrame);
+ return TRUE;
+}
+
+
+ULONG FASTCALL WU32ExitWindows(PVDMFRAME pFrame)
+// BUGBUG mattfe 4-mar-92, this routine should not return if we close down
+// all the apps successfully.
+{
+ ULONG ul;
+ register PEXITWINDOWS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(EXITWINDOWS16), parg16);
+
+ ul = GETBOOL16(ExitWindows(
+ DWORD32(parg16->dwReserved),
+ WORD32(parg16->wReturnCode)
+ ));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+WORD gUser16CS = 0;
+
+ULONG FASTCALL WU32NotifyWow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PNOTIFYWOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(NOTIFYWOW16), parg16);
+
+ switch (FETCHWORD(parg16->Id)) {
+ case FUN_LOADACCELERATORS:
+ ul = WU32LoadAccelerators(FETCHDWORD(parg16->pData));
+ break;
+
+ case FUN_LOADICON:
+ case FUN_LOADCURSOR:
+ ul = (ULONG) W32CheckIfAlreadyLoaded(parg16->pData, FETCHWORD(parg16->Id));
+ break;
+
+ case FUN_WINHELP:
+ {
+ // this call is made from IWinHelp in USER.exe to find the
+ // '16bit' help window if it exists.
+ //
+
+ LPSZ lpszClass;
+ GETMISCPTR(parg16->pData, lpszClass);
+ ul = (ULONG)(pfnOut.pfnWOWFindWindow)((LPCSTR)lpszClass, (LPCSTR)NULL);
+ if (ul) {
+ // check if hwndWinHelp belongs to this process or not.
+ DWORD pid, pidT;
+ pid = pidT = GetCurrentProcessId();
+ GetWindowThreadProcessId((HWND)ul, &pid);
+ ul = (ULONG)MAKELONG((WORD)GETHWND16(ul),(WORD)(pid == pidT));
+ }
+ FREEMISCPTR(lpszClass);
+ }
+ break;
+
+ case FUN_FINALUSERINIT:
+ {
+ static BYTE CallCsrFlag = 0;
+ extern DWORD gpsi;
+ PUSERCLIENTGLOBALS pfinit16;
+ WORD UNALIGNED *pwMaxDWPMsg;
+ PBYTE pDWPBits;
+#ifdef DEBUG
+ WORD wMsg;
+ int i;
+ PSZ pszFormat;
+#endif
+
+ GETVDMPTR(parg16->pData, sizeof(USERCLIENTGLOBALS), pfinit16);
+ GETVDMPTR(pfinit16->lpwMaxDWPMsg, sizeof(WORD), pwMaxDWPMsg);
+ GETVDMPTR(pfinit16->lpDWPBits, pfinit16->cbDWPBits, pDWPBits);
+
+ // store the 16bit hmod of user.exe
+ gUser16hInstance = (WORD)pfinit16->hInstance;
+ WOW32ASSERTMSGF((gUser16hInstance),
+ ("WOW Error gUser16hInstance == NULL!\n"));
+
+ // store the 16bit CS of user.exe
+ gUser16CS = HIWORD(pFrame->vpCSIP);
+
+ // initialize user16client globals
+
+ if (pfinit16->lpgpsi) {
+ BYTE **lpT;
+ GETVDMPTR(pfinit16->lpgpsi, sizeof(DWORD), lpT);
+ *lpT = (BYTE *)gpsi;
+ FLUSHVDMCODEPTR((ULONG)pfinit16->lpgpsi, sizeof(DWORD), lpT);
+ FREEVDMPTR(lpT);
+ }
+ if (pfinit16->lpCsrFlag) {
+ BYTE **lpT;
+ GETVDMPTR(pfinit16->lpCsrFlag, sizeof(DWORD), lpT);
+ *lpT = (LPSTR)&CallCsrFlag;
+ FLUSHVDMCODEPTR((ULONG)pfinit16->lpCsrFlag, sizeof(DWORD), lpT);
+ FREEVDMPTR(lpT);
+ }
+
+ if (HIWORD(pfinit16->dwBldInfo) != HIWORD(pfnOut.dwBldInfo)) {
+ MessageBeep(0);
+ MessageBoxA(NULL, "user.exe and user32.dll are mismatched.",
+ "WOW Error", MB_OK | MB_ICONEXCLAMATION);
+ }
+
+ *pwMaxDWPMsg = (pfnOut.pfnWowGetDefWindowProcBits)(pDWPBits, pfinit16->cbDWPBits);
+
+ FLUSHVDMCODEPTR(pfinit16->lpwMaxDWPMsg, sizeof(WORD), pwMaxDWPMsg);
+ FLUSHVDMCODEPTR(pfinit16->lpDWPBits, pfinit16->cbDWPBits, pDWPBits);
+
+#ifdef DEBUG
+ LOGDEBUG(LOG_TRACE, ("WU32NotifyWow: got DefWindowProc bits, wMaxDWPMsg = 0x%x.\n", *pwMaxDWPMsg));
+ LOGDEBUG(LOG_TRACE, ("The following messages will be passed on to 32-bit DefWindowProc:\n"));
+
+#define FPASSTODWP32(msg) \
+ (pDWPBits[msg >> 3] & (1 << (msg & 7)))
+
+ wMsg = 0;
+ i = 0;
+
+ while (wMsg <= *pwMaxDWPMsg) {
+ if (FPASSTODWP32(wMsg)) {
+ if ( i & 3 ) {
+ pszFormat = ", %s";
+ } else {
+ pszFormat = "\n%s";
+ }
+ LOGDEBUG(LOG_TRACE, (pszFormat, aw32Msg[wMsg].lpszW32));
+ i++;
+ }
+ wMsg++;
+ }
+
+ LOGDEBUG(LOG_TRACE, ("\n\n"));
+#endif
+
+ //
+ // Return value tells User16 whether to thunk
+ // string routines to Win32 or use the fast
+ // US-only versions. TRUE means thunk.
+ //
+ // If the locale is U.S. English, we default to
+ // not thunking, outside the U.S. we default to
+ // thunking. See wow32.c's use of fThunkStrRtns.
+ //
+ // We engage in this nastiness because the Winstone 94
+ // Access 1.1 test takes *twice* as long to run in
+ // the US if we thunk lstrcmp and lstrcmpi to Win32.
+ //
+ // By adding a value "ThunkNLS" to the WOW registry
+ // key of type REG_DWORD, the user can force thunking
+ // to Win32 (value 1) or use the fast US-only ones (value 0).
+ //
+
+ ul = fThunkStrRtns;
+
+ FREEVDMPTR(pDWPBits);
+ FREEVDMPTR(pwMaxDWPMsg);
+ FREEVDMPTR(pfinit16);
+
+ }
+ break;
+
+ default:
+ ul = 0;
+ break;
+ }
+
+ FREEARGPTR(parg16);
+ return ul;
+}
+
+
+ULONG FASTCALL WU32WordBreakProc(PVDMFRAME pFrame)
+{
+ PSZ psz1;
+ ULONG ul;
+ register PWORDBREAKPROC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(WORDBREAKPROC16), parg16);
+ GETPSZPTR(parg16->lpszEditText, psz1);
+
+ ul = (*W32WordBreakProc)(psz1, parg16->ichCurrentWord, parg16->cbEditText,
+ parg16->action);
+
+ FREEPSZPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+//
+// WU32MouseEvent: Thunk for 16-bit register-based API mouse_event,
+// with the help of user16 function mouse_event (in
+// winmisc2.asm).
+//
+
+ULONG FASTCALL WU32MouseEvent(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PMOUSEEVENT16 parg16;
+ typedef ULONG (WINAPI *PFMOUSE_EVENT)(DWORD, DWORD, DWORD, DWORD, DWORD);
+
+ GETARGPTR(pFrame, sizeof(PMOUSEEVENT16), parg16);
+
+ //
+ // mouse_event is declared void, but we'll return the same value as
+ // user32.
+ //
+
+ ul = ((PFMOUSE_EVENT)(PVOID)mouse_event)(
+ parg16->wFlags,
+ parg16->dx,
+ parg16->dy,
+ parg16->cButtons,
+ parg16->dwExtraInfo
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//
+// WU32KeybdEvent: Thunk for 16-bit register-based API keybd_event,
+// with the help of user16 function keybd_event (in
+// winmisc2.asm).
+//
+
+ULONG FASTCALL WU32KeybdEvent(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PKEYBDEVENT16 parg16;
+ typedef ULONG (WINAPI *PFKEYBD_EVENT)(BYTE, BYTE, DWORD, DWORD);
+
+ GETARGPTR(pFrame, sizeof(PKEYBDEVENT16), parg16);
+
+ //
+ // keybd_event is declared void, but we'll return the same value as
+ // user32.
+ //
+
+ ul = ((PFKEYBD_EVENT)(PVOID)keybd_event)(
+ LOBYTE(parg16->bVirtualKey),
+ LOBYTE(parg16->bScanCode),
+ ((HIBYTE(parg16->bVirtualKey) == 0x80) ? KEYEVENTF_KEYUP : 0) |
+ ((HIBYTE(parg16->bScanCode) == 0x1) ? KEYEVENTF_EXTENDEDKEY : 0),
+ parg16->dwExtraInfo
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wuman.h b/private/mvdm/wow32/wuman.h
new file mode 100644
index 000000000..c75dd0c83
--- /dev/null
+++ b/private/mvdm/wow32/wuman.h
@@ -0,0 +1,21 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUMAN.H
+ * WOW32 16-bit User API support (manually-coded thunks)
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+typedef ULONG (*WBP) (LPSTR, int, int, int);
+
+ULONG FASTCALL WU32FinalUserInit(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ExitWindows(PVDMFRAME pFrame);
+ULONG FASTCALL WU32NotifyWow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32WordBreakProc(PVDMFRAME pFrame);
+ULONG FASTCALL WU32MouseEvent(PVDMFRAME pFrame);
+ULONG FASTCALL WU32KeybdEvent(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wumenu.c b/private/mvdm/wow32/wumenu.c
new file mode 100644
index 000000000..8ae3715d9
--- /dev/null
+++ b/private/mvdm/wow32/wumenu.c
@@ -0,0 +1,1613 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUMENU.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wumenu.c);
+
+
+/*++
+ BOOL AppendMenu(<hMenu>, <wFlags>, <wIDNewItem>, <lpNewItem>)
+ HMENU <hMenu>;
+ WORD <wFlags>;
+ WORD <wIDNewItem>;
+ LPSTR <lpNewItem>;
+
+ The %AppendMenu% function appends a new item to the end of a menu. The
+ application can specify the state of the menu item by setting values in the
+ <wFlags> parameter.
+
+ <hMenu>
+ Identifies the menu to be changed.
+
+ <wFlags>
+ Specifies information about the state of the new menu item when
+ it is added to the menu. It consists of one or more values listed in the
+ following Comments section.
+
+ <wIDNewItem>
+ Specifies either the command ID of the new menu item or, if
+ <wFlags> is set to MF_POPUP, the menu handle of the pop-up menu.
+
+ <lpNewItem>
+ Specifies the content of the new menu item. The interpretation
+ of the <lpNewItem> parameter depends upon the setting of the <wFlags>
+ parameter.
+
+ MF_STRING
+ Contains a long pointer to a null-terminated string.
+
+ MF_BITMAP
+ Contains a bitmap handle in its low-order word.
+
+ MF_OWNERDRAW
+ Contains an application-supplied 32-bit value which the application can
+ use to maintain additional data associated with the menu item. This
+ 32-bit value is available to the application in the %itemData% member of
+ the structure pointed to by the <lParam> parameter of the WM_MEASUREITEM
+ and WM_DRAWITEM messages sent when the menu item is initially displayed
+ or is changed.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function is successful. Otherwise, it is FALSE.
+
+ Whenever a menu changes (whether or not the menu resides in a window that is
+ displayed), the application should call %DrawMenuBar%.
+
+ Each of the following groups list flags that are mutually exclusive and
+ cannot be used together:
+
+ o MF_BYCOMMAND and MF_BYPOSITION
+
+ o MF_DISABLED, MF_ENABLED, and MF_GRAYED
+
+ o MF_BITMAP, MF_STRING, and MF_OWNERDRAW
+
+ o MF_MENUBARBREAK and MF_MENUBREAK
+
+ o MF_CHECKED and MF_UNCHECKED
+
+ .cmt
+ 16-Sep-1990 [ralphw]
+
+ Some of the above flags aren't documented as valid values for the wFlags
+ parameter. If they are valid, they should be documented, otherwise, they
+ should be removed from the list.
+ .endcmt
+
+ The following list describes the flags which may be set in the <wFlags>
+ parameter:
+
+ MF_BITMAP
+ Uses a bitmap as the item. The low-order word of the lpNewItem parameter
+ contains the handle of the bitmap.
+
+ MF_CHECKED
+ Places a checkmark next to the item. If the application has supplied
+ checkmark bitmaps (see %SetMenuItemBitmaps%), setting this flag displays
+ the checkmark on bitmap next to the menu item.
+
+ MF_DISABLED
+ Disables the menu item so that it cannot be selected, but does not gray
+ it.
+
+ MF_ENABLED
+ Enables the menu item so that it can be selected and restores it from
+ its grayed state.
+
+ MF_GRAYED
+ Disables the menu item so that it cannot be selected and grays it.
+
+ MF_MENUBARBREAK
+ Same as MF_MENUBREAK except that for pop-up menus, separates the new
+ column from the old column with a vertical line.
+
+ MF_MENUBREAK
+ Places the item on a new line for static menu-bar items. For pop-up
+ menus, places the item in a new column, with no dividing line between
+ the columns.
+
+ MF_OWNERDRAW
+ Specifies that the item is an owner-draw item. The window that owns the
+ menu receives a WM_MEASUREITEM message when the menu is displayed for
+ the first time to retrieve the height and width of the menu item. The
+ WM_DRAWITEM message is then sent whenever the owner must update the
+ visual appearance of the menu item. This option is not valid for a
+ top-level menu item.
+
+ MF_POPUP
+ Specifies that the menu item has a pop-up menu associated with it. The
+ <wIDNewItem> parameter specifies a handle to a pop-up menu to be
+ associated with the item. This is used for adding either a top-level
+ pop-up menu or adding a hierarchical pop-up menu to a pop-up menu item.
+
+ MF_SEPARATOR
+ Draws a horizontal dividing line. Can only be used in a pop-up menu.
+ This line cannot be grayed, disabled, or highlighted. The <lpNewItem>
+ and <wIDNewItem> parameters are ignored.
+
+ MF_STRING
+ Specifies that the menu item is a character string; the <lpNewItem>
+ parameter points to the string for the menu item.
+
+ MF_UNCHECKED
+ Does not place a checkmark next to the item (default). If the
+ application has supplied checkmark bitmaps (see %SetMenuItemBitmaps%),
+ setting this flag displays the checkmark off bitmap next to the menu
+ item.
+--*/
+
+ULONG FASTCALL WU32AppendMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz4;
+ register PAPPENDMENU16 parg16;
+ UINT wIDNewItem;
+
+ GETARGPTR(pFrame, sizeof(APPENDMENU16), parg16);
+
+ // USER has some internal bitmap identifiers for menu item bitmaps so
+ // it doesn't have to store multiple copies of these bitmaps when they
+ // appear in multiple menus. WinProj does its own MDI and uses these
+ // bitmaps.
+
+ // #define MENUHBM_CHILDCLOSE (UINT)1
+ // #define MENUHBM_RESTORE (UINT)2
+ // #define MENUHBM_MINIMIZE (UINT)3
+ // #define MENUHBM_MAX (UINT)4
+
+ if (parg16->f2 & MF_BITMAP) {
+ if (LOW(parg16->f4) >= 4)
+ psz4 = (PSZ)HBITMAP32(LOW(parg16->f4));
+ else
+ psz4 = (PSZ)WORD32(parg16->f4);
+ }
+ else if (parg16->f2 & MF_OWNERDRAW)
+ psz4 = (PSZ)DWORD32(parg16->f4);
+ else
+ GETPSZPTR(parg16->f4, psz4);
+
+ wIDNewItem = (UINT) WORD32(parg16->f3);
+
+ if (parg16->f2 & MF_POPUP)
+ wIDNewItem = (UINT) HMENU32(parg16->f3);
+
+
+ ul = GETBOOL16(AppendMenu(HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ wIDNewItem,
+ psz4));
+
+ FREEPSZPTR(psz4);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/*++
+ BOOL ChangeMenu(<hMenu>,<wIDChangeItem>,<lpNewItem>,<wIDNewItem>,<wFlags>)
+ HMENU <hMenu>;
+ WORD <wIDChangeItem>;
+ LPSTR <lpNewItem>;
+ WORD <wIDNewItem>;
+ WORD <wFlags>;
+
+ The %ChangeMenu% function appends, inserts, deletes, or modifies a menu
+ item in the menu given by the <hMenu> parameter. The <wIDChangeItem>,
+ <lpNewItem>, <wIDNewItem> and <wFlags> parameters define which item to
+ change and how to change it.
+
+ <hMenu>
+ Identifies the menu to be changed.
+
+ <wIDChangeItem>
+ Specifies the item to be changed. If MF_BYPOSITION is specified,
+ <wIDChangeItem> gives the position of the menu item to be
+ changed (the first item is at position zero). If MF_BYCOMMAND is
+ specified instead, <wIDChangeItem> specifies the menu-item ID.
+ The menu-item ID can specify any popup-menu item (that is, an item
+ in a popup menu associated with an item of <hMenu>). If neither
+ flag is given, the default is MF_BYCOMMAND. When MF_INSERT is used,
+ <wIDChangeItem> identifies the item before which the new item is to
+ be inserted. When MF_APPEND is used, <wIDChangeItem> is NULL.
+
+ <lpNewItem>
+ Specifies the content of the new menu item. The interpretation
+ of the <lpNewItem> parameter depends upon the setting of the <wFlags>
+ parameter. The <lpNewItem> parameter is never a handle to a menu.
+ The MF_POPUP flag applies to the <wIDNewItem> parameter only.
+
+ MF_BITMAP
+ <lpNewItem> contains a bitmap handle in its low-order word.
+
+ MF_STRING
+ <lpNewItem> contains a long pointer to a null-terminated string.
+
+ The default is MF_STRING. A NULL value for <lpNewItem> creates a
+ horizontal break (the same effect as using the MF_SEPARATOR flag).
+
+ Note that MF_OWNERDRAW is not allowed on ChangeMenu; it conflicts with
+ the ChangeMenu command bit MF_APPEND.
+
+ <wIDNewItem>
+ Specifies either the command ID of the new menu item or, if
+ <wFlags> is set to MF_POPUP, the menu handle of the pop-up menu.
+ It is never a menu-item position.
+
+ <wFlags>
+ Specifies information about the state of the new menu item when it
+ is added to the menu. It consists of one or more values listed in
+ the following Comments section.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function is successful. Otherwise, it is FALSE.
+
+ Whenever a menu changes (whether or not the menu resides in a window that is
+ displayed), the application should call %DrawMenuBar%.
+
+ Each of the following groups list flags that are mutually exclusive and
+ cannot be used together:
+
+ o MF_APPEND, MF_CHANGE, MF_DELETE, MF_INSERT and MF_REMOVE
+
+ o MF_BYCOMMAND and MF_BYPOSITION
+
+ o MF_DISABLED, MF_ENABLED, and MF_GRAYED
+
+ o MF_BITMAP, MF_POPUP and MF_STRING
+
+ o MF_MENUBARBREAK and MF_MENUBREAK
+
+ o MF_CHECKED and MF_UNCHECKED
+
+ .cmt
+ 16-Sep-1990 [ralphw]
+
+ Some of the above flags aren't documented as valid values for the wFlags
+ parameter. If they are valid, they should be documented, otherwise, they
+ should be removed from the list.
+ .endcmt
+
+ The following list describes the flags which may be set in the <wFlags>
+ parameter:
+
+ MF_APPEND
+ Appends the new item to the end of the menu.
+
+ MF_BITMAP
+ Uses a bitmap as the item. The low-order word of the lpNewItem parameter
+ contains the handle of the bitmap.
+
+ MF_BYCOMMAND
+ Specifies that the <wIDChangeItem> parameter gives the menu-item ID
+ number (default).
+
+ MF_BYPOSITION
+ Specifies that the <wIDChangeItem> parameter gives the position of
+ the menu item to be changed.
+
+ MF_CHANGE
+ Changes or replaces the specified item.
+
+ MF_CHECKED
+ Places a checkmark next to the item. If the application has supplied
+ checkmark bitmaps (see %SetMenuItemBitmaps%), setting this flag displays
+ the checkmark on bitmap next to the menu item.
+
+ MF_DELETE
+ Deletes the item.
+
+ MF_DISABLED
+ Disables the menu item so that it cannot be selected, but does not gray
+ it.
+
+ MF_ENABLED
+ Enables the menu item so that it can be selected and restores it from
+ its grayed state.
+
+ MF_GRAYED
+ Disables the menu item so that it cannot be selected and grays it.
+
+ MF_INSERT
+ Inserts a new item, just before the specified item.
+
+ MF_MENUBARBREAK
+ Same as MF_MENUBREAK except that for pop-up menus, separates the new
+ column from the old column with a vertical line.
+
+ MF_MENUBREAK
+ Places the item on a new line for static menu-bar items. For pop-up
+ menus, places the item in a new column, with no dividing line between
+ the columns.
+
+ MF_POPUP
+ Specifies that the menu item has a pop-up menu associated with it. The
+ <wIDNewItem> parameter specifies a handle to a pop-up menu to be
+ associated with the item. This is used for adding either a top-level
+ pop-up menu or adding a hierarchical pop-up menu to a pop-up menu item.
+
+ MF_REMOVE
+ Removes the item but does not delete it.
+
+ MF_SEPARATOR
+ Draws a horizontal dividing line. Can only be used in a pop-up menu.
+ This line cannot be grayed, disabled, or highlighted. The <lpNewItem>
+ and <wIDNewItem> parameters are ignored.
+
+ MF_STRING
+ Specifies that the menu item is a character string; the <lpNewItem>
+ parameter points to the string for the menu item.
+
+ MF_UNCHECKED
+ Does not place a checkmark next to the item (default). If the
+ application has supplied checkmark bitmaps (see %SetMenuItemBitmaps%),
+ setting this flag displays the checkmark off bitmap next to the menu
+ item.
+--*/
+
+ULONG FASTCALL WU32ChangeMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz3;
+ DWORD dw4;
+
+ register PCHANGEMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CHANGEMENU16), parg16);
+
+ if (parg16->f5 & MF_BITMAP) {
+ if (LOW(parg16->f3) >= 4)
+ psz3 = (PSZ)HBITMAP32(LOW(parg16->f3));
+ else
+ psz3 = (PSZ)WORD32(parg16->f3);
+ }
+ else
+ GETPSZPTR(parg16->f3, psz3);
+
+ dw4 = WORD32(parg16->f4);
+ if (WORD32(parg16->f5) & MF_POPUP)
+ dw4 = (DWORD)HMENU32(parg16->f4);
+
+ ul = GETBOOL16(ChangeMenu(
+ HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ psz3,
+ dw4,
+ WORD32(parg16->f5)
+ ));
+
+ FREEPSZPTR(psz3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL CheckMenuItem(<hMenu>, <wIDCheckItem>, <wCheck>)
+ HMENU <hMenu>;
+ WORD <wIDCheckItem>;
+ WORD <wCheck>;
+
+ The %CheckMenuItem% function places checkmarks next to or removes checkmarks
+ from menu items in the pop-up menu specified by the <hMenu> parameter. The
+ <wIDCheckItem> parameter specifies the item to be modified.
+
+ <hMenu>
+ Identifies the menu.
+
+ <wIDCheckItem>
+ Specifies the menu item to be checked.
+
+ <wCheck>
+ Specifies how to check the menu item and how to determine the item's
+ position in the menu. The <wCheck> parameter can be a combination of the
+ MF_CHECKED or MF_UNCHECKED with MF_BYPOSITION or MF_BYCOMMAND flags.
+ These flags can be combined by using the bitwise OR operator. They have
+ the following meanings:
+
+ MF_BYCOMMAND
+ Specifies that the <wIDCheckItem> parameter gives the menu-item ID
+ (MF_BYCOMMAND is the default).
+
+ MF_BYPOSITION
+ Specifies that the <wIDCheckItem > parameter gives the position of the
+ menu item (the first item is at position zero).
+
+ MF_CHECKED
+ Adds checkmark.
+
+ MF_UNCHECKED
+ Removes checkmark.
+
+ The return value specifies the previous state of the item. It is either
+ MF_CHECKED or MF_UNCHECKED. The return value is -1 if the menu item does not
+ exist.
+
+ The <wIDCheckItem> parameter may identify a pop-up menu item as well as a
+ menu item. No special steps are required to check a pop-up menu item.
+
+ Top-level menu items cannot be checked.
+
+ A pop-up menu item should be checked by position since it does not have a
+ menu-item identifier associated with it.
+--*/
+
+ULONG FASTCALL WU32CheckMenuItem(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCHECKMENUITEM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CHECKMENUITEM16), parg16);
+
+ ul = GETBOOL16(CheckMenuItem(
+ HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HMENU CreateMenu(VOID)
+
+ The %CreateMenu% function creates a menu. The menu is initially empty, but
+ can be filled with menu items by using the %AppendMenu% or %InsertMenu%
+ function.
+
+ This function has no parameters.
+
+ The return value identifies the newly created menu. It is NULL if the menu
+ cannot be created.
+--*/
+
+ULONG FASTCALL WU32CreateMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETHMENU16(CreateMenu());
+
+ RETURN(ul);
+}
+
+
+/*++
+ HMENU CreatePopupMenu(VOID)
+
+ The %CreatePopupMenu% function creates and returns a handle to an empty
+ pop-up menu.
+
+ An application adds items to the pop-up menu by calling %InsertMenu% and
+ %AppendMenu%. The application can add the pop-up menu to an existing menu or
+ pop-up menu, or it may display and track selections on the pop-up menu by
+ calling %TrackPopupMenu%.
+
+ This function has no parameters.
+
+ The return value identifies the newly created menu. It is NULL if the menu
+ cannot be created.
+--*/
+
+ULONG FASTCALL WU32CreatePopupMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETHMENU16(CreatePopupMenu());
+
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL DeleteMenu(<hMenu>, <nPosition>, <wFlags>)
+ HMENU <hMenu>;
+ WORD <nPosition>;
+ WORD <wFlags>;
+
+ The %DeleteMenu% function deletes an item from the menu identified by the
+ <hMenu> parameter; if the menu item has an associated pop-up menu,
+ %DeleteMenu% destroys the handle by the pop-up menu and frees the memory
+ used by the pop-up menu.
+
+ <hMenu>
+ Identifies the menu to be changed.
+
+ <nPosition>
+ Specifies the menu item which is to be deleted, as determined by the
+ <wFlags> parameter:
+
+ MF_BYPOSITION
+ Specifies the position of the menu item; the first item in the menu is
+ at position 0.
+
+ MF_BYCOMMAND
+ Specifies the command ID of the existing menu item.
+
+ <wFlags>
+ Specifies how the <nPosition> parameter is interpreted. It may be
+ set to either MF_BYCOMMAND or MF_BYPOSITION.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function is successful. Otherwise, it is FALSE.
+
+ Whenever a menu changes (whether or not the menu resides in a window that is
+ displayed), the application should call %DrawMenuBar%.
+--*/
+
+ULONG FASTCALL WU32DeleteMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDELETEMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DELETEMENU16), parg16);
+
+ ul = GETBOOL16(DeleteMenu(
+ HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL DestroyMenu(<hMenu>)
+ HMENU <hMenu>;
+
+ The %DestroyMenu% function destroys the menu specified by the <hMenu>
+ parameter and frees any memory that the menu occupied.
+
+ <hMenu>
+ Identifies the menu to be destroyed.
+
+ The return value specifies whether or not the specified menu is destroyed.
+ It is TRUE if the menu is destroyed. Otherwise, it is FALSE.
+--*/
+
+ULONG FASTCALL WU32DestroyMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDESTROYMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DESTROYMENU16), parg16);
+
+ ul = GETBOOL16(DestroyMenu(HMENU32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void DrawMenuBar(<hwnd>)
+ HWND <hwnd>;
+
+ The %DrawMenuBar% function redraws the menu bar. If a menu bar is changed
+ <after> Windows has created the window, this function should be called to
+ draw the changed menu bar.
+
+ <hwnd>
+ Identifies the window whose menu needs redrawing.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32DrawMenuBar(PVDMFRAME pFrame)
+{
+ register PDRAWMENUBAR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DRAWMENUBAR16), parg16);
+
+ DrawMenuBar(HWND32(parg16->f1));
+
+ FREEARGPTR(parg16);
+ RETURN(TRUE);
+}
+
+
+/*++
+ DWORD GetMenuCheckMarkDimensions(VOID)
+
+ The %GetMenuCheckMarkDimensions% function returns the dimensions of the
+ default checkmark bitmap. Windows displays this bitmap next to checked menu
+ items. Before calling the %SetMenuItemBitmaps% function to replace the
+ default checkmark, an application should call the
+ %GetMenuCheckMarkDimensions% function to determine the correct size for the
+ bitmaps.
+
+ This function has no parameters.
+
+ The return value specifies the height and width of the default checkmark
+ bitmap. The high-order word contains the height in pixels and the low-order
+ word contains the width.
+--*/
+
+ULONG FASTCALL WU32GetMenuCheckMarkDimensions(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETLONG16(GetMenuCheckMarkDimensions());
+
+ RETURN(ul);
+}
+
+
+/*++
+ int GetMenuString(<hMenu>, <wIDItem>, <lpString>, <nMaxCount>, <wFlag>)
+ HMENU <hMenu>;
+ WORD <wIDItem>;
+ LPSTR <lpString>;
+ int <nMaxCount>;
+ WORD <wFlag>;
+
+ The %GetMenuString% function copies the label of the specified menu item
+ into the <lpString> parameter.
+
+ <hMenu>
+ Identifies the menu.
+
+ <wIDItem>
+ Specifies the integer identifier of the menu item (from the
+ resource file) or the offset of the menu item in the menu, depending on
+ the value of the <wFlag> parameter.
+
+ <lpString>
+ Points to the buffer that is to receive the label.
+
+ <nMaxCount>
+ Specifies the maximum length of the label to be copied. If the
+ label is longer than the maximum specified in <nMaxCount>, the extra
+ characters are truncated.
+
+ <wFlag>
+ Specifies the nature of the <wID> parameter. If <wFlags> contains
+ MF_BYPOSITION, <wId> specifies a (zero-based) relative position; if the
+ <wFlags> parameter contains MF_BYCOMMAND, <wId> specifies the item ID.
+
+ The return value specifies the actual number of bytes copied to the buffer.
+
+ The <nMaxCount> parameter should be one larger than the number of characters
+ in the label to accommodate the null character that terminates a string.
+--*/
+
+#define GMS32_LIMIT 2000
+ULONG FASTCALL WU32GetMenuString(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz3;
+ register PGETMENUSTRING16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETMENUSTRING16), parg16);
+ ALLOCVDMPTR(parg16->f3, parg16->f4, psz3);
+
+ // limit nMaxCount to a reasonable amount so it does not fail in client
+ // server. Some wow apps passed in -1.
+ ul = GETINT16(GetMenuString(
+ HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ psz3,
+ (WORD32(parg16->f4) > GMS32_LIMIT) ? GMS32_LIMIT : WORD32(parg16->f4),
+ WORD32(parg16->f5)
+ ));
+
+ FLUSHVDMPTR(parg16->f3, strlen(psz3)+1, psz3);
+ FREEVDMPTR(psz3);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HMENU GetSystemMenu(<hwnd>, <bRevert>)
+ HWND <hwnd>;
+ BOOL <bRevert>;
+
+ The %GetSystemMenu% function allows the application to access the System
+ menu for copying and modification.
+
+ <hwnd>
+ Identifies the window that will own a copy of the System menu.
+
+ <bRevert>
+ Specifies the action to be taken.
+
+ If <bRevert> is FALSE, the %GetSystemMenu% returns a handle to a copy of
+ the System menu currently in use. This copy is initially identical to
+ the System menu, but can be modified.
+
+ If <bRevert> is TRUE, the %GetSystemMenu% function destroys the possibly
+ modified copy of the System menu (if there is one) that belongs to the
+ specified window and returns a handle to the original, unmodified
+ version of the System menu.
+
+ The return value identifies the System menu if <bRevert> is TRUE and the
+ System menu has been modified. If <bRevert> is TRUE and the System menu
+ has <not> been modified, the return value is NULL. If <bRevert> is FALSE, the
+ return value identifies a copy of the System menu.
+
+ Any window that does not use the %GetSystemMenu% function to make its own
+ copy of the System menu receives the standard System menu.
+
+ The handle returned by the %GetSystemMenu% function can be used with the
+ %AppendMenu%, %InsertMenu% or %ModifyMenu% functions to change the System
+ menu. The System menu initially contains items identified with various ID
+ values such as SC_CLOSE, SC_MOVE, and SC_SIZE. Menu items on the System menu
+ send WM_SYSCOMMAND messages. All predefined System-menu items have ID
+ numbers greater than 0xF000. If an application adds commands to the System
+ menu, it should use ID numbers less than F000.
+
+ Windows automatically grays items on the standard System menu, depending on
+ the situation. The application can carry out its own checking or graying by
+ responding to the WM_INITMENU message, which is sent before any menu is
+ displayed.
+--*/
+
+ULONG FASTCALL WU32GetSystemMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETSYSTEMMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETSYSTEMMENU16), parg16);
+
+ ul = GETHMENU16(GetSystemMenu(HWND32(parg16->f1),
+ BOOL32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL HiliteMenuItem(<hwnd>, <hMenu>, <wIDHiliteItem>, <wHilite>)
+ HWND <hwnd>;
+ HMENU <hMenu>;
+ WORD <wIDHiliteItem>;
+ WORD <wHilite>;
+
+ The %HiliteMenuItem% function highlights or removes the highlighting from a
+ top-level (menu-bar) menu item.
+
+ <hwnd>
+ Identifies the window that contains the menu.
+
+ <hMenu>
+ Identifies the top-level menu that contains the item to be
+ highlighted.
+
+ <wIDHiliteItem>
+ Specifies the integer identifier of the menu item or the offset
+ of the menu item in the menu, depending on the value of the <wHilite>
+ parameter.
+
+ <wHilite>
+ Specifies whether the menu item is highlighted or the highlight
+ is removed. It can be a combination of MF_HILITE or MF_UNHILITE with
+ MF_BYCOMMAND or MF_BYPOSITION. The values can be combined using the
+ bitwise OR operator. These values have the following meanings:
+
+ MF_BYCOMMAND
+ Interprets wIDHiliteItem as the menu-item ID (the default
+ interpretation).
+
+ MF_BYPOSITION
+ Interprets <wIDHiliteItem> as an offset.
+
+ MF_HILITE
+ Highlights the item. If this value is not given, highlighting is removed
+ from the item.
+
+ MF_UNHILITE
+ Removes highlighting from the item.
+
+ The return value specifies whether or not the menu item is highlighted the
+ outcome of the function. It is TRUE if the item is highlighted was set to
+ the specified highlight state. Otherwise, it is FALSE.
+
+ The MF_HILITE and MF_UNHILITE flags can be used only with the
+ %HiliteMenuItem% function; they cannot be used with the %ModifyMenu%
+ function.
+--*/
+
+ULONG FASTCALL WU32HiliteMenuItem(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PHILITEMENUITEM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(HILITEMENUITEM16), parg16);
+
+ ul = GETBOOL16(HiliteMenuItem(
+ HWND32(parg16->f1),
+ HMENU32(parg16->f2),
+ WORD32(parg16->f3),
+ WORD32(parg16->f4)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL InsertMenu(<hMenu>, <nPosition>, <wFlags>, <wIDNewItem>, <lpNewItem>)
+ HMENU <hMenu>;
+ WORD <nPosition>;
+ WORD <wFlags>;
+ WORD <wIDNewItem>;
+ LPSTR <lpNewItem>;
+
+ The %InsertMenu% function inserts a new menu item at the position specified
+ by the <nPosition> parameter, moving other items down the menu. The
+ application can specify the state of the menu item by setting values in the
+ <wFlags> parameter.
+
+ <hMenu>
+ Identifies the menu to be changed.
+
+ <nPosition>
+ Specifies the menu item before which the new menu item is to be
+ inserted. The interpretation of the <nPosition> parameter depends upon
+ the setting of the <wFlags> parameter.
+
+ MF_BYPOSITION
+ Specifies the position of the existing menu item. The first item in the
+ menu is at position zero.
+
+ If nPosition is -1, the new menu item is appended to the end of the
+ menu.
+
+ MF_BYCOMMAND
+ Specifies the command ID of the existing menu item.
+
+ <wFlags>
+ Specifies how the <nPosition> parameter is interpreted and
+ information about the state of the new menu item when it is added to the
+ menu. It consists of one or more values listed in the following Comments
+ section.
+
+ <wIDNewItem>
+ Specifies either the command ID of the new menu item or, if
+ <wFlags> is set to MF_POPUP, the menu handle of the pop-up menu.
+
+ <lpNewItem>
+ Specifies the content of the new menu item. If <wFlags> is set
+ to MF_STRING (the default), then <lpNewItem> is a long pointer to a
+ null-terminated string. If <wFlags> is set to MF_BITMAP instead, then
+ <lpNewItem> contains a bitmap handle (%HBITMAP%) in its low-order word.
+ If <wFlags> is set to MF_OWNERDRAW, <lpNewItem> specifies an
+ application-supplied 32-bit value which the application can use to
+ maintain additional data associated with the menu item. This 32-bit
+ value is available to the application in the %itemData% member of the
+ structure pointed to by the <lParam> parameter of the following
+ messages:
+
+ WM_MEASUREITEM
+ WM_DRAWITEM
+
+ These messages are sent when the menu item is initially displayed, or is
+ changed.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function is successful. Otherwise, it is FALSE.
+
+ Whenever a menu changes (whether or not the menu resides in a window that is
+ displayed), the application should call %DrawMenuBar%.
+
+ Each of the following groups lists flags that should not be used together:
+
+ o MF_BYCOMMAND and MF_BYPOSITION
+
+ o MF_DISABLED, MF_ENABLED, and MF_GRAYED
+
+ o MF_BITMAP, MF_STRING, MF_OWNERDRAW, and MF_SEPARATOR
+
+ o MF_MENUBARBREAK and MF_MENUBREAK
+
+ o MF_CHECKED and MF_UNCHECKED
+
+ The following list describes the flags which may be set in the <wFlags>
+ parameter:
+
+ MF_BITMAP
+ Uses a bitmap as the item. The low-order word of the lpNewItem parameter
+ contains the handle of the bitmap. MF_BYCOMMAND Specifies that the
+ <nPosition> parameter gives the menu-item control ID number (default).
+
+ MF_BYPOSITION
+ Specifies that the <nPosition> parameter gives the position of the menu
+ item to be changed rather than an ID number.
+
+ MF_CHECKED
+ Places a checkmark next to the menu item. If the application has
+ supplied checkmark bitmaps (see the %SetMenuItemBitmaps% function),
+ setting this flag displays the checkmark on bitmap next to the menu
+ item.
+
+ MF_DISABLED
+ Disables the menu item so that it cannot be selected, but does not gray
+ it.
+
+ MF_ENABLED
+ Enables the menu item so that it can be selected and restores it from
+ its grayed state.
+
+ MF_GRAYED
+ Disables the menu item so that it cannot be selected and grays it.
+
+ MF_MENUBARBREAK
+ Same as MF_MENUBREAK except that for pop-up menus, separates the new
+ column from the old column with a vertical line.
+
+ MF_MENUBREAK
+ Places the menu item on a new line for static menu-bar items. For pop-up
+ menus, places the menu item in a new column, with no dividing line
+ between the columns.
+
+ MF_OWNERDRAW
+ Specifies that the item is an owner-draw item. The window that owns the
+ menu receives a WM_MEASUREITEM message when the menu is displayed for
+ the first time to retrieve the height and width of the menu item. The
+ WM_DRAWITEM message is then sent to the owner whenever the owner must
+ update the visual appearance of the menu item. This option is not valid
+ for a top-level menu item.
+
+ MF_POPUP
+ Specifies that the menu item has a pop-up menu associated with it. The
+ <wIDNewItem> parameter specifies a handle to a pop-up menu to be
+ associated with the item. Use the MF_OWNERDRAW flag to add either a
+ top-level pop-up menu or a hierarchical pop-up menu to a pop-up menu
+ item.
+
+ MF_SEPARATOR
+ Draws a horizontal dividing line. You can use this flag in a pop-up
+ menu. This line cannot be grayed, disabled, or highlighted. Windows
+ ignores the <lpNewItem> and <wIDNewItem> parameters.
+
+ MF_STRING
+ Specifies that the menu item is a character string; the <lpNewItem>
+ parameter points to the string for the item.
+
+ MF_UNCHECKED
+ Does not place a checkmark next to the item (default). If the
+ application has supplied checkmark bitmaps (see %SetMenuItemBitmaps%),
+ setting this flag displays the "checkmark off" bitmap next to the menu
+ item.
+--*/
+
+ULONG FASTCALL WU32InsertMenu(PVDMFRAME pFrame)
+{
+ BOOL fNeedToFreePsz5 = FALSE;
+ ULONG ul;
+ PSZ psz5;
+ UINT w4;
+ register PINSERTMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(INSERTMENU16), parg16);
+
+ if (parg16->f3 & MF_BITMAP) {
+ if (LOW(parg16->f5) >= 4)
+ psz5 = (PSZ)HBITMAP32(LOW(parg16->f5));
+ else
+ psz5 = (PSZ)WORD32(parg16->f5);
+ }
+ else if (parg16->f3 & MF_OWNERDRAW) {
+ psz5 = (PSZ)DWORD32(parg16->f5);
+ }
+ else if (parg16->f3 & MF_SEPARATOR) {
+ // lpszNewItem is ignored when inserting a separator bar.
+ psz5 = NULL;
+ }
+ else {
+ GETPSZPTR(parg16->f5, psz5);
+ fNeedToFreePsz5 = TRUE;
+ }
+
+ w4 = (parg16->f3 & MF_POPUP) ? (UINT)HMENU32(parg16->f4) : WORD32(parg16->f4);
+
+ ul = GETBOOL16(InsertMenu(
+ HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ w4,
+ psz5
+ ));
+
+ if (fNeedToFreePsz5) {
+ FREEPSZPTR(psz5);
+ }
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HMENU LoadMenu(<hInstance>, <lpMenuName>)
+ HANDLE <hInstance>;
+ LPSTR <lpMenuName>;
+
+ This function loads the menu resource named by the <lpMenuName> parameter
+ from the executable file associated with the module specified by the
+ <hInstance> parameter.
+
+ <hInstance>
+ Identifies an instance of the module whose executable file contains the
+ menu.
+
+ <lpMenuName>
+ Points to a character string that names the menu resource. The
+ string must be a null-terminated string.
+
+ The return value identifies a menu resource if the function is successful.
+ Otherwise, it is NULL.
+
+ The <lpMenuName> parameter can contain a value created by the
+ %MAKEINTRESOURCE% macro. If it does, the ID must reside in the low-order
+ word of <lpMenuName>, and the high-order word must be set to zero.
+--*/
+
+ULONG FASTCALL WU32LoadMenu(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ PSZ psz2;
+ register PLOADMENU16 parg16;
+ DWORD cb;
+ LPBYTE lpResData;
+
+ LPWSTR lpUniName_Menu;
+
+ GETARGPTR(pFrame, sizeof(LOADMENU16), parg16);
+ psz2 = (PSZ)DWORD32(parg16->f2);
+ GETPSZIDPTR(parg16->f2, psz2);
+
+ if (HIWORD(psz2) != (WORD) NULL) {
+ if (!(MBToWCS(psz2, -1, &lpUniName_Menu, -1, TRUE))) {
+ FREEPSZIDPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+ }
+ }
+ else {
+ lpUniName_Menu = (LPWSTR) psz2;
+ }
+
+ cb = parg16->f4 * sizeof(WCHAR); // see SizeofResource16
+ if (cb && (lpResData = malloc_w(cb))) {
+ ConvertMenu16(parg16->f5, lpResData, parg16->f3, cb, parg16->f4);
+
+ ul = GETHMENU16((pfnOut.pfnServerLoadCreateMenu)(HMODINST32(parg16->f1),
+ (LPTSTR) lpUniName_Menu,
+ lpResData,
+ cb,
+ FALSE));
+
+
+
+ free_w (lpResData);
+ }
+
+ if (HIWORD(psz2) != (WORD) NULL) {
+ LocalFree (lpUniName_Menu);
+ }
+
+ FREEPSZIDPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HMENU LoadMenuIndirect(<lpMenuTemplate>)
+ LPSTR <lpMenuTemplate>;
+
+ The %LoadMenuIndirect% function loads into memory the menu named by the
+ <lpMenuTemplate> parameter. The template specified by <lpMenuTemplate> is a
+ header followed by a collection of one or more %MENUITEMTEMPLATE%
+ structures, each of which may contain one or more menu items and pop-up
+ menus.
+
+ <lpMenuTemplate>
+ Points to a menu template (which is a collection of one or more
+ %MENUITEMTEMPLATE% structures).
+
+ The return value identifies the menu if the function is successful.
+ Otherwise, it is NULL.
+--*/
+
+ULONG FASTCALL WU32LoadMenuIndirect(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ DWORD cb = 0;
+ PVOID pMenu32;
+ PLOADMENUINDIRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOADMENUINDIRECT16), parg16);
+ /*
+ * we need to convert this randomly created 16-bit resource into a
+ * 32-bit resource so that NT user will be able to use it.
+ */
+ if ((cb = (DWORD)ConvertMenu16((WORD)0x300, NULL, (VPBYTE)parg16->f1, cb, 0)) != 0) {
+ pMenu32 = malloc_w(cb);
+ if (pMenu32 != NULL) {
+ ConvertMenu16((WORD)0x300, pMenu32, (VPBYTE)parg16->f1, cb, 0);
+ ul = GETHMENU16(LoadMenuIndirect(pMenu32));
+ free_w(pMenu32);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL ModifyMenu(<hMenu>, <nPosition>, <wFlags>, <wIDNewItem>, <lpNewItem>)
+ HMENU <hMenu>;
+ WORD <nPosition>;
+ WORD <wFlags>;
+ WORD <wIDNewItem>;
+ LPSTR <lpNewItem>;
+
+ The %ModifyMenu% function changes an existing menu item at the position
+ specified by the <nPosition> parameter. The application specifies the new
+ state of the menu item by setting values in the <wFlags> parameter. If this
+ function replaces a pop-up menu associated with the menu item, it destroys
+ the old pop-up menu and frees the memory used by the pop-up menu.
+
+ <hMenu>
+ Identifies the menu to be changed.
+
+ <nPosition>
+ Specifies the menu item to be changed. The interpretation of the
+ <nPosition> parameter depends upon the setting of the <wFlags>
+ parameter.
+
+ MF_BYPOSITION
+ Specifies the position of the existing menu item. The first item in the
+ menu is at position zero.
+
+ MF_BYCOMMAND
+ Specifies the command ID of the existing menu item.
+
+ <wFlags>
+ Specifies how the <nPosition> parameter is interpreted and
+ information about the changes to be made to the menu item. It consists
+ of one or more values listed in the following Comments section.
+
+ <wIDNewItem>
+ Specifies either the command ID of the modified menu item or, if
+ <wFlags> is set to MF_POPUP, the menu handle of the pop-up menu.
+
+ <lpNewItem>
+ Specifies the content of the changed menu item. If <wFlags> is
+ set to MF_STRING (the default), then <lpNewItem> is a long pointer to a
+ null-terminated string. If <wFlags> is set to MF_BITMAP instead, then
+ <lpNewItem> contains a bitmap handle (%HBITMAP%) in its low-order word.
+ If <wFlags> is set to MF_OWNERDRAW, <lpNewItem> specifies an
+ application-supplied 32-bit value which the application can use to
+ maintain additional data associated with the menu item. This 32-bit
+ value is available to the application in the %itemData% field of the
+ structure, pointed to by the <lParam> parameter of the following
+ messages:
+
+ WM_MEASUREITEM
+ WM_DRAWITEM
+
+ These messages are sent when the menu item is initially displayed, or is
+ changed.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function is successful. Otherwise, it is FALSE.
+
+ Whenever a menu changes (whether or not the menu resides in a window that is
+ displayed), the application should call %DrawMenuBar%. In order to change
+ the attributes of existing menu items, it is much faster to use the
+ %CheckMenuItem% and %EnableMenuItem% functions.
+
+ Each of the following groups lists flags that should not be used together:
+
+ o MF_BYCOMMAND and MF_BYPOSITION
+
+ o MF_DISABLED, MF_ENABLED, and MF_GRAYED
+
+ o MF_BITMAP, MF_STRING, MF_OWNERDRAW, and MF_SEPARATOR
+
+ o MF_MENUBARBREAK and MF_MENUBREAK
+
+ o MF_CHECKED and MF_UNCHECKED
+
+ The following list describes the flags which may be set in the <wFlags>
+ parameter:
+
+ MF_BITMAP
+ Uses a bitmap as the menu item. The low-order word of the lpNewItem
+ parameter contains the handle of the bitmap.
+
+ MF_BYCOMMAND
+ Specifies that the <nPosition> parameter gives the menu item control ID
+ number. This is the default if neither MF_BYCOMMAND nor MF_POSITION is
+ set.
+
+ MF_BYPOSITION
+ Specifies that the <nPosition> parameter gives the position of the menu
+ item to be changed rather than an ID number.
+
+ MF_CHECKED
+ Places a checkmark next to the menu item. If the application has
+ supplied checkmark bitmaps (see %SetMenuItemBitmaps%), setting this flag
+ displays the checkmark on bitmap next to the menu item.
+
+ MF_DISABLED
+ Disables the menu item so that it cannot be selected, but does not gray
+ it.
+
+ MF_ENABLED
+ Enables the menu item so that it can be selected and restores it from
+ its grayed state.
+
+ MF_GRAYED
+ Disables the menu item so that it cannot be selected and grays it.
+
+ MF_MENUBARBREAK
+ Same as MF_MENUBREAK except that for pop-up menus, separates the new
+ column from the old column with a vertical line.
+
+ MF_MENUBREAK
+ Places the menu item on a new line for static menu-bar items. For pop-up
+ menus, this flag places the item in a new column, with no dividing line
+ between the columns.
+
+ MF_OWNERDRAW
+ Specifies that the menu item is an owner-draw item. The window that owns
+ the menu receives a WM_MEASUREITEM message when the menu is displayed
+ for the first time to retrieve the height and width of the menu item.
+ The WM_DRAWITEM message is then sent whenever the owner must update the
+ visual appearance of the menu item. This option is not valid for a
+ top-level menu item.
+
+ MF_POPUP
+ Specifies that the item has a pop-up menu associated with it. The
+ <wIDNewItem> parameter specifies a handle to a pop-up menu to be
+ associated with the menu item. Use this flag for adding either a
+ top-level pop-up menu or adding a hierarchical pop-up menu to a pop-up
+ menu item.
+
+ MF_SEPARATOR
+ Draws a horizontal dividing line. You can only use this flag in a pop-up
+ menu. This line cannot be grayed, disabled, or highlighted. The
+ <lpNewItem> and <wIDNewItem> parameters are ignored.
+
+ MF_STRING
+ Specifies that the menu item is a character string; the <lpNewItem>
+ parameter points to the string for the menu item.
+
+ MF_UNCHECKED
+ Does not place a checkmark next to the menu item. No checkmark is the
+ default if neither MF_CHECKED nor MF_UNCHECKED is set. If the
+ application has supplied checkmark bitmaps (see %SetMenuItemBitmaps%),
+ setting this flag displays the checkmark off bitmap next to the menu
+ item.
+--*/
+
+ULONG FASTCALL WU32ModifyMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz5;
+ register PMODIFYMENU16 parg16;
+ UINT wIDNewItem;
+
+
+
+ GETARGPTR(pFrame, sizeof(MODIFYMENU16), parg16);
+
+ if (parg16->f3 & MF_BITMAP) {
+ if (LOW16(parg16->f5) >= 4)
+ psz5 = (PSZ)HBITMAP32(LOW(parg16->f5));
+ else
+ psz5 = (PSZ)WORD32(parg16->f5);
+ }
+ else if (parg16->f3 & MF_OWNERDRAW)
+ psz5 = (PSZ)DWORD32(parg16->f5);
+ else
+ GETPSZPTR(parg16->f5, psz5);
+
+ wIDNewItem = (UINT) WORD32(parg16->f4);
+
+ if (parg16->f3 & MF_POPUP)
+ wIDNewItem = (UINT) HMENU32(parg16->f4);
+
+
+
+ ul = GETBOOL16(ModifyMenu(
+ HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ wIDNewItem,
+ psz5
+ ));
+
+ if ( ul == FALSE && (parg16->f3 & MF_POPUP) ) {
+ //
+ // PowerPoint v4.0c passes an wIDNewItem which is not a menu handle
+ // when they do pass MF_POPUP. This hack allows it to avoid the
+ // error path in WINSRV. On Win 3.1, they never validated it so it
+ // got through. Luckily they quickly modify the menu to not have
+ // a popup menu soon after that.
+ //
+ if ( !IsMenu((HMENU) wIDNewItem) ) {
+ //
+ // Try again with a better sub-menu handle.
+ //
+ wIDNewItem = (UINT)GetSubMenu( HMENU32(parg16->f1),
+ WORD32(parg16->f2) );
+
+ ul = GETBOOL16(ModifyMenu( HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ wIDNewItem,
+ psz5 ));
+ }
+ }
+
+ FREEPSZPTR(psz5);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL RemoveMenu(<hMenu>, <nPosition>, <wFlags>)
+ HMENU <hMenu>;
+ WORD <nPosition>;
+ WORD <wFlags>;
+
+ The %RemoveMenu% function deletes an menu item with an associated pop-up
+ menu from the menu identified by the <hMenu> parameter but does not destroy
+ the handle for the pop-up menu, allowing the menu to be reused. Before
+ calling this function, the application should call %GetSubMenu% to retrieve
+ the pop-up menu handle.
+
+ <hMenu>
+ Identifies the menu to be changed.
+
+ <nPosition>
+ Specifies the menu item to be removed. The interpretation of the
+ <nPosition> parameter depends upon the setting of the <wFlags>
+ parameter.
+
+ MF_BYCOMMAND
+ Specifies the command ID of the existing menu item.
+
+ MF_BYPOSITION
+ Specifies the position of the menu item. The first item in the menu is
+ at position zero.
+
+ <wFlags>
+ Specifies how the <nPosition> parameter is interpreted. It must
+ be either MF_BYCOMMAND or MF_BYPOSITION.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function is successful. Otherwise, it is FALSE.
+
+ Whenever a menu changes (whether or not the menu resides in a window that is
+ displayed), the application should call %DrawMenuBar%.
+--*/
+
+ULONG FASTCALL WU32RemoveMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PREMOVEMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(REMOVEMENU16), parg16);
+
+ ul = GETBOOL16(RemoveMenu(
+ HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL SetMenu(<hwnd>, <hMenu>)
+ HWND <hwnd>;
+ HMENU <hMenu>;
+
+ The %SetMenu% function sets the given window's menu to the menu specified by
+ the <hMenu> parameter. If <hMenu> is NULL, the window's current menu is
+ removed. The %SetMenu% function causes the window to be redrawn to reflect
+ the menu change.
+
+ <hwnd>
+ Identifies the window whose menu is to be changed.
+
+ <hMenu>
+ Identifies the new menu.
+
+ The return value specifies whether the menu is changed. It is TRUE if the
+ menu is changed. Otherwise, it is FALSE.
+
+ %SetMenu% will not destroy a previous menu. An application should call the
+ %DestroyMenu% function to accomplish this task.
+--*/
+
+ULONG FASTCALL WU32SetMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETMENU16), parg16);
+
+ ul = GETBOOL16(SetMenu(
+ HWND32(parg16->f1),
+ HMENU32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL SetMenuItemBitmaps(<hMenu>, <nPosition>, <wFlags>,
+ <hBitmapUnchecked>, <hBitmapChecked>)
+ HMENU <hMenu>;
+ WORD <nPosition>;
+ WORD <wFlags>;
+ HBITMAP <hBitmapUnchecked>;
+ HBITMAP <hBitmapChecked>;
+
+ The %SetMenuItemBitmaps% function associates the specified bitmaps with a
+ menu item. Whether the menu item is checked or unchecked, Windows displays
+ the appropriate bitmap next to the menu item.
+
+ <hMenu>
+ Identifies the menu to be changed.
+
+ <nPosition>
+ Specifies the menu item to be changed. If <wFlags> is set to
+ MF_BYPOSITION, <nPosition> specifies the position of the menu item; the
+ first item in the menu is at position 0. If <wFlags> is set to
+ MF_BYCOMMAND, then <nPosition> specifies the command ID of the menu
+ item.
+
+ <wFlags>
+ Specifies how the <nPosition> parameter is interpreted. It may be
+ set to MF_BYCOMMAND (the default) or MF_BYPOSITION.
+
+ <hBitmapUnchecked>
+ Identifies the bitmap to be displayed when the menu item is
+ not checked.
+
+ <hBitmapChecked>
+ Identifies the bitmap to be displayed when the menu item is
+ checked.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function is successful. Otherwise, it is FALSE.
+
+ If either the <hBitmapUnchecked> or the <hBitmapChecked> parameters is NULL,
+ then Windows displays nothing next to the menu item for the corresponding
+ attribute. If both parameters are NULL, Windows uses the default checkmark
+ when the item is checked and removes the checkmark when the item is
+ unchecked.
+
+ When the menu is destroyed, these bitmaps are not destroyed; it is the
+ responsibility of the application to destroy them.
+
+ The %GetMenuCheckMarkDimensions% function retrieves the dimensions of the
+ default checkmark used for menu items. The application should use these
+ values to determine the appropriate size for the bitmaps supplied with this
+ function.
+--*/
+
+ULONG FASTCALL WU32SetMenuItemBitmaps(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETMENUITEMBITMAPS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETMENUITEMBITMAPS16), parg16);
+
+ ul = GETBOOL16(SetMenuItemBitmaps(
+ HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3),
+ HBITMAP32(parg16->f4),
+ HBITMAP32(parg16->f5)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL TrackPopupMenu(<hMenu>, <wFlags>, <x>, <y>, <nReserved>, <hwnd>,
+ <lpReserved>)
+
+ The %TrackPopupMenu% function displays a floating pop-up menu at the
+ specified location and tracks the selection of items on the pop-up menu. A
+ floating pop-up menu can appear anywhere on the screen. The <hMenu>
+ parameter specifies the handle of the menu to be displayed; the application
+ obtains this handle by calling %CreatePopupMenu% to create a new pop-up menu
+ or by calling %GetSubMenu% to retrieve the handle of a pop-up menu
+ associated with an existing menu item.
+
+ Windows sends messages generated by the menu to the window identified by the
+ <hwnd> parameter.
+
+ <hMenu>
+ Identifies the pop-up menu to be displayed.
+
+ <wFlags>
+ Not used. This parameter must be set to zero.
+
+ <x>
+ Specifies the horizontal position in screen coordinates of the
+ left side of the menu on the screen.
+
+ <y>
+ Specifies the vertical position in screen coordinates of the top
+ of the menu on the screen.
+
+ <nReserved>
+ Is reserved and must be set to zero.
+
+ <hwnd>
+ Identifies the window which owns the pop-up menu. This window
+ receives all WM_COMMAND messages from the menu.
+
+ <lpReserved>
+ Is reserved and must be set to NULL.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function is successful. Otherwise, it is FALSE.
+--*/
+
+ULONG FASTCALL WU32TrackPopupMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t7, *p7;
+ register PTRACKPOPUPMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(TRACKPOPUPMENU16), parg16);
+ p7 = GETRECT16(parg16->f7, &t7);
+
+ ul = GETBOOL16(TrackPopupMenu(
+ HMENU32(parg16->f1),
+ WORD32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ HWND32(parg16->f6),
+ p7
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
diff --git a/private/mvdm/wow32/wumenu.h b/private/mvdm/wow32/wumenu.h
new file mode 100644
index 000000000..f1076b2e8
--- /dev/null
+++ b/private/mvdm/wow32/wumenu.h
@@ -0,0 +1,35 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUMENU.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WU32AppendMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ChangeMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CheckMenuItem(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CreateMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CreatePopupMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DeleteMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DestroyMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DrawMenuBar(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetMenuCheckMarkDimensions(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetMenuString(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetSystemMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32HiliteMenuItem(PVDMFRAME pFrame);
+ULONG FASTCALL WU32InsertMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32LoadMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32LoadMenuIndirect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ModifyMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32RemoveMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetMenuItemBitmaps(PVDMFRAME pFrame);
+ULONG FASTCALL WU32TrackPopupMenu(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wumsg.c b/private/mvdm/wow32/wumsg.c
new file mode 100644
index 000000000..02d1b5108
--- /dev/null
+++ b/private/mvdm/wow32/wumsg.c
@@ -0,0 +1,2225 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUMSG.C
+ * WOW32 16-bit User Message API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+MODNAME(wumsg.c);
+
+
+extern HANDLE hmodWOW32;
+
+// SendDlgItemMessage cache
+HWND hdlgSDIMCached = NULL ;
+
+BOOL fWhoCalled = FALSE;
+
+
+
+// DDE bit used in GetMessage and PeekMessage
+
+#define fAckReq 0x8000
+#define fRelease 0x2000
+
+
+
+/*++
+ BOOL CallMsgFilter(<lpMsg>, <nCode>)
+ LPMSG <lpMsg>;
+ int <nCode>;
+
+ The %CallMsgFilter% function passes the given message and code to the
+ current message filter function. The message filter function is an
+ application-specified function that examines and modifies all messages. An
+ application specifies the function by using the %SetWindowsHook% function.
+
+ <lpMsg>
+ Points to an %MSG% structure that contains the message to be
+ filtered.
+
+ <nCode>
+ Specifies a code used by the filter function to determine how to
+ process the message.
+
+ The return value specifies the state of message processing. It is FALSE if
+ the message should be processed. It is TRUE if the message should not be
+ processed further.
+
+ The %CallMsgFilter% function is usually called by Windows to let
+ applications examine and control the flow of messages during internal
+ processing in menus and scroll bars or when moving or sizing a window.
+
+ Values given for the <nCode> parameter must not conflict with any of the
+ MSGF_ and HC_ values passed by Windows to the message filter function.
+--*/
+
+ULONG FASTCALL WU32CallMsgFilter(PVDMFRAME pFrame)
+{
+ INT f2;
+ ULONG ul;
+ MSG t1;
+ VPMSG16 vpf1;
+ register PCALLMSGFILTER16 parg16;
+ MSGPARAMEX mpex;
+
+ GETARGPTR(pFrame, sizeof(CALLMSGFILTER16), parg16);
+
+ vpf1 = (VPMSG16)(parg16->f1);
+ f2 = INT32(parg16->f2);
+
+ getmsg16(vpf1, &t1, &mpex);
+
+ // Note: getmsg16 may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ BlockWOWIdle(TRUE);
+
+ ul = GETBOOL16(CallMsgFilter(&t1, f2));
+
+ // Note: Call to CallMsgFilter may have caused 16-bit memory to move
+
+ BlockWOWIdle(FALSE);
+
+ // we need to free the struct ret'd by PackDDElParam in the getmsg16 call
+ // (actually the call is made in ThunkWMMsg16() which is called by getmsg16)
+ if((t1.message >= WM_DDE_FIRST) && (t1.message <= WM_DDE_LAST)) {
+ if(t1.message == WM_DDE_ACK ||
+ t1.message == WM_DDE_DATA ||
+ t1.message == WM_DDE_POKE ||
+ t1.message == WM_DDE_ADVISE ) {
+
+ // make sure this isn't in response to an initiate message
+ if(!WI32DDEInitiate((HWND16) mpex.Parm16.WndProc.hwnd)) {
+ FreeDDElParam(t1.message, t1.lParam);
+ }
+ }
+ }
+
+ FREEMSG16(vpf1, &t1);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ LONG CallWindowProc(<lpPrevWndFunc>, <hwnd>, <wMsg>, <wParam>, <lParam>)
+ FARPROC <lpPrevWndFunc>;
+ HWND <hwnd>;
+ WORD <wMsg>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ The %CallWindowProc% function passes message information to the function
+ specified by the <lpPrevWndFunc> parameter. The %CallWindowProc% function is
+ used for window subclassing. Normally, all windows with the same class share
+ the same window function. A subclass is a window or set of windows belonging
+ to the same window class whose messages are intercepted and processed by
+ another function (or functions) before being passed to the window function
+ of that class.
+
+ The %SetWindowLong% function creates the subclass by changing the window
+ function associated with a particular window, causing Windows to call the
+ new window function instead of the previous one. Any messages not processed
+ by the new window function must be passed to the previous window function by
+ calling %CallWindowProc%. This allows a chain of window functions to be
+ created.
+
+ <lpPrevWndFunc>
+ Is the procedure-instance address of the previous window function.
+
+ <hwnd>
+ Identifies the window that receives the message.
+
+ <wMsg>
+ Specifies the message number.
+
+ <wParam>
+ Specifies additional message-dependent information.
+
+ <lParam>
+ Specifies additional message-dependent information.
+
+ The return value specifies the result of the message processing. The
+ possible return values depend on the message sent.
+--*/
+
+ULONG FASTCALL WU32CallWindowProc(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PARM16 Parm16;
+ register PCALLWINDOWPROC16 parg16;
+ WORD f2, f3, f4;
+ LONG f5;
+ DWORD Proc16;
+ DWORD Proc32;
+ INT iMsgThunkClass = 0;
+
+ ul = FALSE;
+ GETARGPTR(pFrame, sizeof(CALLWINDOWPROC16), parg16);
+
+ Proc16 = DWORD32(parg16->f1);
+ f2 = parg16->f2;
+ f3 = WORD32(parg16->f3);
+ f4 = WORD32(parg16->f4);
+ f5 = LONG32(parg16->f5);
+
+ Proc32 = IsThunkWindowProc(Proc16, &iMsgThunkClass);
+
+ // Note: IsThunkWindowProc may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ if (Proc32) {
+ HWND hwnd;
+ UINT uMsgNew;
+ UINT uParamNew;
+ LONG lParamNew;
+ MSGPARAMEX mpex;
+
+ mpex.Parm16.WndProc.hwnd = f2;
+ mpex.Parm16.WndProc.wMsg = f3;
+ mpex.Parm16.WndProc.wParam = f4;
+ mpex.Parm16.WndProc.lParam = f5;
+ mpex.iMsgThunkClass = iMsgThunkClass;
+
+ if (hwnd = ThunkMsg16(&mpex)) {
+
+ // Note: ThunkMsg16 may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ uMsgNew = mpex.uMsg;
+ uParamNew = mpex.uParam;
+ lParamNew = mpex.lParam;
+
+ //
+ // see comment in IsMDIChild()
+ //
+
+ if ((uMsgNew == WM_CREATE || uMsgNew == WM_NCCREATE) && iMsgThunkClass == WOWCLASS_MDICLIENT) {
+ FinishThunkingWMCreateMDI16(lParamNew,
+ (LPCLIENTCREATESTRUCT)((LPCREATESTRUCT)lParamNew + 1));
+ }
+
+ BlockWOWIdle(TRUE);
+
+ ul = CallWindowProc((WNDPROC)Proc32, hwnd, uMsgNew,
+ uParamNew, lParamNew);
+ BlockWOWIdle(FALSE);
+
+ if ((uMsgNew == WM_CREATE || uMsgNew == WM_NCCREATE) && iMsgThunkClass == WOWCLASS_MDICLIENT) {
+ StartUnThunkingWMCreateMDI16(lParamNew); // does nothing
+ }
+
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ mpex.lReturn = ul;
+ (mpex.lpfnUnThunk16)(&mpex);
+ ul = mpex.lReturn;
+ }
+ }
+ }
+ else {
+ Parm16.WndProc.hwnd = f2;
+ Parm16.WndProc.wMsg = f3;
+ Parm16.WndProc.wParam = f4;
+ Parm16.WndProc.lParam = f5;
+ Parm16.WndProc.hInst = (WORD)GetWindowLong(HWND32(f2), GWL_HINSTANCE);
+ CallBack16(RET_WNDPROC, &Parm16, VPFN32(Proc16), (PVPVOID)&ul);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+
+
+/*++
+ LONG DefDlgProc(<hDlg>, <wMsg>, <wParam>, <lParam>)
+ HWND <hDlg>;
+ WORD <wMsg>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ The %DefDlgProc% function provides default processing for any Windows
+ messages that a dialog box with a private window class does not process.
+
+ All window messages that are not explicitly processed by the window function
+ must be passed to the %DefDlgProc% function, not the %DefWindowProc%
+ function. This ensures that all messages not handled by their private window
+ procedure will be handled properly.
+
+ <hDlg>
+ Identifies the dialog box.
+
+ <wMsg>
+ Specifies the message number.
+
+ <wParam>
+ Specifies 16 bits of additional message-dependent information.
+
+ <lParam>
+ Specifies 32 bits of additional message-dependent information.
+
+ The return value specifies the result of the message processing and depends
+ on the actual message sent.
+
+ The source code for the %DefDlgProc% function is provided on the SDK disks.
+
+ An application creates a dialog box by calling one of the following
+ functions:
+
+ %CreateDialog%
+ Creates a modeless dialog box.
+
+ %CreateDialogIndirect%
+ Creates a modeless dialog box.
+
+ %CreateDialogIndirectParam%
+ Creates a modeless dialog box and passes data to it when it is created.
+
+ %CreateDialogParam%
+ Creates a modeless dialog box and passes data to it when it is created.
+
+ %DialogBox%
+ Creates a modal dialog box.
+
+ %DialogBoxIndirect%
+ Creates a modal dialog box.
+
+ %DialogBoxIndirectParam%
+ Creates a modal dialog box and passes data to it when it is created.
+
+ %DialogBoxParam%
+ Creates a modal dialog box and passes data to it when it is created.
+--*/
+
+ULONG FASTCALL WU32DefDlgProc(PVDMFRAME pFrame)
+{
+ HWND hdlg;
+ MSGPARAMEX mpex;
+ register PDEFDLGPROC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DEFDLGPROC16), parg16);
+
+ mpex.lReturn = 0;
+ mpex.Parm16.WndProc.hwnd = parg16->f1;
+ mpex.Parm16.WndProc.wMsg = WORD32(parg16->f2);
+ mpex.Parm16.WndProc.wParam = WORD32(parg16->f3);
+ mpex.Parm16.WndProc.lParam = LONG32(parg16->f4);
+ mpex.iMsgThunkClass = 0;
+
+ if (hdlg = ThunkMsg16(&mpex)) {
+
+ // Note: ThunkMsg16 may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ SetFakeDialogClass(hdlg);
+
+ BlockWOWIdle(TRUE);
+ mpex.lReturn = DefDlgProc(hdlg, mpex.uMsg, mpex.uParam, mpex.lParam);
+ BlockWOWIdle(FALSE);
+
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ (mpex.lpfnUnThunk16)(&mpex);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN((ULONG)mpex.lReturn);
+}
+
+
+
+
+
+
+
+
+
+/*++
+ LONG DefFrameProc(<hwnd>, <hwndMDIClient>, <wMsg>, <wParam>, <lParam>)
+ HWND <hwnd>;
+ HWND <hwndMDIClient>;
+ WORD <wMsg>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ The %DefFrameProc% function provides default processing for any Windows
+ messages that the window function of a multiple document interface (MDI)
+ frame window does not process. All window messages that are not explicitly
+ processed by the window function must be passed to the %DefFrameProc%
+ function, not the %DefWindowProc% function.
+
+ <hwnd>
+ Identifies the MDI frame window.
+
+ <hwndMDIClient>
+ Identifies the MDI client window.
+
+ <wMsg>
+ Specifies the message number.
+
+ <wParam>
+ Specifies 16 bits of additional message-dependent information.
+
+ <lParam>
+ Specifies 32 bits of additional message-dependent information.
+
+ The return value specifies the result of the message processing and depends
+ on the actual message sent. If the <hwndMDIClient> parameter is NULL, the
+ return value is the same as for the %DefWindowProc% function.
+
+ Normally, when an application's window procedure does not handle a message,
+ it passes the message to the %DefWindowProc% function, which processes the
+ message. MDI applications use the %fDefFrameProc% and %DefMDIChildProc%
+ functions instead of %DefWindowProc% to provide default message processing.
+ All messages that an application would normally pass to %DefWindowProc%
+ (such as nonclient messages and WM_SETTEXT) should be passed to
+ %DefFrameProc% instead. In addition to these, %DefFrameProc% also handles
+ the following messages:
+
+ WM_COMMAND
+ The frame window of an MDI application receives the WM_COMMAND message
+ to activate a particular MDI child window. The window ID accompanying
+ this message will be the ID of the MDI child window assigned by Windows,
+ starting with the first ID specified by the application when it created
+ the MDI client window. This value of the first ID must not conflict with
+ menu-item IDs.
+
+ WM_MENUCHAR
+ When the ^ALTHYPHEN^ key is pressed, the control menu of the active MDI
+ child window will be selected.
+
+ WM_SETFOCUS
+ %DefFrameProc% passes focus on to the MDI client, which in turn passes
+ the focus on to the active MDI child window.
+
+ WM_SIZE
+ If the frame window procedure passes this message to %DefFrameProc%, the
+ MDI client window will be resized to fit in the new client area. If the
+ frame window procedure sizes the MDI client to a different size, it
+ should not pass the message to %DefWindowProc%.
+--*/
+
+ULONG FASTCALL WU32DefFrameProc(PVDMFRAME pFrame)
+{
+ HWND hwnd, hwnd2;
+
+ MSGPARAMEX mpex;
+ register PDEFFRAMEPROC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DEFFRAMEPROC16), parg16);
+
+ mpex.lReturn = 0;
+ mpex.Parm16.WndProc.hwnd = parg16->f1;
+ mpex.Parm16.WndProc.wMsg = WORD32(parg16->f3);
+ mpex.Parm16.WndProc.wParam = WORD32(parg16->f4);
+ mpex.Parm16.WndProc.lParam = LONG32(parg16->f5);
+ mpex.iMsgThunkClass = 0;
+
+ hwnd2 = HWND32(parg16->f2);
+
+ if (hwnd = ThunkMsg16(&mpex)) {
+
+ // Note: ThunkMsg16 may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ if (mpex.uMsg == WM_CLIENTSHUTDOWN &&
+ CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_IGNORECLIENTSHUTDOWN) {
+
+ //
+ // TurboCAD picks up an uninitialized stack variable as the
+ // message number to pass to DefFrameProc. In NT 3.51 it
+ // got 0x907 so the call was a NOP. In NT 4.0, because we
+ // now save FS and GS in wow16call, they pick up the x86
+ // flat FS, 0x3b, which also happens to be WM_CLIENTSHUTDOWN
+ // on NT and Win95, an undocumented message. DefFrameProc
+ // passes the message to DefWindowProc, which does some
+ // shutdown related processing which causes TurboCAD to fault
+ // soon thereafter.
+ //
+ // We considered renumbering WM_CLIENTSHUTDOWN, but Win95 uses
+ // it as well and some apps may have reverse-engineered the
+ // value 3b and depend on seeing the message.
+ //
+ // So instead we eat the call to DefFrameProc here under
+ // a compatibility bit.
+ // -- DaveHart 31-May-96
+ //
+
+ mpex.lReturn = 0;
+
+ } else {
+
+ BlockWOWIdle(TRUE);
+ mpex.lReturn = DefFrameProc(hwnd, hwnd2,
+ mpex.uMsg, mpex.uParam, mpex.lParam);
+ BlockWOWIdle(FALSE);
+ }
+
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ (mpex.lpfnUnThunk16)(&mpex);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN((ULONG)mpex.lReturn);
+}
+
+
+
+
+
+
+
+
+
+
+/*++
+ LONG DefMDIChildProc(<hwnd>, <wMsg>, <wParam>, <lParam>)
+ HWND <hwnd>;
+ WORD <wMsg>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ The %DefMDIChildProc% function provides default processing for any Windows
+ messages that the window function of a multiple document interface (MDI)
+ child window does not process. All window messages that are not explicitly
+ processed by the window function must be passed to the %DefMDIChildProc%
+ function, not the %DefWindowProc% function.
+
+ <hwnd>
+ Identifies the MDI child window.
+
+ <wMsg>
+ Specifies the message number.
+
+ <wParam>
+ Specifies 16 bits of additional message-dependent information.
+
+ <lParam>
+ Specifies 32 bits of additional message-dependent information.
+
+ The return value specifies the result of the message processing and depends
+ on the actual message sent.
+
+ This function assumes that the parent of the window identified by the <hwnd>
+ parameter was created with the MDICLIENT class.
+
+ Normally, when an application's window procedure does not handle a message,
+ it passes the message to the %DefWindowProc% function, which processes the
+ message. MDI applications use the %DefFrameProc% and %DefMDIChildProc%
+ functions instead of %DefWindowProc% to provide default message processing.
+ All messages that an application would normally pass to %DefWindowProc%
+ (such as nonclient messages and WM_SETTEXT) should be passed to
+ %DefMDIChildProc% instead. In addition to these, %DefMDIChildProc% also
+ handles the following messages:
+
+ WM_CHILDACTIVATE
+ Performs activation processing when child windows are sized, moved, or
+ shown. This message must be passed.
+
+ WM_GETMINMAXINFO
+ Calculates the size of a maximized MDI child window based on the current
+ size of the MDI client window.
+
+ WM_MENUCHAR
+ Sends the key to the frame window.
+
+ WM_MOVE
+ Recalculates MDI client scroll bars, if they are present.
+
+ WM_SETFOCUS
+ Activates the child window if it is not the active MDI child.
+
+ WM_SIZE
+ Performs necessary operations when changing the size of a window,
+ especially when maximizing or restoring an MDI child window. Failing to
+ pass this message to %DefMDIChildProc% will produce highly undesirable
+ results.
+
+ WM_SYSCOMMAND
+ Also handles the next window command.
+--*/
+
+ULONG FASTCALL WU32DefMDIChildProc(PVDMFRAME pFrame)
+{
+ HWND hwnd;
+ register PDEFMDICHILDPROC16 parg16;
+ MSGPARAMEX mpex;
+
+ GETARGPTR(pFrame, sizeof(DEFMDICHILDPROC16), parg16);
+
+ mpex.lReturn = 0;
+ mpex.Parm16.WndProc.hwnd = parg16->f1;
+ mpex.Parm16.WndProc.wMsg = WORD32(parg16->f2);
+ mpex.Parm16.WndProc.wParam = WORD32(parg16->f3);
+ mpex.Parm16.WndProc.lParam = LONG32(parg16->f4);
+ mpex.iMsgThunkClass = 0;
+
+ if (hwnd = ThunkMsg16(&mpex)) {
+
+ // Note: ThunkMsg16 may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ BlockWOWIdle(TRUE);
+ mpex.lReturn = DefMDIChildProc(hwnd, mpex.uMsg, mpex.uParam,
+ mpex.lParam);
+ BlockWOWIdle(FALSE);
+
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ (mpex.lpfnUnThunk16)(&mpex);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN((ULONG)mpex.lReturn);
+}
+
+
+
+
+
+
+
+
+
+
+/*++
+ LONG DefWindowProc(<hwnd>, <wMsg>, <wParam>, <lParam>)
+ HWND <hwnd>;
+ WORD <wMsg>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ The %DefWindowProc% function calls the default window procedure. The
+ default window procedure provides default processing for any window messages
+ that an application does not process. This function is used to ensure that
+ every message is processed. It should be called with the same parameters as
+ those received by the window procedure.
+
+ <hwnd>
+ Identifies the window that received the message.
+
+ <wMsg>
+ Specifies the message.
+
+ <wParam>
+ Specifies 16 bits of additional message-dependent information.
+
+ <lParam>
+ Specifies 32 bits of additional message-dependent information.
+
+ The return value is dependent on the message that was passed to this
+ function.
+--*/
+
+ULONG FASTCALL WU32DefWindowProc(PVDMFRAME pFrame)
+{
+ HWND hwnd;
+ register PDEFWINDOWPROC16 parg16;
+ MSGPARAMEX mpex;
+
+ GETARGPTR(pFrame, sizeof(DEFWINDOWPROC16), parg16);
+
+ mpex.lReturn = 0;
+ mpex.Parm16.WndProc.hwnd = parg16->hwnd;
+ mpex.Parm16.WndProc.wMsg = WORD32(parg16->wMsg);
+ mpex.Parm16.WndProc.wParam = WORD32(parg16->wParam);
+ mpex.Parm16.WndProc.lParam = LONG32(parg16->lParam);
+ mpex.iMsgThunkClass = 0;
+
+ if (hwnd = ThunkMsg16(&mpex)) {
+
+ // Note: ThunkMsg16 may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ BlockWOWIdle(TRUE);
+ mpex.lReturn = DefWindowProc(hwnd, mpex.uMsg, mpex.uParam, mpex.lParam);
+ BlockWOWIdle(FALSE);
+
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ (mpex.lpfnUnThunk16)(&mpex);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN((ULONG)mpex.lReturn);
+}
+
+
+
+
+
+
+
+
+
+
+/*++
+ LONG DispatchMessage(<lpMsg>)
+ LPMSG <lpMsg>;
+
+ The %DispatchMessage% function passes the message in the %MSG% structure
+ pointed to by the <lpMsg> parameter to the window function of the specified
+ window.
+
+ <lpMsg>
+ Points to an %MSG% structure that contains message information from
+ the Windows application queue.
+
+ The structure must contain valid message values. If <lpMsg> points to a
+ WM_TIMER message and the <lParam> parameter of the WM_TIMER message is
+ not NULL, then the <lParam> parameter is the address of a function that
+ is called instead of the window function.
+
+ The return value specifies the value returned by the window function. Its
+ meaning depends on the message being dispatched, but generally the return
+ value is ignored.
+--*/
+
+ULONG FASTCALL WU32DispatchMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ WORD wTDB;
+ MSG t1;
+ register PDISPATCHMESSAGE16 parg16;
+ MSGPARAMEX mpex;
+
+ GETARGPTR(pFrame, sizeof(DISPATCHMESSAGE16), parg16);
+
+ wTDB = pFrame->wTDB;
+
+ getmsg16(parg16->f1, &t1, &mpex);
+
+ // Note: getmsg16 may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ if (CACHENOTEMPTY() && !(CURRENTPTD()->dwWOWCompatFlags & WOWCF_DONTRELEASECACHEDDC)) {
+
+ ReleaseCachedDCs(wTDB, 0, 0, 0, SRCHDC_TASK16);
+ }
+
+ BlockWOWIdle(TRUE);
+
+ ul = GETLONG16(DispatchMessage(&t1));
+
+ BlockWOWIdle(FALSE);
+
+ // WARNING Don't rely on any 32 bit flat pointers to 16 bit memory
+ // After the dispatchmessage call.
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ BOOL GetMessage(<lpMsg>, <hwnd>, <wMsgFilterMin>, <wMsgFilterMax>)
+ LPMSG <lpMsg>;
+ HWND <hwnd>;
+ WORD <wMsgFilterMin>;
+ WORD <wMsgFilterMax>;
+
+ The %GetMessage% function retrieves a message from the application queue and
+ places the message in the structure pointed to by the <lpMsg> parameter. If
+ no message is available, the %GetMessage% function yields control to other
+ applications until a message becomes available.
+
+ %GetMessage% retrieves only messages associated with the window specified by
+ the <hwnd> parameter and within the range of message values given by the
+ <wMsgFilterMin> and <wMsgFilterMax> parameters. If <hwnd> is NULL,
+ %GetMessage% retrieves messages for any window that belongs to the
+ application making the call. (The %GetMessage% function does not retrieve
+ messages for windows that belong to other applications.) If <wMsgFilterMin>
+ and <wMsgFilterMax> are both zero, %GetMessage% returns all available
+ messages (no filtering is performed).
+
+ The constants WM_KEYFIRST and WM_KEYLAST can be used as filter values to
+ retrieve all messages related to keyboard input; the constants WM_MOUSEFIRST
+ and WM_MOUSELAST can be used to retrieve all mouse-related messages.
+
+ <lpMsg>
+ Points to an %MSG% structure that contains message information from
+ the Windows application queue.
+
+ <hwnd>
+ Identifies the window whose messages are to be examined. If
+ <hwnd> is NULL, %GetMessage% retrieves messages for any window that
+ belongs to the application making the call.
+
+ <wMsgFilterMin>
+ Specifies the integer value of the lowest message value to be
+ retrieved.
+
+ <wMsgFilterMax>
+ Specifies the integer value of the highest message value to be
+ retrieved.
+
+ The return value is TRUE if a message other than WM_QUIT is retrieved. It is
+ FALSE if the WM_QUIT message is retrieved.
+
+ The return value is usually used to decide whether to terminate the
+ application's main loop and exit the program.
+
+ In addition to yielding control to other applications when no messages are
+ available, the %GetMessage% and %PeekMessage% functions also yield control
+ when WM_PAINT or WM_TIMER messages for other tasks are available.
+
+ The %GetMessage%, %PeekMessage%, and %WaitMessage% functions are the only
+ ways to let other applications run. If your application does not call any of
+ these functions for long periods of time, other applications cannot run.
+
+ When %GetMessage%, %PeekMessage%, and %WaitMessage% yield control to other
+ applications, the stack and data segments of the application calling the
+ function may move in memory to accommodate the changing memory requirements
+ of other applications. If the application has stored long pointers to
+ objects in the data or stack segment (that is, global or local variables),
+ these pointers can become invalid after a call to %GetMessage%,
+ %PeekMessage%, or %WaitMessage%. The <lpMsg> parameter of the called
+ function remains valid in any case.
+--*/
+
+ULONG FASTCALL WU32GetMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ MSG t1;
+ VPMSG16 vpMsg;
+ register PGETMESSAGE16 parg16;
+ ULONG ulReturn;
+
+ BlockWOWIdle(TRUE);
+
+// NOTE: pFrame needs to be restored on all GOTO's to get_next_dde_message
+get_next_dde_message:
+
+ GETARGPTR(pFrame, sizeof(GETMESSAGE16), parg16);
+
+ vpMsg = parg16->vpMsg;
+
+
+
+ ul = GETBOOL16(GetMessage(&t1,
+ HWND32(parg16->hwnd),
+ WORD32(parg16->wMin),
+ WORD32(parg16->wMax)));
+
+
+ // There Could have been a Task Switch Before GetMessage Returned so
+ // Don't Trust any 32 bit flat pointers we have, memory could've been
+ // compacted or moved.
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+
+#ifdef DEBUG
+ if (t1.message == WM_TIMER) {
+ WOW32ASSERT(HIWORD(t1.wParam) == 0);
+ }
+#endif
+
+ ulReturn = putmsg16(vpMsg, &t1);
+
+ // NOTE: Call to putmsg16 could've caused 16-bit memory movement
+
+ if (((t1.message == WM_DDE_DATA) || (t1.message == WM_DDE_POKE)) && (!ulReturn)) {
+ register PMSG16 pmsg16;
+ DDEDATA *lpMem32;
+ WORD Status;
+ UINT dd;
+ WORD ww;
+ char szMsgBoxText[1024];
+ char szCaption[256];
+
+ GETVDMPTR(vpMsg, sizeof(MSG16), pmsg16);
+
+ dd = FETCHDWORD(pmsg16->lParam);
+ ww = FETCHWORD(pmsg16->wParam);
+
+ lpMem32 = GlobalLock((HGLOBAL)dd);
+ Status = (*((PWORD) lpMem32));
+ GlobalUnlock((HGLOBAL)dd);
+
+ (pfnOut.pfnFreeDDEData)((HANDLE)dd, TRUE, TRUE);
+
+ GlobalDeleteAtom (ww);
+
+ if ((Status & fAckReq) || (t1.message == WM_DDE_POKE)) {
+ LoadString(hmodWOW32, iszOLEMemAllocFailedFatal, szMsgBoxText, sizeof szMsgBoxText);
+ LoadString(hmodWOW32, iszSystemError, szCaption, sizeof szCaption);
+ MessageBox(t1.hwnd, (LPCTSTR) szMsgBoxText, szCaption, MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
+ PostMessage((HWND) t1.wParam, WM_DDE_TERMINATE, (WPARAM)FULLHWND32((WORD)t1.hwnd), (LPARAM)0l);
+ }
+ else {
+ LoadString(hmodWOW32, iszOLEMemAllocFailed, szMsgBoxText, sizeof szMsgBoxText);
+ LoadString(hmodWOW32, iszSystemError, szCaption, sizeof szCaption);
+ MessageBox(t1.hwnd, (LPCTSTR) szMsgBoxText, szCaption, MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
+ }
+
+ FREEVDMPTR(pmsg16);
+
+ // restore the frame ptr due to possible 16-bit memory movement
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+
+ goto get_next_dde_message;
+ }
+
+ BlockWOWIdle(FALSE);
+
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ DWORD GetMessagePos(VOID)
+
+ The %GetMessagePos% function returns a long value that represents the cursor
+ position (in screen coordinates) when the last message obtained by the
+ %GetMessage% function occurred.
+
+ This function has no parameters.
+
+ The return value specifies the <x>- and <y>-coordinates of the cursor
+ position. The <x>-coordinate is in the low-order word, and the
+ <y>-coordinate is in the high-order word. If the return value is assigned to
+ a variable, the %MAKEPOINT% macro can be used to obtain a %POINT% structure
+ from the return value; the %LOWORD% or %HIWORD% macro can be used to extract
+ the <x>- or the <y>-coordinate.
+
+ To obtain the current position of the cursor instead of the position when
+ the last message occurred, use the %GetCursorPos% function.
+--*/
+
+ULONG FASTCALL WU32GetMessagePos(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETDWORD16(GetMessagePos());
+
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ DWORD GetMessageTime(VOID)
+
+ The %GetMessageTime% function returns the message time for the last message
+ retrieved by the %GetMessage% function. The time is a long integer that
+ specifies the elapsed time (in milliseconds) from the time the system was
+ booted to the time the message was created (placed in the application
+ queue).
+
+ This function has no parameters.
+
+ The return value specifies the message time.
+
+ Do not assume that the return value is always increasing. The return value
+ will wrap around to zero if the timer count exceeds the maximum value for
+ long integers.
+
+ To calculate time delays between messages, subtract the time of the second
+ message from the time of the first message.
+--*/
+
+ULONG FASTCALL WU32GetMessageTime(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETLONG16(GetMessageTime());
+
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ BOOL InSendMessage(VOID)
+
+ The %InSendMessage% function specifies whether the current window function
+ is processing a message that is passed to it through a call to the
+ %SendMessage% function.
+
+ This function has no parameters.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ window function is processing a message sent to it with %SendMessage%.
+ Otherwise, it is FALSE.
+
+ Applications use the %InSendMessage% function to determine how to handle
+ errors that occur when an inactive window processes messages. For example,
+ if the active window uses %SendMessage% to send a request for information to
+ another window, the other window cannot become active until it returns
+ control from the %SendMessage% call. The only method an inactive window has
+ to inform the user of an error is to create a message box.
+--*/
+
+ULONG FASTCALL WU32InSendMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETBOOL16(InSendMessage());
+
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ BOOL PeekMessage(<lpMsg>, <hwnd>, <wMsgFilterMin>, <wMsgFilterMax>,
+ <wRemoveMsg>)
+ LPMSG <lpMsg>;
+ HWND <hwnd>;
+ WORD <wMsgFilterMin>;
+ WORD <wMsgFilterMax>;
+ WORD <wRemoveMsg>;
+
+ The %PeekMessage% function checks the application queue for a message and
+ places the message (if any) in the structure pointed to by the <lpMsg>
+ parameter. Unlike the %GetMessage% function, the %PeekMessage% function does
+ not wait for a message to be placed in the queue before returning. It does,
+ however, yield control (if the PM_NOYIELD flag isn't set) and does not
+ return control after the yield until Windows returns control to the
+ application.
+
+ %PeekMessage% retrieves only messages associated with the window specified
+ by the <hwnd> parameter, or any of its children as specified by the
+ %IsChild% function, and within the range of message values given by the
+ <wMsgFilterMin> and <wMsgFilterMax> parameters. If <hwnd> is NULL,
+ %PeekMessage% retrieves messages for any window that belongs to the
+ application making the call. (The %PeekMessage% function does not retrieve
+ messages for windows that belong to other applications.) If <hwnd> is -1,
+ %PeekMessage% returns only messages with a <hwnd> of NULL as posted by the
+ %PostAppMessage% function. If <wMsgFilterMin> and <wMsgFilterMax> are both
+ zero, %PeekMessage% returns all available messages (no range filtering is
+ performed).
+
+ The WM_KEYFIRST and WM_KEYLAST flags can be used as filter values to
+ retrieve all key messages; the WM_MOUSEFIRST and WM_MOUSELAST flags can be
+ used to retrieve all mouse messages.
+
+ <lpMsg>
+ Points to an %MSG% structure that contains message information from
+ the Windows application queue.
+
+ <hwnd>
+ Identifies the window whose messages are to be examined.
+
+ <wMsgFilterMin>
+ Specifies the value of the lowest message position to be
+ examined.
+
+ <wMsgFilterMax>
+ Specifies the value of the highest message position to be
+ examined.
+
+ <wRemoveMsg>
+ Specifies a combination of the flags described in the following
+ list. PM_NOYIELD can be combined with either PM_NOREMOVE or PM_REMOVE:
+
+ PM_NOREMOVE
+ Messages are not removed from the queue after processing by
+ PeekMessage.
+
+ PM_NOYIELD
+ Prevents the current task from halting and yielding system resources to
+ another task.
+
+ PM_REMOVE
+ Messages are removed from the queue after processing by %PeekMessage%.
+
+ The return value specifies whether or not a message is found. It is TRUE if
+ a message is available. Otherwise, it is FALSE.
+
+ %PeekMessage% does not remove WM_PAINT messages from the queue. The messages
+ remain in the queue until processed. The %GetMessage%, %PeekMessage%, and
+ %WaitMessage% functions yield control to other applications. These calls are
+ the only way to let other applications run. If your application does not
+ call any of these functions for long periods of time, other applications
+ cannot run.
+
+ When %GetMessage%, %PeekMessage%, and %WaitMessage% yield control to other
+ applications, the stack and data segments of the application calling the
+ function may move in memory to accommodate the changing memory requirements
+ of other applications.
+
+ If the application has stored long pointers to objects in the data or stack
+ segment (global or local variables), and if they are unlocked, these
+ pointers can become invalid after a call to %GetMessage%, %PeekMessage%, or
+ %WaitMessage%. The <lpMsg> parameter of the called function remains valid in
+ any case.
+--*/
+
+ULONG FASTCALL WU32PeekMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ VPMSG16 vpf1;
+ HANDLE f2;
+ WORD f3, f4, f5;
+ MSG t1;
+ register PPEEKMESSAGE16 parg16;
+ BOOL fNoYield;
+
+ BlockWOWIdle(TRUE);
+
+// NOTE: pFrame needs to be restored on all GOTO's to get_next_dde_message
+get_next_dde_message:
+
+ GETARGPTR(pFrame, sizeof(PEEKMESSAGE16), parg16);
+
+ vpf1 = parg16->f1;
+ f2 = HWND32(parg16->f2);
+ f3 = WORD32(parg16->f3);
+ f4 = WORD32(parg16->f4);
+ f5 = parg16->f5;
+
+ fNoYield = f5 & PM_NOYIELD;
+
+ ul = GETBOOL16(PeekMessage(&t1, f2, f3, f4, f5));
+
+ // There could've been a task switch before peekmessage returned
+ // so Don't trust any 32 bit flat pointers we have, memory could
+ // have been compacted or moved.
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+#ifdef DEBUG
+ if (ul && t1.message == WM_TIMER) {
+ WOW32ASSERT(HIWORD(t1.wParam) == 0);
+ }
+#endif
+
+ // If PeekMessage returned NULL don't bother to copy anything back
+
+ if (ul) {
+ ULONG ulReturn;
+
+ //
+ // We need to set/reset fThunkDDEmsg (based on PM_REMOVE flag)
+ // so that we know whether to call FreeDDElParam or not while
+ // thunking 32 bit message to 16 bit message.
+ //
+
+ fThunkDDEmsg = (BOOL) (f5 & PM_REMOVE);
+ ulReturn = putmsg16(vpf1, &t1);
+
+ // There Could've been a Task Switch Before putmsg16 Returned so Don't
+ // Trust any 32 bit flat pointers we have, memory could have been
+ // compacted or moved.
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+ fThunkDDEmsg = TRUE;
+
+ if (((t1.message == WM_DDE_DATA) || (t1.message == WM_DDE_POKE)) && (!ulReturn)) {
+ register PMSG16 pmsg16;
+ DDEDATA *lpMem32;
+ WORD Status;
+ UINT dd;
+ WORD ww;
+ char szMsgBoxText[1024];
+ char szCaption[256];
+
+ GETVDMPTR(vpf1, sizeof(MSG16), pmsg16);
+
+ dd = FETCHDWORD(pmsg16->lParam);
+ ww = FETCHWORD(pmsg16->wParam);
+
+ lpMem32 = GlobalLock((HGLOBAL)dd);
+ Status = (*((PWORD) lpMem32));
+ GlobalUnlock((HGLOBAL)dd);
+
+ (pfnOut.pfnFreeDDEData)((HANDLE)dd, TRUE, TRUE);
+
+ GlobalDeleteAtom (ww);
+
+ if (!(f5 & PM_REMOVE)) {
+
+ ul = GETBOOL16(PeekMessage(&t1, f2, f3, f4, f5 | PM_REMOVE));
+
+ // There could've been a task switch before peekmessage returned
+ // so Don't trust any 32 bit flat pointers we have, memory could
+ // have been compacted or moved.
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ FREEVDMPTR(pmsg16);
+
+ // uncomment if parg16 is ref'd before goto get_next_dde_message
+ //GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+ //GETARGPTR(pFrame, sizeof(PEEKMESSAGE16), parg16);
+
+ // uncomment if pmsg16 is ref'd before goto get_next_dde_message
+ //GETVDMPTR(vpf1, sizeof(MSG16), pmsg16);
+ }
+
+ if ((Status & fAckReq) || (t1.message == WM_DDE_POKE)) {
+
+ LoadString(hmodWOW32, iszOLEMemAllocFailedFatal, szMsgBoxText, sizeof szMsgBoxText);
+ LoadString(hmodWOW32, iszSystemError, szCaption, sizeof szCaption);
+ MessageBox(t1.hwnd, (LPCTSTR) szMsgBoxText, szCaption, MB_OK);
+ PostMessage ((HWND) t1.wParam, WM_DDE_TERMINATE, (WPARAM)FULLHWND32((WORD)t1.hwnd), (LPARAM)0l);
+ }
+ else {
+ LoadString(hmodWOW32, iszOLEMemAllocFailed, szMsgBoxText, sizeof szMsgBoxText);
+ LoadString(hmodWOW32, iszSystemError, szCaption, sizeof szCaption);
+ MessageBox(t1.hwnd, (LPCTSTR) szMsgBoxText, szCaption, MB_OK);
+ }
+
+ FREEVDMPTR(pmsg16);
+
+ // restore the frame ptr due to possible 16-bit memory movement
+ GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
+
+ goto get_next_dde_message;
+ }
+ }
+ else if (fNoYield && (CURRENTPTD()->dwWOWCompatFlags & WOWCF_SETNULLMESSAGE)) {
+
+ // winproj (help.tutorial) calls peekmessage with PM_REMOVE and
+ // PM_NOYIELD and an lpmsg whose contents are uninitialized. However
+ // even if peekmessage returns false, it checks if lpmsg->message is
+ // WM_QUIT and if true exits. In WOW by pure coincidence the
+ // unintialized lpmsg->message happens to be value 0x12, which is
+ // WM_QUIT and thus the tutorial always exits after initialization.
+ //
+ // So we reset lpmsg->message to zero, if it was called with PM_NOYIELD
+ // and if it happens to be WM_QUIT and if peekmessage returns zero.
+ //
+ // - nanduri
+
+ // we don't need to reinitialize pFrame etc. 'cause peekmessage was
+ // called with PM_NOYIELD and thus the 16bit memory couldn't have moved
+
+ register PMSG16 pmsg16;
+ GETVDMPTR(vpf1, sizeof(MSG16), pmsg16);
+ if (pmsg16 && (pmsg16->message == WM_QUIT)) {
+ pmsg16->message = 0;
+ }
+ FREEVDMPTR(pmsg16);
+ }
+
+
+ BlockWOWIdle(FALSE);
+
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ BOOL PostAppMessage(<hTask>, <wMsg>, <wParam>, <lParam>)
+ HANDLE <hTask>;
+ WORD <wMsg>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ The %PostAppMessage% function posts a message to an application identified
+ by a task handle, and then returns without waiting for the application to
+ process the message. The application receiving the message obtains the
+ message by calling the %GetMessage% or %PeekMessage% function. The <hwnd>
+ parameter of the returned %MSG% structure is NULL.
+
+ <hTask>
+ Identifies the task that is to receive the message. The
+ %GetCurrentTask% function returns this handle.
+
+ <wMsg>
+ Specifies the type of message posted.
+
+ <wParam>
+ Specifies additional message information.
+
+ <lParam>
+ Specifies additional message information.
+
+ The return value specifies whether or not the message is posted. It is
+ TRUE if the message is posted. Otherwise, it is FALSE.
+--*/
+
+ULONG FASTCALL WU32PostAppMessage(PVDMFRAME pFrame)
+{
+ register PPOSTAPPMESSAGE16 parg16;
+ DWORD f1;
+ MSGPARAMEX mpex;
+
+ GETARGPTR(pFrame, sizeof(POSTAPPMESSAGE16), parg16);
+
+ mpex.lReturn = 0;
+ mpex.Parm16.WndProc.hwnd = 0;
+ mpex.Parm16.WndProc.wMsg = WORD32(parg16->f2);
+ mpex.Parm16.WndProc.wParam = WORD32(parg16->f3);
+ mpex.Parm16.WndProc.lParam = LONG32(parg16->f4);
+ mpex.iMsgThunkClass = 0;
+
+ f1 = THREADID32(parg16->f1);
+
+ ThunkMsg16(&mpex);
+
+ // Note: ThunkMsg16 may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ mpex.lReturn = PostThreadMessage(f1, mpex.uMsg, mpex.uParam, mpex.lParam);
+
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ (mpex.lpfnUnThunk16)(&mpex);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN((ULONG)mpex.lReturn);
+}
+
+
+
+
+
+
+
+/*++
+ BOOL PostMessage(<hwnd>, <msg>, <wParam>, <lParam>)
+ HWND <hwnd>;
+ WORD <msg>;
+ WORD <wParam>;
+ LONG <lParam>;
+
+ The %PostMessage% function places a message in a window's application queue,
+ and then returns without waiting for the corresponding window to process the
+ message. Messages in a message queue are retrieved by calls to the
+ %GetMessage% or %PeekMessage% function.
+
+ .*
+ .* DA's: the following parameters section should be identical to the
+ .* parameters section in the sdmsg.ref file. If there is a change
+ .* to this section, the identical change should be made in the other
+ .* file.
+ .*
+
+ <hwnd>
+ Identifies the window that is to receive the message. If this parameter
+ is 0xFFFF (-1), the message is sent to all top-level windows.
+
+ <msg>
+ Specifies the message to be sent.
+
+ <wParam>
+ Specifies additional message information. The contents of this
+ parameter depends on the message being sent.
+
+ <lParam>
+ Specifies additional message information. The contents of this
+ parameter depends on the message being sent.
+
+ The return value is TRUE if the message is posted, or FALSE if it is not.
+
+ An application should never use the %PostMessage% function to send a message
+ to a control.
+
+ .cmt
+ 27-Oct-1990 [ralphw]
+
+ The following is a rewording of the previous documentation. However, it
+ needs confirmation from development as to its technical accuracy before it
+ can be released for public consumption.
+
+ If the message is being sent to another application, and the <wParam> or
+ <lParam> parameters are used to pass a handle or pointer to global memory,
+ the memory should be allocated by the %GlobalAlloc% function using the
+ GMEM_NOT_BANKED flag. In a system using expanded memory (EMS), this ensures
+ that the memory is not in in a different bank of memory from the application
+ using the memory.
+ .endcmt
+--*/
+
+ULONG FASTCALL WU32PostMessage(PVDMFRAME pFrame)
+{
+ LONG l;
+ UINT f2;
+ WPARAM f3;
+ LPARAM f4;
+ HWND hwnd;
+ register PPOSTMESSAGE16 parg16;
+ MSGPARAMEX mpex;
+ DWORD err = NO_ERROR;
+
+ GETARGPTR(pFrame, sizeof(POSTMESSAGE16), parg16);
+
+ // Apps should never use PostMessage to post messages that have
+ // pointers to structures, because those messages will show up in
+ // GetMessage, and if GetMessage tries to thunk them (ie, tries to
+ // call back to the 16-bit kernel to allocate some 16-bit memory to
+ // copy the converted 32-bit structure into), we have no way of
+ // knowing when to free that 16-bit memory.
+ //
+ // BUGBUG 22-Aug-91 JeffPar: a flag should be added to ThunkMsg16
+ // indicating whether or not such allocations are permissible; this
+ // flag should be passed on to all the ThunkXXMsg16 subfunctions,
+ // and each of those subfunctions should assert the flag is false
+ // whenever allocating 16-bit memory.
+
+
+ //
+ // Used by 16->32 DDE thunkers.
+ //
+
+ fWhoCalled = WOWDDE_POSTMESSAGE;
+
+ f2 = (UINT)WORD32(parg16->f2);
+ f3 = (WPARAM)(WORD32(parg16->f3));
+ f4 = (LPARAM)(LONG32(parg16->f4));
+
+ mpex.lReturn = 0;
+ mpex.Parm16.WndProc.hwnd = parg16->f1;
+ mpex.Parm16.WndProc.wMsg = f2;
+ mpex.Parm16.WndProc.wParam = f3;
+ mpex.Parm16.WndProc.lParam = f4;
+ mpex.iMsgThunkClass = 0;
+
+ // The Reader.exe shipped with Lotus 123MM version has a message
+ // synchronization problem. Force proper synchronization by
+ // converting this PostMessage call to a SendMessage().
+ if ((f2 == WM_VSCROLL) &&
+ ((f3 == SB_THUMBTRACK) || (f3 == SB_THUMBPOSITION)) &&
+ (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_SENDPOSTEDMSG) ) {
+
+ l = (LONG)WU32SendMessage(pFrame);
+ FREEARGPTR(parg16);
+ RETURN((ULONG) l);
+ }
+
+ hwnd = ThunkMsg16(&mpex);
+
+ // Note: ThunkMsg16 may have caused 16-bit memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ fWhoCalled = FALSE;
+ if (hwnd) {
+
+ l = PostMessage(hwnd, mpex.uMsg, mpex.uParam, mpex.lParam);
+
+ if (!l)
+ err = GetLastError();
+
+ mpex.lReturn = l;
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ (mpex.lpfnUnThunk16)(&mpex);
+ }
+
+
+ // If the post message failed, then the message was probably one
+ // that has pointers and therefore can not be posted. (MetaDesign
+ // tries to post these kind of messages.) If the destination was a
+ // WOW app, then make it into a private message, and try the post
+ // again. We don't have to worry about thunking since both the source
+ // and destination are in the WOW address space.
+
+ if (err == ERROR_INVALID_PARAMETER) {
+ PWW pww;
+ pww = FindPWW(hwnd, WOWCLASS_UNKNOWN);
+
+ if (pww != NULL && pww->iClass != WOWCLASS_UNKNOWN) {
+
+ mpex.lReturn = PostMessage(hwnd, f2 | WOWPRIVATEMSG, f3, f4);
+ }
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN((ULONG)mpex.lReturn);
+}
+
+
+
+
+
+
+
+/*++
+ void PostQuitMessage(<nExitCode>)
+ int <nExitCode>;
+
+ The %PostQuitMessage% function informs Windows that the application wishes
+ to terminate execution. It is typically used in response to a WM_DESTROY
+ message.
+
+ The %PostQuitMessage% function posts a WM_QUIT message to the application
+ and returns immediately; the function merely informs the system that the
+ application wants to quit sometime in the future.
+
+ When the application receives the WM_QUIT message, it should exit the
+ message loop in the main function and return control to Windows. The exit
+ code returned to Windows must be the <wParam> parameter of the WM_QUIT
+ message.
+
+ <nExitCode>
+ Specifies an application exit code. It is used as the wParam parameter
+ of the WM_QUIT message.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32PostQuitMessage(PVDMFRAME pFrame)
+{
+ register PPOSTQUITMESSAGE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(POSTQUITMESSAGE16), parg16);
+
+ PostQuitMessage(INT32(parg16->wExitCode));
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+
+
+
+
+
+/*++
+ WORD RegisterWindowMessage(<lpString>)
+ LPSTR <lpString>;
+
+ This function defines a new window message that is guaranteed to be unique
+ throughout the system. The returned message value can be used when calling
+ the %SendMessage% or %PostMessage% function.
+
+ %RegisterWindowMessage% is typically used for communication between two
+ cooperating applications.
+
+ If the same message string is registered by two different applications, the
+ same message value is returned. The message remains registered until the
+ user ends the Windows session.
+
+ <lpString>
+ Points to the message string to be registered.
+
+ The return value specifies the outcome of the function. It is an unsigned
+ short integer within the range 0xC000 to 0xFFFF if the message is
+ successfully registered. Otherwise, it is zero.
+
+ Use the %RegisterWindowMessage% function only when the same message must be
+ understood by more than one application. For sending private messages within
+ an application, an application can use any integer within the range WM_USER
+ to 0xBFFF.
+--*/
+
+ULONG FASTCALL WU32RegisterWindowMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ register PREGISTERWINDOWMESSAGE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(REGISTERWINDOWMESSAGE16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+
+ ul = GETWORD16(RegisterWindowMessage(psz1));
+
+ FREEPSZPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ void ReplyMessage(<lReply>)
+ LONG <lReply>;
+
+ The %ReplyMessage% function is used to reply to a message sent through the
+ %SendMessage% function without returning control to the function that called
+ %SendMessage.%
+
+ By calling this function, the window function that receives the message
+ allows the task that called %SendMessage% to continue to execute as though
+ the task that received the message had returned control. The task that calls
+ %ReplyMessage% also continues to execute.
+
+ Normally a task that calls %SendMessage% to send a message to another task
+ will not continue executing until the window procedure that Windows calls to
+ receive the message returns. However, if a task that is called to receive a
+ message needs to perform some type of operation that might yield control
+ (such as calling the %MessageBox% or %DialogBox% functions), Windows could
+ be placed in a deadlock situation where the sending task needs to execute
+ and process messages but cannot because it is waiting for %SendMessage% to
+ return. An application can avoid this problem if the task receiving the
+ message calls %ReplyMessage% before performing any operation that could
+ cause the task to yield.
+
+ The %ReplyMessage% function has no effect if the message was not sent
+ through the %SendMessage% function or if the message was sent by the same
+ task.
+
+ <lReply>
+ Specifies the result of the message processing. The possible values
+ depend on the actual message sent.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32ReplyMessage(PVDMFRAME pFrame)
+{
+ register PREPLYMESSAGE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(REPLYMESSAGE16), parg16);
+
+ ReplyMessage(LONG32(parg16->f1));
+
+ // WARNING - Don't use any 32 bit flat pointers after call to ReplyMessage,
+ // other tasks might have run and made the pointers invalid.
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+
+
+
+
+
+/*++
+ DWORD SendDlgItemMessage(<hDlg>, <nIDDlgItem>, <wMsg>, <wParam>, <lParam>)
+ HWND <hDlg>;
+ int <nIDDlgItem>;
+ WORD <wMsg>;
+ WORD <wParam>;
+ DWORD <lParam>;
+
+ The %SendDlgItemMessage% function sends a message to the control specified
+ by the <nIDDlgItem> parameter within the dialog box specified by the <hDlg>
+ parameter. The %SendDlgItemMessage% function does not return until the
+ message has been processed.
+
+ <hDlg>
+ Identifies the dialog box that contains the control.
+
+ <nIDDlgItem>
+ Specifies the integer identifier of the dialog item that is to
+ receive the message.
+
+ <wMsg>
+ Specifies the message value.
+
+ <wParam>
+ Specifies additional message information.
+
+ <lParam>
+ Specifies additional message information.
+
+ The return value specifies the outcome of the function. It is the value
+ returned by the control's window function, or zero if the control identifier
+ is not valid.
+
+ Using %SendDlgItemMessage% is identical to obtaining a handle to the given
+ control and calling the %SendMessage% function.
+--*/
+
+#define W31EM_GETRECT (WM_USER+2) // w31 EM_GETRECT != NT EM_GETRECT
+
+ULONG FASTCALL WU32SendDlgItemMessage(PVDMFRAME pFrame)
+{
+ HWND hdlg, hwndItem;
+ register PSENDDLGITEMMESSAGE16 parg16;
+ MSGPARAMEX mpex;
+
+static HWND hwndCached = NULL ;
+static DWORD dwCachedItem = 0L ;
+
+ GETARGPTR(pFrame, sizeof(SENDDLGITEMMESSAGE16), parg16);
+
+ // QuarkExpress v3.31 passes a hard coded 7fff:0000 as the pointer to the
+ // RECT struct for EM_GETRECT message - W3.1 rejects it in validation layer
+ if( (DWORD32(parg16->f5) == 0x7FFF0000) &&
+ (WORD32(parg16->f3) == W31EM_GETRECT) &&
+ (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_BOGUSPOINTER) ) {
+
+ FREEARGPTR(parg16);
+ RETURN((ULONG)0);
+ }
+
+ // Need unique handle
+ hdlg = (HWND)FULLHWND32(parg16->f1);
+
+ //
+ // Caching the hwnd for the dialog item because EForm will
+ // call SendDlgItemMessage in a tight loop.
+ //
+ if ( hdlg == hdlgSDIMCached && WORD32(parg16->f2) == dwCachedItem ) {
+
+ // Set from cached
+ hwndItem = hwndCached ;
+ }
+ else {
+ if ( hwndItem = GetDlgItem(hdlg, WORD32(parg16->f2)) ) {
+
+ // and cache needed information
+ hdlgSDIMCached = hdlg ;
+ hwndCached = hwndItem ;
+ dwCachedItem = WORD32(parg16->f2) ;
+ }
+ else {
+ FREEARGPTR(parg16);
+ RETURN((ULONG)0);
+ }
+ }
+
+ mpex.lReturn = 0;
+ if (hwndItem) {
+ mpex.Parm16.WndProc.hwnd = GETHWND16(hwndItem);
+ mpex.Parm16.WndProc.wMsg = WORD32(parg16->f3);
+ mpex.Parm16.WndProc.wParam = WORD32(parg16->f4);
+ mpex.Parm16.WndProc.lParam = LONG32(parg16->f5);
+ mpex.iMsgThunkClass = 0;
+
+ if (ThunkMsg16(&mpex)) {
+
+ // Note: ThunkMsg16 may have caused memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ /*
+ ** Since we already know which window the message is going to
+ ** don't make USER32 look it up again. - MarkRi
+ */
+ mpex.lReturn = SendMessage(hwndItem, mpex.uMsg, mpex.uParam,
+ mpex.lParam);
+
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ (mpex.lpfnUnThunk16)(&mpex);
+ }
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN((ULONG)mpex.lReturn);
+}
+
+
+
+
+
+
+
+/*++
+ DWORD SendMessage(<hwnd>, <msg>, <wParam>, <lParam>)
+ HWND <hwnd>;
+ WORD <msg>;
+ WORD <wParam>;
+ LONG <lParam>;
+
+ The %SendMessage% function sends a message to a window or windows. The
+ %SendMessage% function calls the window procedure for the specified window,
+ and does not return until that window procedure has processed the message.
+ This is in contrast to the %PostMessage% function which places the message
+ into the specified window's message queue and returns immediately.
+
+ <hwnd>
+ Identifies the window that is to receive the message. If this parameter
+ is 0xFFFF (-1), the message is sent to all top-level windows.
+
+ <msg>
+ Specifies the message to be sent.
+
+ <wParam>
+ Specifies additional message information. The contents of this
+ parameter depends on the message being sent.
+
+ <lParam>
+ Specifies additional message information. The contents of this
+ parameter depends on the message being sent.
+
+ The return value is the result returned by the invoked window procedure; its
+ value depends on the message being sent.
+--*/
+
+ULONG FASTCALL WU32SendMessage(PVDMFRAME pFrame)
+{
+ // NOTE: This can be called directly by WU32PostMessage!!!
+
+ HWND hwnd;
+ register PSENDMESSAGE16 parg16;
+ MSGPARAMEX mpex;
+ HWND16 hwndOld;
+ UINT uMsgOld;
+ UINT uParamOld;
+ LONG lParamOld;
+
+ GETARGPTR(pFrame, sizeof(SENDMESSAGE16), parg16);
+
+ hwndOld = parg16->f1;
+ uMsgOld = WORD32(parg16->f2);
+ uParamOld = WORD32(parg16->f3);
+ lParamOld = LONG32(parg16->f4);
+
+ //
+ // Check for funky apps sending WM_SYSCOMMAND - SC_CLOSE to progman
+ //
+ if ( uMsgOld == WM_SYSCOMMAND && uParamOld == SC_CLOSE ) {
+ if ( hwndOld == GETHWND16(hwndProgman) && hwndProgman != (HWND)0 ) {
+ //
+ // Now if shift key is down, they must be trying to save
+ // settings in progman.
+ //
+ if ( GetKeyState( VK_SHIFT ) < 0 ) {
+ uMsgOld = RegisterWindowMessage("SaveSettings");
+ }
+ }
+ }
+
+
+ //
+ // This is for the apps that use DDE protocol wrongly, like AmiPro.
+ //
+
+ fWhoCalled = WOWDDE_POSTMESSAGE;
+
+ mpex.lReturn = 0;
+ mpex.Parm16.WndProc.hwnd = hwndOld;
+ mpex.Parm16.WndProc.wMsg = uMsgOld;
+ mpex.Parm16.WndProc.wParam = uParamOld;
+ mpex.Parm16.WndProc.lParam = lParamOld;
+ mpex.iMsgThunkClass = 0;
+
+ hwnd = ThunkMsg16(&mpex);
+
+ // Note: ThunkMsg16 may have caused memory movement
+ FREEARGPTR(pFrame);
+ FREEARGPTR(parg16);
+
+ fWhoCalled = FALSE;
+
+ if (hwnd) {
+ BlockWOWIdle(TRUE);
+ mpex.lReturn = SendMessage(hwnd, mpex.uMsg, mpex.uParam, mpex.lParam);
+ BlockWOWIdle(FALSE);
+
+ fWhoCalled = WOWDDE_POSTMESSAGE;
+ if (MSG16NEEDSTHUNKING(&mpex)) {
+ (mpex.lpfnUnThunk16)(&mpex);
+ }
+ fWhoCalled = FALSE;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN((ULONG)mpex.lReturn);
+}
+
+
+
+
+
+
+
+/*++
+ BOOL SetMessageQueue(<cMsg>)
+ int <cMsg>;
+
+ The %SetMessageQueue% function creates a new message queue. It is
+ particularly useful in applications that require a queue that contains more
+ than eight messages (the maximum size of the default queue). The <cMsg>
+ parameter specifies the size of the new queue; the function must be called
+ from an application's WinMain function before any windows are created and
+ before any messages are sent. The %SetMessageQueue% function destroys the
+ old queue, along with messages it might contain.
+
+ <cMsg>
+ Specifies the maximum number of messages that the new queue may
+ contain.
+
+ The return value specifies whether a new message queue is created. It is
+ TRUE if the function creates a new queue. Otherwise, it is FALSE.
+
+ If the return value is FALSE, the application has no queue because the
+ %SetMessageQueue% function deletes the original queue before attempting to
+ create a new one. The application must continue calling %SetMessageQueue%
+ with a smaller queue size until the function returns TRUE.
+--*/
+
+ULONG FASTCALL WU32SetMessageQueue(PVDMFRAME pFrame)
+{
+#ifdef ONLY_API16
+ ULONG ul;
+ register PSETMESSAGEQUEUE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETMESSAGEQUEUE16), parg16);
+
+ ul = GETBOOL16(SetMessageQueue(INT32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+#else
+ UNREFERENCED_PARAMETER(pFrame);
+
+ return TRUE; // WIN32 doesn't have sizeable message queues
+#endif
+}
+
+
+
+
+
+
+
+/*++
+ int TranslateAccelerator(<hwnd>, <hAccTable>, <lpMsg>)
+
+ The %TranslateAccelerator% function processes keyboard accelerators for menu
+ commands. The %TranslateAccelerator% function translates WM_KEYUP and
+ WM_KEYDOWN messages to WM_COMMAND or WM_SYSCOMMAND messages, if there is an
+ entry for the key in the application's accelerator table. The high-order
+ word of the <lParam> parameter of the WM_COMMAND or WM_SYSCOMMAND message
+ contains the value 1 to differentiate the message from messages sent by
+ menus or controls.
+
+ WM_COMMAND or WM_SYSCOMMAND messages are sent directly to the window, rather
+ than being posted to the application queue. The %TranslateAccelerator%
+ function does not return until the message is processed.
+
+ Accelerator key strokes that are defined to select items from the system
+ menu are translated into WM_SYSCOMMAND messages; all other accelerators are
+ translated into WM_COMMAND messages.
+
+ <hwnd>
+ Identifies the window whose messages are to be translated.
+
+ <hAccTable>
+ %HANDLE% Identifies an accelerator table (loaded by using the
+ %LoadAccelerators% function).
+
+ <lpMsg>
+ Points to a message retrieved by using the %GetMessage% or
+ %PeekMessage% function. The message must be an %MSG% structure and
+ contain message information from the Windows application queue.
+
+ .cmt
+ 19-Sep-1990 [johnca]
+ Doesn't this function really return a BOOL?
+ .endcmt
+
+ The return value specifies the outcome of the function. It is nonzero if
+ translation occurs. Otherwise, it is zero.
+
+ When %TranslateAccelerator% returns nonzero (meaning that the message is
+ translated), the application should <not> process the message again by using
+ the %TranslateMessage% function.
+
+ Commands in accelerator tables do not have to correspond to menu items.
+
+ If the accelerator command does correspond to a menu item, the application
+ is sent WM_INITMENU and WM_INITMENUPOPUP messages, just as if the user were
+ trying to display the menu. However, these messages are not sent if any of
+ the following conditions are present:
+
+ o The window is disabled.
+
+ o The menu item is disabled.
+
+ o The command is not in the System menu and the window is minimized.
+
+ o A mouse capture is in effect (for more information, see the %SetCapture%
+ function, earlier in this chapter).
+
+ If the window is the active window and there is no keyboard focus (generally
+ true if the window is minimized), then WM_SYSKEYUP and WM_SYSKEYDOWN
+ messages are translated instead of WM_KEYUP and WM_KEYDOWN messages.
+
+ If an accelerator key stroke that corresponds to a menu item occurs when the
+ window that owns the menu is iconic, no WM_COMMAND message is sent. However,
+ if an accelerator key stroke that does not match any of the items on the
+ window's menu or the System menu occurs, a WM_COMMAND message is sent, even
+ if the window is iconic.
+--*/
+
+ULONG FASTCALL WU32TranslateAccelerator(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ MSG t3;
+ register PTRANSLATEACCELERATOR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(TRANSLATEACCELERATOR16), parg16);
+
+ W32CopyMsgStruct(parg16->f3, &t3, TRUE);
+ ul = GETINT16(TranslateAccelerator(HWND32(parg16->f1),
+ HACCEL32(parg16->f2), &t3 ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ BOOL TranslateMDISysAccel(<hwndClient>, <lpMsg>)
+
+ The %TranslateMDISysAccel% function processes keyboard accelerators for
+ multiple document interface (MDI) child window System-menu commands. The
+ %TranslateMDISysAccel% function translates WM_KEYUP and WM_KEYDOWN messages
+ to WM_SYSCOMMAND messages. The high-order word of the <lParam> parameter of
+ the WM_SYSCOMMAND message contains the value 1 to differentiate the message
+ from messages sent by menus or controls.
+
+ <hwndClient>
+ Identifies the parent MDI client window.
+
+ <lpMsg>
+ Points to a message retrieved by using the %GetMessage% or
+ %PeekMessage% function. The message must be an %MSG% structure and
+ contain message information from the Windows application queue.
+
+ The return value is TRUE if the function translated a message into a system
+ command. Otherwise, it is FALSE.
+--*/
+
+ULONG FASTCALL WU32TranslateMDISysAccel(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ MSG t2;
+ register PTRANSLATEMDISYSACCEL16 parg16;
+
+ GETARGPTR(pFrame, sizeof(TRANSLATEMDISYSACCEL16), parg16);
+
+ W32CopyMsgStruct(parg16->f2, &t2, TRUE);
+
+ ul = GETBOOL16(TranslateMDISysAccel(HWND32(parg16->f1), &t2));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ BOOL TranslateMessage(<lpMsg>)
+
+ The %TranslateMessage% function translates virtual-key messages into
+ character messages, as follows:
+
+ o WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or a WM_DEADCHAR
+ message.
+
+ o WM_SYSKEYDOWN/WM_SYSKEYUP combinations produce a WM_SYSCHAR or a
+ WM_SYSDEADCHAR message.
+
+ The character messages are posted to the application queue, to be read the
+ next time the application calls the %GetMessage% or %PeekMessage% function.
+
+ <lpMsg>
+ Points to a %MSG% structure retrieved through the GetMessage or
+ PeekMessage function. The structure contains message information from
+ the Windows application queue.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ message is translated (that is, character messages are posted to the
+ application queue). Otherwise, it is FALSE.
+
+ The %TranslateMessage% function does not modify the message given by the
+ <lpMsg> parameter.
+
+ %TranslateMessage% produces WM_CHAR messages only for keys which are mapped
+ to ASCII characters by the keyboard driver.
+
+ An application should not call %TranslateMessage% if the application
+ processes virtual-key messages for some other purpose. For instance, an
+ application should not call the %TranslateMessage% function if the
+ %TranslateAccelerator% function returns TRUE.
+--*/
+
+ULONG FASTCALL WU32TranslateMessage(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ MSG t1;
+ register PTRANSLATEMESSAGE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(TRANSLATEMESSAGE16), parg16);
+
+ W32CopyMsgStruct(parg16->f1, &t1, TRUE);
+
+ ul = GETBOOL16(TranslateMessage( &t1 ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+
+
+
+/*++
+ void WaitMessage(VOID)
+
+ The %WaitMessage% function yields control to other applications when an
+ application has no other tasks to perform. The %WaitMessage% function
+ suspends the application and does not return until a new message is placed
+ in the application's queue.
+
+ This function has no parameters.
+
+ This function does not return a value.
+
+ The %GetMessage%, %PeekMessage%, and %WaitMessage% functions yield control
+ to other applications. These calls are the only way to let other
+ applications run. If your application does not call any of these functions
+ for long periods of time, other applications cannot run.
+
+ When %GetMessage%, %PeekMessage%, and %WaitMessage% yield control to other
+ applications, the stack and data segments of the application calling the
+ function may move in memory to accommodate the changing memory requirements
+ of other applications. If the application has stored long pointers to
+ objects in the data or stack segment (that is, global or local variables),
+ these pointers can become invalid after a call to %GetMessage%,
+ %PeekMessage%, or %WaitMessage%.
+--*/
+
+ULONG FASTCALL WU32WaitMessage(PVDMFRAME pFrame)
+{
+ UNREFERENCED_PARAMETER(pFrame);
+
+ BlockWOWIdle(TRUE);
+
+ WaitMessage();
+
+ BlockWOWIdle(FALSE);
+
+ RETURN(0);
+}
+
+
+
+
+
+
+
+//----------------------------------------------------------------------------
+// SetFakeDialogClass
+// - mimics USER32 behaviour. If an app calls DefDlgProc, or EndDialog,
+// or MapDialogRect with an hwnd that is not a 'dialog' mark it as a
+// dialog window.
+//
+// This is needed for handling the DWL_DLGPROC constants for GetWindowLong
+// and SetWindowLong.
+//
+// Specifically to support the WINCIM.
+//
+//----------------------------------------------------------------------------
+
+VOID SetFakeDialogClass(HWND hwnd)
+{
+ PWW pww;
+ ULONG ul;
+
+ if (pww = FindPWW(hwnd, WOWCLASS_UNKNOWN)) {
+ if (pww->iClass == WOWCLASS_DIALOG ||
+ pww->flState & WWSTATE_FAKEDIALOGCLASS) {
+ return;
+ }
+ else {
+
+ // mark this hwnd as a dialog
+
+ SETWL(hwnd, GWL_WOWiClassAndflState,
+ MAKECLASSANDSTATE(pww->iClass, pww->flState | WWSTATE_FAKEDIALOGCLASS));
+
+ LOGDEBUG(0, ("WOW:SetFakeDialogClass: fake dialog hwnd = %08lx\n",
+ (ULONG)hwnd));
+
+ ul = GetWindowLong(hwnd, DWL_DLGPROC);
+ if (ul) {
+
+ // current DWL_DLGPROC is non-zero, so assume that the value
+ // is a 16:16 wndproc
+
+ SETWL(hwnd, GWL_WOWvpfnDlgProc, ul);
+ ul = SetWindowLong(hwnd, DWL_DLGPROC, (LONG)W32DialogFunc);
+ }
+ else {
+
+ // current DWL_DLGPROC is NULL, nothing to do
+
+ WOW32ASSERT(pww->vpfnDlgProc == (VPWNDPROC)NULL);
+ }
+
+
+ }
+ }
+
+ return;
+
+}
diff --git a/private/mvdm/wow32/wumsg.h b/private/mvdm/wow32/wumsg.h
new file mode 100644
index 000000000..a7867bfe5
--- /dev/null
+++ b/private/mvdm/wow32/wumsg.h
@@ -0,0 +1,43 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUMSG.H
+ * WOW32 16-bit User Message API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+#define WOWDDE_POSTMESSAGE TRUE
+
+extern BOOL fWhoCalled;
+
+ULONG FASTCALL WU32CallMsgFilter(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CallWindowProc(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DefDlgProc(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DefFrameProc(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DefMDIChildProc(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DefWindowProc(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DispatchMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetMessagePos(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetMessageTime(PVDMFRAME pFrame);
+ULONG FASTCALL WU32InSendMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32PeekMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32PostAppMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32PostMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32PostQuitMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32RegisterWindowMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ReplyMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SendDlgItemMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SendMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetMessageQueue(PVDMFRAME pFrame);
+ULONG FASTCALL WU32TranslateAccelerator(PVDMFRAME pFrame);
+ULONG FASTCALL WU32TranslateMDISysAccel(PVDMFRAME pFrame);
+ULONG FASTCALL WU32TranslateMessage(PVDMFRAME pFrame);
+ULONG FASTCALL WU32WaitMessage(PVDMFRAME pFrame);
+
+VOID SetFakeDialogClass(HWND hwnd);
diff --git a/private/mvdm/wow32/wuser.c b/private/mvdm/wow32/wuser.c
new file mode 100644
index 000000000..e9d171d0a
--- /dev/null
+++ b/private/mvdm/wow32/wuser.c
@@ -0,0 +1,3555 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUSER.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#define OEMRESOURCE
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+MODNAME(wuser.c);
+
+extern HANDLE hmodWOW32;
+
+
+/*++
+ HDC BeginPaint(<hwnd>, <lpPaint>)
+ HWND <hwnd>;
+ LPPAINTSTRUCT <lpPaint>;
+
+ The %BeginPaint% function prepares the given window for painting and fills
+ the paint structure pointed to by the <lpPaint> parameter with information
+ about the painting.
+
+ The paint structure contains a handle to the device context for the window,
+ a %RECT% structure that contains the smallest rectangle that completely
+ encloses the update region, and a flag that specifies whether or not the
+ background has been erased.
+
+ The %BeginPaint% function automatically sets the clipping region of the
+ device context to exclude any area outside the update region. The update
+ region is set by the %InvalidateRect% or %InvalidateRgn% functions and by
+ the system after sizing, moving, creating, scrolling, or any other operation
+ that affects the client area. If the update region is marked for erasing,
+ %BeginPaint% sends a WM_ERASEBKGND message to the window.
+
+ An application should not call the %BeginPaint% function except in response
+ to a WM_PAINT message. Each %BeginPaint% call must have a matching call to
+ the %EndPaint% function.
+
+ <hwnd>
+ Identifies the window to be repainted.
+
+ <lpPaint>
+ Points to the %PAINTSTRUCT% structure that is to receive painting
+ information, such as the device context for the window and the update
+ rectangle.
+
+ The return value identifies the device context for the specified window.
+
+ If the caret is in the area to be painted, the %BeginPaint% function
+ automatically hides the caret to prevent it from being erased.
+--*/
+
+ULONG FASTCALL WU32BeginPaint(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PAINTSTRUCT t2;
+ register PBEGINPAINT16 parg16;
+ VPVOID vpPaint;
+
+ GETARGPTR(pFrame, sizeof(BEGINPAINT16), parg16);
+ vpPaint = parg16->vpPaint;
+
+ ul = GETHDC16(BeginPaint(
+ HWND32(parg16->hwnd),
+ &t2
+ ));
+
+ putpaintstruct16(vpPaint, &t2);
+ W32FixPaintRect (vpPaint, &t2);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HICON CreateIcon(<hInstance>, <nWidth>, <nHeight>, <nPlanes>,
+ <nBitsPixel>, <lpANDbits>, <lpXORbits>)
+ HANDLE <hInstance>;
+ int <nWidth>;
+ int <nHeight>;
+ BYTE <nPlanes>;
+ BYTE <nBitsPixel>;
+ LPSTR <lpANDbits>;
+ LPSTR <lpXORbits>;
+
+ This function creates an icon that has specified width, height, colors, and
+ bit patterns.
+
+ <hInstance>
+ Identifies an instance of the module creating the icon.
+
+ <nWidth>
+ Specifies the width in pixels of the icon.
+
+ <nHeight>
+ Specifies the height in pixels of the icon.
+
+ <nPlanes>
+ Specifies the number of planes in the XOR mask of the icon.
+
+ <nBitsPixel>
+ Specifies the number of bits per pixel in the XOR mask of the icon.
+
+ <lpANDbits>
+ Points to an array of bytes that contains the bit values for the AND
+ mask of the icon. This array must specify a monochrome mask.
+
+ <lpXORbits>
+ Points to an array of bytes that contains the bit values for the XOR
+ mask of the icon. This can be the bits of a monochrome or
+ device-dependent color bitmap.
+
+ The return value identifies an icon if the function is successful.
+ Otherwise, it is NULL.
+--*/
+
+ULONG FASTCALL WU32CreateIcon(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PCREATEICON16 parg16;
+ int nWidth;
+ int nHeight;
+ BYTE nPlanes;
+ BYTE nBitsPixel;
+ DWORD nBytesAND;
+ DWORD nBytesXOR;
+ LPBYTE lpBitsAND;
+ LPBYTE lpBitsXOR;
+ int ScanLen16;
+
+ HANDLE h32;
+ HAND16 h16;
+ HAND16 hInst16;
+
+ GETARGPTR(pFrame, sizeof(CREATEICON16), parg16);
+
+ hInst16 = parg16->f1;
+ nWidth = INT32(parg16->f2);
+ nHeight = INT32(parg16->f3);
+
+ /*
+ ** Convert the AND mask bits
+ */
+ nPlanes = 1; /* MONOCHROME BITMAP */
+ nBitsPixel = 1; /* MONOCHROME BITMAP */
+ ScanLen16 = (((nWidth*nBitsPixel)+15)/16) * 2 ; // bytes/scan in 16 bit world
+ nBytesAND = ScanLen16*nHeight*nPlanes;
+
+ GETVDMPTR(parg16->f6, nBytesAND, lpBitsAND);
+
+
+ /*
+ ** Convert the XOR mask bits
+ */
+ nPlanes = BYTE32(parg16->f4);
+ nBitsPixel = BYTE32(parg16->f5);
+
+ ScanLen16 = (((nWidth*nBitsPixel)+15)/16) * 2 ; // bytes/scan in 16 bit world
+ nBytesXOR = ScanLen16*nHeight*nPlanes;
+
+ GETVDMPTR(parg16->f7, nBytesXOR, lpBitsXOR);
+
+
+ h32 = (HANDLE)CreateIcon(HMODINST32(hInst16),
+ nWidth,
+ nHeight,
+ nPlanes,
+ nBitsPixel,
+ lpBitsAND,
+ lpBitsXOR);
+
+ if (h32) {
+ h16 = (HAND16)W32Create16BitCursorIcon(hInst16,
+ nWidth/2, nHeight/2,
+ nWidth, nHeight, nPlanes, nBitsPixel,
+ lpBitsAND, lpBitsXOR,
+ nBytesAND, nBytesXOR);
+
+ ul = SetupCursorIconAlias(hInst16, h32, h16,
+ HANDLE_TYPE_ICON, NULL, (WORD)NULL);
+ } else {
+ ul = 0;
+ }
+
+ FREEPSZPTR(lpBitsAND);
+ FREEPSZPTR(lpBitsXOR);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL DestroyIcon(<hIcon>)
+ HICON <hIcon>;
+
+ This function destroys an icon that was previously created by the
+ %CreateIcon% function and frees any memory that the icon occupied. It should
+ not be used to destroy any icon that was not created with the %CreateIcon%
+ function.
+
+ <hIcon>
+ Identifies the icon to be destroyed. The icon must not be in current
+ use.
+
+ The return value is TRUE if the function was successful. It is FALSE if
+ the function failed.
+--*/
+
+ULONG FASTCALL WU32DestroyIcon(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDESTROYICON16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DESTROYICON16), parg16);
+
+ if (ul = GETBOOL16(DestroyIcon(HICON32(parg16->f1))))
+ FREEHICON16(parg16->f1);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32DragObject(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDRAGOBJECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DRAGOBJECT16), parg16);
+
+ ul = (ULONG) DragObject(HWND32(parg16->f1),
+ HWND32(parg16->f2),
+ UINT32(parg16->f3),
+ DWORD32(parg16->f4),
+ HCURSOR32(parg16->f5)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32DragDetect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT pt;
+ register PDRAGDETECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(*parg16), parg16);
+ COPYPOINT16(parg16->pt, pt);
+
+ ul = (ULONG) DragDetect(
+ HWND32(parg16->hwnd),
+ pt
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/*++
+ void DrawFocusRect(<hDC>, <lpRect>)
+ HDC <hDC>;
+ LPRECT <lpRect>;
+
+ The %DrawFocusRect% function draws a rectangle in the style used to indicate
+ focus.
+
+ <hDC>
+ Identifies the device context.
+
+ <lpRect>
+ Points to a %RECT% structure that specifies the
+ coordinates of the rectangle to be drawn.
+
+ This function does not return a value.
+
+ Since this is an XOR function, calling this function a second time with the
+ same rectangle removes the rectangle from the display.
+
+ The rectangle drawn by this function cannot be scrolled. To scroll an area
+ containing a rectangle drawn by this function, call %DrawFocusRect% to
+ remove the rectangle from the display, scroll the area, and then call
+ %DrawFocusRect% to draw the rectangle in the new position.
+--*/
+
+ULONG FASTCALL WU32DrawFocusRect(PVDMFRAME pFrame)
+{
+ RECT t2;
+ register PDRAWFOCUSRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DRAWFOCUSRECT16), parg16);
+
+ WOW32VERIFY(GETRECT16(parg16->f2, &t2));
+
+ DrawFocusRect(
+ HDC32(parg16->f1),
+ &t2
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ BOOL DrawIcon(<hDC>, <X>, <Y>, <hIcon>)
+ HDC <hDC>;
+ int <X>;
+ int <Y>;
+ HICON <hIcon>;
+
+ The %DrawIcon% function draws an icon on the specified device. The
+ %DrawIcon% function places the icon's upper-left corner at the location
+ specified by the <X> and <Y> parameters. The location is subject to the
+ current mapping mode of the device context.
+
+ <hDC>
+ Identifies the device context for a window.
+
+ <X>
+ Specifies the logical <x>-coordinate of the upper-left corner of
+ the icon.
+
+ <Y>
+ Specifies the logical <y>-coordinate of the upper-left corner of
+ the icon.
+
+ <hIcon>
+ Identifies the icon to be drawn.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function is successful. Otherwise, it is FALSE.
+
+ The icon resource must have been previously loaded by using the %LoadIcon%
+ function. The MM_TEXT mapping mode must be selected prior to using this
+ function.
+--*/
+
+ULONG FASTCALL WU32DrawIcon(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDRAWICON16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DRAWICON16), parg16);
+
+ ul = GETBOOL16(DrawIcon(
+ HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ HICON32(parg16->f4)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int DrawText(<hDC>, <lpString>, <nCount>, <lpRect>, <wFormat>)
+ HDC <hDC>;
+ LPSTR <lpString>;
+ int <nCount>;
+ LPRECT <lpRect>;
+ WORD <wFormat>;
+
+ The %DrawText% function draws formatted text in the rectangle specified by
+ the <lpRect> parameter. It formats text by expanding tabs into appropriate
+ spaces, justifying text to the left, right, or center of the given
+ rectangle, and breaking text into lines that fit within the given
+ rectangle. The type of formatting is specified by the <wFormat> parameter.
+
+ The %DrawText% function uses the device context's selected font, text color,
+ and background color to draw the text. Unless the DT_NOCLIP format is used,
+ %DrawText% clips the text so that the text does not appear outside the given
+ rectangle. All formatting is assumed to have multiple lines unless the
+ DT_SINGLELINE format is given.
+
+ <hDC>
+ Identifies the device context.
+
+ <lpString>
+ Points to the string to be drawn. If the <nCount> parameter is -1, the
+ string must be null-terminated.
+
+ <nCount>
+ Specifies the number of bytes in the string. If <nCount> is -1,
+ then <lpString> is assumed to be a long pointer to a null-terminated
+ string and %DrawText% computes the character count automatically.
+
+ <lpRect>
+ Points to a %RECT% structure that contains the rectangle
+ (in logical coordinates) in which the text is to be formatted.
+
+ <wFormat>
+ Specifies the method of formatting the text. It can be any
+ combination of the following values:
+
+ DT_BOTTOM
+ Specifies bottom-justified text. This value must be combined with
+ DT_SINGLELINE.
+
+ DT_CALCRECT
+ Determines the width and height of the rectangle. If there are multiple
+ lines of text, %DrawText% will use the width of the rectangle pointed to
+ by the <lpRect> parameter and extend the base of the rectangle to bound
+ the last line of text. If there is only one line of text, %DrawText%
+ will modify the right side of the rectangle so that it bounds the last
+ character in the line. In either case, %DrawText% returns the height of
+ the formatted text but does not draw the text.
+
+ DT_CENTER
+ Centers text horizontally.
+
+ DT_EXPANDTABS
+ Expands tab characters. The default number of characters per tab is
+ eight.
+
+ DT_EXTERNALLEADING
+ Includes the font external leading in line height. Normally, external
+ leading is not included in the height of a line of text.
+
+ DT_LEFT
+ Aligns text flush-left.
+
+ DT_NOCLIP
+ Draws without clipping. %DrawText% is somewhat faster when DT_NOCLIP is
+ used.
+
+ DT_NOPREFIX
+ Turns off processing of prefix characters. Normally, %DrawText%
+ interprets the mnemonic-prefix character & as a directive to
+ underscore the character that follows, and the mnemonic-prefix
+ characters && as a directive to print a single &. By specifying
+ DT_NOPREFIX, this processing is turned off.
+
+ DT_RIGHT
+ Aligns text flush-right.
+
+ DT_SINGLELINE
+ Specifies single line only. Carriage returns and linefeeds do not break
+ the line.
+
+ DT_TABSTOP
+ Sets tab stops. The high-order byte of the <wFormat> parameter is the
+ number of characters for each tab. The default number of characters per
+ tab is eight.
+
+ DT_TOP
+ Specifies top-justified text (single line only).
+
+ DT_VCENTER
+ Specifies vertically centered text (single line only).
+
+ DT_WORDBREAK
+ Specifies word breaking. Lines are automatically broken between words if
+ a word would extend past the edge of the rectangle specified by the
+ <lpRect> parameter. A carriage return/line sequence will also break the
+ line.
+
+ Note that the DT_CALCRECT, DT_EXTERNALLEADING, DT_INTERNAL, DT_NOCLIP,
+ and DT_NOPREFIX values cannot be used with the DT_TABSTOP value:
+
+ The return value specifies the height of the text.
+
+ If the selected font is too large for the specified rectangle, the
+ %DrawText% function does not attempt to substitute a smaller font.
+--*/
+
+ULONG FASTCALL WU32DrawText(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSTR pstr2;
+ RECT t4;
+ register PDRAWTEXT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DRAWTEXT16), parg16);
+ GETVARSTRPTR(parg16->vpString, INT32(parg16->nCount), pstr2);
+
+ WOW32VERIFY(GETRECT16(parg16->vpRect, &t4));
+
+ ul = GETINT16(DrawText(
+ HDC32(parg16->hdc),
+ pstr2,
+ INT32(parg16->nCount),
+ &t4,
+ WORD32(parg16->wFormat)
+ ));
+
+ PUTRECT16(parg16->vpRect, &t4);
+
+ FREESTRPTR(pstr2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL EnableHardwareInput(<bEnableInput>)
+ BOOL <bEnableInput>;
+
+ The %EnableHardwareInput% function disables mouse and keyboard input. The
+ input is saved if the <bEnableInput> parameter is TRUE and discarded if it
+ is FALSE.
+
+ <bEnableInput>
+ Specifies that the function should save input if the bEnableInput
+ parameter is set to a nonzero value; specifies that the function should
+ discard input if the bEnableInput parameter is set to zero.
+
+ The return value specifies whether mouse and keyboard input is disabled. It
+ is TRUE if input was previously enabled. Otherwise, it is FALSE. The
+ default return value is TRUE.
+--*/
+
+ULONG FASTCALL WU32EnableHardwareInput(PVDMFRAME pFrame)
+{
+#ifdef ONLY_API16
+ ULONG ul;
+ register PENABLEHARDWAREINPUT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENABLEHARDWAREINPUT16), parg16);
+
+ ul = GETBOOL16(EnableHardwareInput(
+ BOOL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+#else
+ UNREFERENCED_PARAMETER(pFrame);
+
+ return TRUE;
+#endif
+
+}
+
+
+/*++
+ void EndPaint(<hwnd>, <lpPaint>)
+ HWND <hwnd>;
+ LPPAINTSTRUCT <lpPaint>;
+
+ The %EndPaint% function marks the end of painting in the given window. The
+ %EndPaint% function is required for each call to the %BeginPaint% function,
+ but only after painting is complete.
+
+ <hwnd>
+ Identifies the window that is repainted.
+
+ <lpPaint>
+ Points to a %PAINTSTRUCT% structure that contains the painting
+ information retrieved by the %BeginPaint% function.
+
+ This function does not return a value.
+
+ If the caret was hidden by the %BeginPaint% function, %EndPaint% restores
+ the caret to the screen.
+--*/
+
+ULONG FASTCALL WU32EndPaint(PVDMFRAME pFrame)
+{
+ PAINTSTRUCT t2;
+ register PENDPAINT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENDPAINT16), parg16);
+ getpaintstruct16(parg16->vpPaint, &t2);
+
+ EndPaint(
+ HWND32(parg16->hwnd),
+ &t2
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+#define MAX_WIN16_PROP_TEXT 256 /* Taken from Win 3.1 - winprops.c */
+
+static VPVOID vpEnumPropsProc;
+static VPVOID vpString;
+
+INT W32EnumPropsFunc( HWND hwnd, LPSTR lpString, HANDLE hData )
+{
+ PARM16 Parm16;
+ LONG lReturn;
+ VPVOID vp;
+
+ if ( HIWORD(lpString) == 0 ) {
+ vp = (DWORD)lpString;
+ } else {
+ INT cb;
+
+ vp = vpString;
+ cb = strlen(lpString)+1;
+ if ( cb > MAX_WIN16_PROP_TEXT-1 ) {
+ cb = MAX_WIN16_PROP_TEXT-1;
+ }
+ putstr16(vpString, lpString, cb);
+ }
+
+ Parm16.EnumPropsProc.hwnd = GETHWND16(hwnd);
+ Parm16.EnumPropsProc.vpString = vp;
+ Parm16.EnumPropsProc.hData = GETHANDLE16(hData);
+
+ CallBack16(RET_ENUMPROPSPROC, &Parm16, vpEnumPropsProc, (PVPVOID)&lReturn);
+
+ return (SHORT)lReturn;
+}
+
+/*++
+ int EnumProps(<hwnd>, <lpEnumFunc>)
+ HWND <hwnd>;
+ FARPROC <lpEnumFunc>;
+
+ The %EnumProps% function enumerates all entries in the property list of the
+ specified window. It enumerates the entries by passing them, one by one, to
+ the callback function specified by <lpEnumFunc>. %EnumProps% continues until
+ the last entry is enumerated or the callback function returns zero.
+
+ <hwnd>
+ Identifies the window whose property list is to be enumerated.
+
+ <lpEnumFunc>
+ Specifies the procedure-instance address of the callback function.
+ See the following Comments section for details.
+
+ The return value specifies the last value returned by the callback function.
+ It is -1 if the function did not find a property for enumeration.
+
+ An application can remove only those properties which it has added. It
+ should not remove properties added by other applications or by Windows
+ itself.
+
+ The following restrictions apply to the callback function:
+
+ 1 The callback function must not yield control or do anything that might
+ yield control to other tasks.
+
+ 2 The callback function can call the %RemoveProp% function. However, the
+ %RemoveProp% function can remove only the property passed to the
+ callback function through the callback function's parameters.
+
+ 3 A callback function should not attempt to add properties.
+
+ The address passed in the <lpEnumFunc> parameter must be created by using
+ the %MakeProcInstance% function.
+
+ Fixed Data Segments:
+
+ The callback function must use the Pascal calling convention and must be
+ declared %FAR%. In applications and dynamic libraries with fixed data
+ segments and in dynamic libraries with moveable data segments that do not
+ contain a stack, the callback function must have the form shown below.
+
+ Callback Function:
+
+ int FAR PASCAL <EnumFunc>(<hwnd>, <lpString>, <hData>)
+ HWND <hwnd>;
+ LPSTR <lpString>;
+ HANDLE <hData>;
+
+ <EnumFunc> is a placeholder for the application-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the application's module-definition file.
+
+ <hwnd>
+ Identifies a handle to the window that contains the property list.
+
+ <lpString>
+ Points to the null-terminated string associated with the data handle
+ when the application called the%SetProp% function to set the property.
+ If the application passed an atom instead of a string to the %SetProp%
+ function, the<lpString> parameter contains the atom in its low-order
+ word, and the high-order word is zero.
+
+ <hData>
+ Identifies the data handle.
+
+ The callback function can carry out any desired task. It must return a
+ nonzero value to continue enumeration, or a zero value to stop it.
+
+ Moveable Data Segments:
+
+ The callback function must use the Pascal calling convention and must be
+ declared %FAR%. In applications with moveable data segments and in dynamic
+ libraries whose moveable data segments also contain a stack, the callback
+ function must have the form shown below.
+
+ Callback Function:
+
+ int FAR PASCAL <EnumFunc>(<hwnd>, <nDummy>, <pString>, <hData>)
+ HWND <hwnd>;
+ WORD <nDummy>;
+ PSTR <pString>;
+ HANDLE <hData>;
+
+ <EnumFunc> is a placeholder for the application-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the application's module-definition file.
+
+ <hwnd>
+ Identifies a handle to the window that contains the property list.
+
+ <nDummy>
+ Specifies a dummy parameter.
+
+ <pString>
+ Points to the null-terminated string associated with the data handle
+ when the application called the %SetProp% function to set the property.
+ If the application passed an atom instead of a string to the %SetProp%
+ function, the <pString> parameter contains the atom.
+
+ <hData>
+ Identifies the data handle.
+
+ The callback function can carry out any desired task. It should return a
+ nonzero value to continue enumeration, or a zero value to stop it.
+
+ The alternate form above is required since movement of the data will
+ invalidate any long pointer to a variable on the stack, such as the
+ <lpString> parameter. The data segment typically moves if the callback
+ function allocates more space in the local heap than is currently
+ available.
+--*/
+
+ULONG FASTCALL WU32EnumProps(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ HWND hwnd;
+ register PENUMPROPS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENUMPROPS16), parg16);
+
+ hwnd = HWND32(parg16->f1);
+ vpEnumPropsProc = parg16->f2;
+
+ vpString = malloc16(MAX_WIN16_PROP_TEXT);
+ // 16-bit memory may have moved - invalidate flat pointers
+ FREEARGPTR(parg16);
+ FREEVDMPTR(pFrame);
+
+ if (vpString) {
+ ul = GETINT16(EnumProps(hwnd,(PROPENUMPROC)W32EnumPropsFunc));
+ free16(vpString);
+
+ } else {
+ ul = (ULONG)-1;
+ }
+
+ RETURN(ul);
+}
+
+
+
+/*++
+ int ExcludeUpdateRgn(<hDC>, <hwnd>)
+ HANDLE <hDC>;
+ HWND <hwnd>;
+
+ The %ExcludeUpdateRgn% function prevents drawing within invalid areas of a
+ window by excluding an updated region in the window from a clipping region.
+
+ <hDC>
+ Identifies the device context associated with the clipping region.
+
+ <hwnd>
+ Identifies the window being updated.
+
+ The return value is the type of excluded region. It can be any one of the
+ following values:
+
+ COMPLEXREGION The region has overlapping borders.
+ ERROR No region was created.
+ NULLREGION The region is empty.
+ SIMPLEREGION The region has no overlapping borders.
+--*/
+
+ULONG FASTCALL WU32ExcludeUpdateRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PEXCLUDEUPDATERGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(EXCLUDEUPDATERGN16), parg16);
+
+ ul = GETINT16(ExcludeUpdateRgn(
+ HDC32(parg16->f1),
+ HWND32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/*++
+ int FillWindow(<hWndParent>, <hWnd>, <hDC>, <hBrush>)
+ HWND <hWndParent>;
+ HWND <hWnd>;
+ HDC <hDC>;
+ HBRUSH <hBrush>;
+
+ The %FillWindow% function paints a given window by using the specified
+ brush.
+
+ <hWndParent>
+ Identifies the parent of the window to be painted.
+
+ <hWnd>
+ Identifies the window to be painted.
+
+ <hDC>
+ Identifies the device context.
+
+ <hBrush>
+ Identifies the brush used to fill the rectangle.
+
+--*/
+
+ULONG FASTCALL WU32FillWindow(PVDMFRAME pFrame)
+{
+ register PFILLWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(FILLWINDOW16), parg16);
+
+ (pfnOut.pfnFillWindow)(
+ HWND32(parg16->f1),
+ HWND32(parg16->f2),
+ HDC32(parg16->f3),
+ HBRUSH32(parg16->f4)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ int FillRect(<hDC>, <lpRect>, <hBrush>)
+ HDC <hDC>;
+ LPRECT <lpRect>;
+ HBRUSH <hBrush>;
+
+ The %FillRect% function fills a given rectangle by using the specified
+ brush. The %FillRect% function fills the complete rectangle, including the
+ left and top borders, but does not fill the right and bottom borders.
+
+ <hDC>
+ Identifies the device context.
+
+ <lpRect>
+ Points to a %RECT% structure that contains the logical
+ coordinates of the rectangle to be filled.
+
+ <hBrush>
+ Identifies the brush used to fill the rectangle.
+
+ Although the %FillRect% function return type is an integer, the return value
+ is not used and has no meaning.
+
+ The brush must have been created previously by using either the
+ %CreateHatchBrush%, %CreatePatternBrush%, or %CreateSolidBrush% function, or
+ retrieved using the %GetStockObject% function.
+
+ When filling the specified rectangle, the %FillRect% function does not
+ include the rectangle's right and bottom sides. GDI fills a rectangle up to,
+ but does not include, the right column and bottom row, regardless of the
+ current mapping mode.
+
+ %FillRect% compares the values of the %top%, %bottom%, %left%, and %right%
+ members of the specified rectangle. If %bottom% is less than or equal to
+ %top%, or if %right% is less than or equal to %left%, the rectangle is not
+ drawn.
+--*/
+
+ULONG FASTCALL WU32FillRect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t2;
+ register PFILLRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(FILLRECT16), parg16);
+
+ WOW32VERIFY(GETRECT16(parg16->f2, &t2));
+
+ ul = GETINT16(FillRect(
+ HDC32(parg16->f1),
+ &t2,
+ HBRUSH32(parg16->f3)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int FrameRect(<hDC>, <lpRect>, <hBrush>)
+ HDC <hDC>;
+ LPRECT <lpRect>;
+ HBRUSH <hBrush>;
+
+ The %FrameRect% function draws a border around the rectangle specified by
+ the <lpRect> parameter. The %FrameRect% function uses the given brush to
+ draw the border. The width and height of the border is always one logical
+ unit.
+
+ <hDC>
+ Identifies the device context of the window.
+
+ <lpRect>
+ Points to a %RECT% structure that contains the logical
+ coordinates of the upper-left and lower-right corners of the rectangle.
+
+ <hBrush>
+ Identifies the brush to be used for framing the rectangle.
+
+ Although the return value type is integer, its contents should be ignored.
+
+ The brush identified by the <hBrush> parameter must have been created
+ previously by using the %CreateHatchBrush%, %CreatePatternBrush%, or
+ %CreateSolidBrush% function.
+
+ If the %bottom% member is less than or equal to the %top% member, or if the
+ %right% member is less than or equal to the %left% member, the rectangle is
+ not drawn.
+--*/
+
+ULONG FASTCALL WU32FrameRect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t2;
+ register PFRAMERECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(FRAMERECT16), parg16);
+
+ WOW32VERIFY(GETRECT16(parg16->f2, &t2));
+
+ ul = GETINT16(FrameRect(
+ HDC32(parg16->f1),
+ &t2,
+ HBRUSH32(parg16->f3)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int GetAsyncKeyState(<vKey>)
+ int <vKey>;
+
+ The %GetAsyncKeyState% function determines whether a key is up or down at
+ the time the function is called, and whether the key was pressed after a
+ previous call to the %GetAsyncKeyState% function. If the most significant
+ bit of the return value is set, the key is currently down; if the least
+ significant bit is set, the key was pressed after a previous call to the
+ function.
+
+ <vKey>
+ Specifies one of 256 possible virtual-key code values.
+
+ The return value specifies whether the key was pressed since the last call
+ to %GetAsyncKeyState% and whether the key is currently up or down. If the
+ most significant bit is set, the key is down, and if the least significant
+ bit is set, the key was pressed after a preceding %GetAsyncKeyState% call.
+--*/
+
+ULONG FASTCALL WU32GetAsyncKeyState(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETASYNCKEYSTATE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETASYNCKEYSTATE16), parg16);
+
+ ul = GETINT16(GetAsyncKeyState(
+ INT32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HWND GetCapture(VOID)
+
+ The %GetCapture% function retrieves a handle that identifies the window that
+ has the mouse capture. Only one window has the mouse capture at any given
+ time; this window receives mouse input whether or not the cursor is within
+ its borders.
+
+ This function has no parameters.
+
+ The return value identifies the window that has the mouse capture; it is
+ NULL if no window has the mouse capture.
+
+ A window receives the mouse capture when its handle is passed as the <hwnd>
+ parameter of the %SetCapture% function.
+--*/
+
+ULONG FASTCALL WU32GetCapture(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETHWND16(GetCapture());
+
+ RETURN(ul);
+}
+
+
+/*++
+ HDC GetDC(<hwnd>)
+ HWND <hwnd>;
+
+ The %GetDC% function retrieves a handle to a display context for the client
+ area of the given window. The display context can be used in subsequent GDI
+ functions to draw in the client area.
+
+ The %GetDC% function retrieves a common, class, or private display context
+ depending on the class style specified for the given window. For common
+ display contexts, %GetDC% assigns default attributes to the context each
+ time it is retrieved. For class and private contexts, %GetDC% leaves the
+ previously assigned attributes unchanged.
+
+ <hwnd>
+ Identifies the window whose display context is to be retrieved.
+
+ The return value identifies the display context for the given window's
+ client area if the function is successful. Otherwise, it is NULL.
+
+ After painting with a common display context, the %ReleaseDC% function must
+ be called to release the context. Class and private display contexts do not
+ have to be released. Since only five common display contexts are available
+ at any given time, failure to release a display context can prevent other
+ applications from accessing a display context.
+--*/
+
+ULONG FASTCALL WU32GetDC(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETDC16 parg16;
+ HAND16 htask16 = pFrame->wTDB;
+
+ GETARGPTR(pFrame, sizeof(GETDC16), parg16);
+
+ if (CACHENOTEMPTY()) {
+ ReleaseCachedDCs(htask16, parg16->f1, 0, 0, SRCHDC_TASK16_HWND16);
+ }
+
+ CURRENTPTD()->ulLastDesktophDC = 0;
+
+ ul = GETHDC16(GetDC(
+ HWND32(parg16->f1)
+ ));
+
+ if (ul) {
+// Some apps such as MSWORKS and MS PUBLISHER use some wizard code that accepts
+// a hDC or a hWnd as a parameter and attempt to figure out what type of handle
+// it is by using the IsWindow() call. Since both handles come from different
+// handle spaces they may end up the same value and this wizard code will end
+// up writing to the DC for a random window. By ORing in a 1 we ensure that the
+// handle types will never share the same value since all hWnds are even. Note
+// that this hack is also made in WG32CreateCompatibleDC()
+//
+// Note that there are some apps that use the lower 2 bits of the hDC for their
+// own purposes.
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_UNIQUEHDCHWND) {
+ ul = ul | 1;
+ } else if ((CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_FIXDCFONT4MENUSIZE) &&
+ (parg16->f1 == 0)) {
+// WP tutorial assumes that the font selected in the hDC for desktop window
+// (ie, result of GetDC(NULL)) is the same font as the font selected for
+// drawing the menu. Unfortunetly in SUR this is not true as the user can
+// select any font for the menu. So we remember the hDC returned for GetDC(0)
+// and check for it in GetTextExtentPoint. If the app does try to use it we
+// find the hDC for the current menu window and substitute that. When the app
+// does another GetDC or ReleaseDC we forget the hDC returned for the original
+// GetDC(0).
+ CURRENTPTD()->ulLastDesktophDC = ul;
+ }
+
+
+
+ StoreDC(htask16, parg16->f1, (HAND16)ul);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ WORD GetDoubleClickTime(VOID)
+
+ The %GetDoubleClickTime% function retrieves the current double-click time
+ for the mouse. A double-click is a series of two clicks of the mouse button,
+ the second occurring within a specified time after the first. The
+ double-click time is the maximum number of milliseconds that may occur
+ between the first and second click of a double-click.
+
+ This function has no parameters.
+
+ The return value specifies the current double-click time (in milliseconds).
+--*/
+
+ULONG FASTCALL WU32GetDoubleClickTime(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETWORD16(GetDoubleClickTime());
+
+ RETURN(ul);
+}
+
+
+/*++
+ HWND GetFocus(VOID)
+
+ The %GetFocus% function retrieves the handle of the window that currently
+ owns the input focus.
+
+ This function has no parameters.
+
+ The return value identifies the window that currently owns the focus if the
+ function is successful. Otherwise, it is NULL.
+--*/
+
+ULONG FASTCALL WU32GetFocus(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETHWND16(GetFocus());
+
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL GetInputState(VOID)
+
+ The %GetInputState% function determines whether there are mouse, keyboard,
+ or timer events in the system queue that require processing. An event is a
+ record that describes interrupt-level input. Mouse events occur when a user
+ moves the mouse or clicks a mouse button. Keyboard events occur when a user
+ presses one or more keys. Timer events occur after a specified number of
+ clock ticks. The system queue is the location in which Windows stores mouse,
+ keyboard, and timer events.
+
+ This function has no parameters.
+
+ The return value specifies whether mouse, keyboard or timer input occurs. It
+ is TRUE if input is detected. Otherwise, it is FALSE.
+--*/
+
+ULONG FASTCALL WU32GetInputState(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETBOOL16(GetInputState());
+
+ RETURN(ul);
+}
+
+
+/*++
+ HWND GetLastActivePopup(<hwndOwner>)
+ HWND <hwndOwner>;
+
+ The %GetLastActivePopup% function determines which pop-up window owned by
+ the window identified by the <hwndOwner> parameter was most recently active.
+
+ <hwndOwner>
+ Identifies the owner window.
+
+ The return value identifies the most-recently active pop-up window. The
+ return value will be <hwndOwner> if any of the following conditions are
+ met:
+
+ o The window identified by <hwndOwner> itself was most recently active.
+
+ o The window identified by <hwndOwner> does not own any pop-up windows.
+
+ o The window identified by <hwndOwner> is not a top-level window or is
+ owned by another window.
+--*/
+
+ULONG FASTCALL WU32GetLastActivePopup(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETLASTACTIVEPOPUP16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETLASTACTIVEPOPUP16), parg16);
+
+ ul = GETHWND16(GetLastActivePopup(HWND32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HANDLE GetProp(<hwnd>, <lpString>)
+ HWND <hwnd>;
+ LPSTR <lpString>;
+
+ The %GetProp% function retrieves a data handle from the property list of the
+ specified window. The character string pointed to by the <lpString>
+ parameter identifies the handle to be retrieved. The string and handle are
+ assumed to have been added to the property list by using the %SetProp%
+ function.
+
+ <hwnd>
+ Identifies the window whose property list is to be searched.
+
+ <lpString>
+ Points to a null-terminated string or an atom that identifies a string.
+ If an atom is given, it must have been created previously by using the
+ %AddAtom% function. The atom, a 16-bit value, must be placed in the
+ low-order word of the <lpString> parameter; the high-order word must be
+ set to zero.
+
+ The return value identifies the associated data handle if the property list
+ contains the given string. Otherwise, it is NULL.
+
+ The value retrieved by the %GetProp% function can be any 16-bit value useful
+ to the application.
+--*/
+
+ULONG FASTCALL WU32GetProp(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PGETPROP16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETPROP16), parg16);
+ GETPSZIDPTR(parg16->f2, psz2);
+
+ ul = (HAND16)GetProp(
+ HWND32(parg16->f1),
+ psz2
+ );
+
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int GetScrollPos(<hwnd>, <nBar>)
+ HWND <hwnd>;
+ int <nBar>;
+
+ The %GetScrollPos% function retrieves the current position of a scroll-bar
+ thumb. The current position is a relative value that depends on the current
+ scrolling range. For example, if the scrolling range is 0 to 100 and the
+ thumb is in the middle of the bar, the current position is 50.
+
+ <hwnd>
+ Identifies a window that has standard scroll bars or a scroll-bar
+ control, depending on the value of the nBar parameter.
+
+ <nBar>
+ Specifies the scroll bar to examine. It can be one of the
+ following values:
+
+ SB_CTL
+ Retrieves the position of a scroll-bar control. In this case, the hwnd
+ parameter must be the window handle of a scroll-bar control.
+
+ SB_HORZ
+ Retrieves the position of a window's horizontal scroll bar.
+
+ SB_VERT
+ Retrieves the position of a window's vertical scroll bar.
+
+ The return value specifies the current position of the scroll-bar thumb.
+--*/
+
+ULONG FASTCALL WU32GetScrollPos(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETSCROLLPOS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETSCROLLPOS16), parg16);
+
+ ul = GETINT16(GetScrollPos(
+ HWND32(parg16->f1),
+ INT32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void GetScrollRange(<hwnd>, <nBar>, <lpMinPos>, <lpMaxPos>)
+ HWND <hwnd>;
+ int <nBar>;
+ LPINT <lpMinPos>;
+ LPINT <lpMaxPos>;
+
+ The %GetScrollRange% function copies the current minimum and maximum
+ scroll-bar positions for the given scroll bar to the locations specified by
+ the <lpMinPos> and <lpMaxPos> parameters. If the given window does not have
+ standard scroll bars or is not a scroll-bar control, then the
+ %GetScrollRange% function copies zero to <lpMinPos> and <lpMaxPos>.
+
+ <hwnd>
+ Identifies a window that has standard scroll bars or a scroll-bar
+ control, depending on the value of the nBar parameter.
+
+ <nBar>
+ Specifies an integer value that identifies which scroll bar to
+ retrieve. It can be one of the following values:
+
+ SB_CTL
+ Retrieves the position of a scroll-bar control; in this case, the hwnd
+ parameter must be the handle of a scroll-bar control.
+
+ SB_HORZ
+ Retrieves the position of a window's horizontal scroll bar.
+
+ SB_VERT
+ Retrieves the position of a window's vertical scroll bar.
+
+ <lpMinPos>
+ Points to the integer variable that is to receive the minimum
+ position.
+
+ <lpMaxPos>
+ Points to the integer variable that is to receive the maximum
+ position.
+
+ This function does not return a value.
+
+ The default range for a standard scroll bar is 0 to 100. The default range
+ for a scroll-bar control is empty (both values are zero).
+--*/
+
+ULONG FASTCALL WU32GetScrollRange(PVDMFRAME pFrame)
+{
+ INT t3;
+ INT t4;
+ register PGETSCROLLRANGE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETSCROLLRANGE16), parg16);
+
+ GetScrollRange(
+ HWND32(parg16->f1),
+ INT32(parg16->f2),
+ &t3,
+ &t4
+ );
+
+ PUTINT16(parg16->f3, t3);
+ PUTINT16(parg16->f4, t4);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ ULONG GetTimerResolution(VOID)
+
+
+ This function has no parameters.
+
+ The Win 3.0 & 3.1 code just return 1000.
+
+ Contacts on this: NeilK DarrinM
+
+ The return value is always 1000.
+
+--*/
+
+ULONG FASTCALL WU32GetTimerResolution(PVDMFRAME pFrame)
+{
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ RETURN(1000L);
+}
+
+
+/*++
+ BOOL GetUpdateRect(<hwnd>, <lpRect>, <bErase>)
+ HWND <hwnd>;
+ LPRECT <lpRect>;
+ BOOL <bErase>;
+
+ The %GetUpdateRect% function retrieves the coordinates of the smallest
+ rectangle that completely encloses the update region of the given window. If
+ the window was created with the CS_OWNDC style and the mapping mode is not
+ MM_TEXT, the %GetUpdateRect% function gives the rectangle in logical
+ coordinates. Otherwise, %GetUpdateRect% gives the rectangle in client
+ coordinates. If there is no update region, %GetUpdateRect% makes the
+ rectangle empty (sets all coordinates to zero).
+
+ The <bErase> parameter specifies whether %GetUpdateRect% should erase the
+ background of the update region. If <bErase> is TRUE and the update region
+ is not empty, the background is erased. To erase the background,
+ %GetUpdateRect% sends a WM_ERASEBKGND message to the given window.
+
+ <hwnd>
+ Identifies the window whose update region is to be retrieved.
+
+ <lpRect>
+ Points to the %RECT% structure that is to receive the
+ client coordinates of the enclosing rectangle.
+
+ <bErase>
+ Specifies whether the background in the update region is to be
+ erased.
+
+ The return value specifies the status of the update region of the given
+ window. It is TRUE if the update region is not empty. Otherwise, it is
+ FALSE.
+
+ The update rectangle retrieved by the %BeginPaint% function is identical to
+ that retrieved by the %GetUpdateRect% function.
+
+ %BeginPaint% automatically validates the update region, so any call to
+ %GetUpdateRect% made immediately after the %BeginPaint% call retrieves an
+ empty update region.
+--*/
+
+ULONG FASTCALL WU32GetUpdateRect(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t2;
+ register PGETUPDATERECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETUPDATERECT16), parg16);
+
+ ul = GETBOOL16(GetUpdateRect(
+ HWND32(parg16->f1),
+ &t2,
+ BOOL32(parg16->f3)
+ ));
+
+
+ PUTRECT16(parg16->f2, &t2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int GetUpdateRgn(<hwnd>, <hRgn>, <fErase>)
+ HWND <hwnd>;
+ HRGN <hRgn>;
+ BOOL <fErase>;
+
+ The %GetUpdateRgn% function copies a window's update region into a region
+ identified by the <hRgn> parameter. The coordinates of this region are
+ relative to the upper-left corner of the window (client coordinates).
+
+ <hwnd>
+ Identifies the window that contains the region to be updated.
+
+ <hRgn>
+ Identifies the update region.
+
+ <fErase>
+ Specifies whether or not the window background should be erased
+ and nonclient areas of child windows should be drawn. If it is zero, no
+ drawing is done.
+
+ The return value specifies a short-integer flag that indicates the type of
+ resulting region. It can be any one of the following values:
+
+ COMPLEXREGION The region has overlapping borders.
+ ERROR No region was created.
+ NULLREGION The region is empty.
+ SIMPLEREGION The region has no overlapping borders.
+
+ %BeginPaint% automatically validates the update region, so any call to
+ %GetUpdateRgn% made immediately after the %BeginPaint% call retrieves an
+ empty update region.
+--*/
+
+ULONG FASTCALL WU32GetUpdateRgn(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETUPDATERGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETUPDATERGN16), parg16);
+
+ ul = GETINT16(GetUpdateRgn(
+ HWND32(parg16->f1),
+ HRGN32(parg16->f2),
+ BOOL32(parg16->f3)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32GlobalAddAtom(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ UINT dw1;
+ register PGLOBALADDATOM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALADDATOM16), parg16);
+
+ dw1 = UINT32(parg16->f1);
+
+ if (!HIWORD(dw1)) {
+
+ //
+ // If the hiword is zero, it's not a pointer.
+ // Instead, it's an integer and we either return
+ // the integer passed (if it's not a valid atom
+ // value), or zero (if it is a valid atom value).
+ //
+
+ if (!dw1 || dw1 >= 0xc000) {
+ ul = 0;
+ } else {
+ ul = dw1;
+ }
+
+ } else {
+
+ GETPSZPTR(parg16->f1, psz1);
+
+ ul = GETATOM16(GlobalAddAtom(
+ psz1
+ ));
+
+ FREEPSZPTR(psz1);
+
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32GlobalDeleteAtom(PVDMFRAME pFrame)
+{
+
+ // Envoy viewer (part of PerfectOffice) has a bug in GlobalDeleteAtom
+ // where it expects the wrong return value (the app thought 0 was
+ // failure while its for success). This causes the app to go in an
+ // infinite loop trying to delete a global object. This app works on
+ // Win3.1 because Win3.1 returns some garbage in AX if the atom is
+ // already deleted which takes this app out of the loop. On Win95 and
+ // NT3.51 that is not the case and 0 is always returned. The following
+ // comaptibility fix mimics the win3.1 behavior for this app.
+
+ ULONG ul;
+ static USHORT envoyHandle16=0;
+ static BOOL fFoundEnvoyAtom = FALSE;
+ BOOL IsEnvoy;
+ CHAR envoyString [32];
+ register PGLOBALDELETEATOM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALDELETEATOM16), parg16);
+
+ IsEnvoy = (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_GLOBALDELETEATOM);
+ if (IsEnvoy){
+ if (!fFoundEnvoyAtom && GlobalGetAtomName (ATOM32(parg16->f1),
+ envoyString,
+ 32) &&
+ !_stricmp (envoyString, "SomeEnvoyViewerIsRunning")) {
+ envoyHandle16 = parg16->f1;
+ }
+
+ }
+ ul = GETATOM16(GlobalDeleteAtom(
+ ATOM32(parg16->f1)
+ ));
+
+ if (IsEnvoy){
+ if (envoyHandle16 && !fFoundEnvoyAtom) {
+ fFoundEnvoyAtom = TRUE;
+ }
+ else if (fFoundEnvoyAtom) {
+ if (envoyHandle16 == parg16->f1) {
+ envoyHandle16 = 0;
+ fFoundEnvoyAtom = FALSE;
+ ul = parg16->f1;
+ }
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32GlobalFindAtom(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ register PGLOBALFINDATOM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALFINDATOM16), parg16);
+ GETPSZPTR(parg16->f1, psz1);
+
+ ul = GETATOM16(GlobalFindAtom(
+ psz1
+ ));
+
+ FREEPSZPTR(psz1);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32GlobalGetAtomName(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PGLOBALGETATOMNAME16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GLOBALGETATOMNAME16), parg16);
+ ALLOCVDMPTR(parg16->f2, parg16->f3, psz2);
+
+ if (parg16->f1) {
+ ul = GETWORD16(GlobalGetAtomName(ATOM32(parg16->f1),
+ psz2,
+ INT32(parg16->f3)));
+
+ FLUSHVDMPTR(parg16->f2, strlen(psz2)+1, psz2);
+ }
+ else {
+ *psz2 = '\0';
+ }
+
+
+ FREEVDMPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL GrayString(<hDC>, <hBrush>, <lpOutputFunc>, <lpData>, <nCount>, <X>,
+ <Y>, <nWidth>, <nHeight>)
+ HDC <hDC>;
+ HBRUSH <hBrush>;
+ FARPROC <lpOutputFunc>;
+ DWORD <lpData>;
+ int <nCount>;
+ int <X>;
+ int <Y>;
+ int <nWidth>;
+ int <nHeight>;
+
+ The %GrayString% function draws gray text at the given location. The
+ %GrayString% function draws gray text by writing the text in a memory
+ bitmap, graying the bitmap, and then copying the bitmap to the display. The
+ function grays the text regardless of the selected brush and
+ background. %GrayString% uses the font currently selected for the device
+ context specified by the <hDC> parameter.
+
+ If the <lpOutputFunc> parameter is NULL, GDI uses the %TextOut% function,
+ and the <lpData> parameter is assumed to be a long pointer to the character
+ string to be output. If the characters to be output cannot be handled by
+ %TextOut% (for example, the string is stored as a bitmap), the application
+ must supply its own output function.
+
+ <hDC>
+ Identifies the device context.
+
+ <hBrush>
+ Identifies the brush to be used for graying.
+
+ <lpOutputFunc>
+ Is the procedure-instance address of the application-supplied
+ function that will draw the string, or, if the %TextOut% function is to
+ be used to draw the string, it is a NULL pointer. See the following
+ Comments section for details.
+
+ <lpData>
+ Specifies a long pointer to data to be passed to the output
+ function. If the <lpOutputFunc> parameter is NULL, <lpData> must be a
+ long pointer to the string to be output.
+
+ <nCount>
+ Specifies the number of characters to be output. If the <nCount>
+ parameter is zero, %GrayString% calculates the length of the string
+ (assuming that <lpData> is a pointer to the string). If <nCount> is -1
+ and the function pointed to by <lpOutputFunc> returns zero, the image is
+ shown but not grayed.
+
+ <X>
+ Specifies the logical <x>-coordinate of the starting position of
+ the rectangle that encloses the string.
+
+ <Y>
+ Specifies the logical <y>-coordinate of the starting position of
+ the rectangle that encloses the string.
+
+ <nWidth>
+ Specifies the width (in logical units) of the rectangle that
+ encloses the string. If the <nWidth> parameter is zero, %GrayString%
+ calculates the width of the area, assuming <lpData> is a pointer to the
+ string.
+
+ <nHeight>
+ Specifies the height (in logical units) of the rectangle that
+ encloses the string. If the <nHeight> parameter is zero, %GrayString%
+ calculates the height of the area, assuming <lpData> is a pointer to the
+ string.
+
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ string is drawn. A return value of FALSE means that either the %TextOut%
+ function or the application-supplied output function returned FALSE, or
+ there was insufficient memory to create a memory bitmap for graying.
+
+ An application can draw grayed strings on devices that support a solid gray
+ color, without calling the %GrayString% function. The system color
+ COLOR_GRAYTEXT is the solid-gray system color used to draw disabled text.
+ The application can call the %GetSysColor% function to retrieve the color
+ value of COLOR_GRAYTEXT. If the color is other than zero (black), the
+ application can call the %SetTextColor% to set the text color to the color
+ value and then draw the string directly. If the retrieved color is black,
+ the application must call %GrayString% to gray the text.
+
+ The callback function must use the Pascal calling convention and must be
+ declared %FAR%.
+
+ Callback Function:
+
+ BOOL FAR PASCAL <OutputFunc>(<hDC>, <lpData>, <nCount>)
+ HDC <hDC>;
+ DWORD <lpData>;
+ int <nCount>;
+
+ <OutputFunc> is a placeholder for the application-supplied callback function
+ name. The actual name must be exported by including it in an %EXPORTS%
+ statement in the application's module-definition file.
+
+ <hDC>
+ Identifies a memory device context with a bitmap of at least the width
+ and height specified by the nWidth and nHeight parameters,
+ respectively.
+
+ <lpData>
+ Points to the character string to be drawn.
+
+ <nCount>
+ Specifies the number of characters to be output.
+
+ The return value must be TRUE to indicate success. Otherwise, it is FALSE.
+
+ This output function (<OutputFunc>) must draw an image relative to the
+ coordinates (0,0) rather than (<X,Y>). The address passed as the
+ <lpOutputFunc> parameter must be created by using the %MakeProcInstance%
+ function, and the output function name must be exported; it must be
+ explicitly defined in an %EXPORTS% statement of the application's
+ module-definition file.
+
+ The MM_TEXT mapping mode must be selected before using this function.
+--*/
+
+BOOL W32GrayStringProc(HDC hDC,PGRAYSTRINGDATA pGray, int n) {
+ INT iReturn;
+ PARM16 Parm16;
+
+ WOW32ASSERT(pGray);
+
+ if (pGray->fResetLengthToZero)
+ n = 0;
+
+ LOGDEBUG(12,(" Graystring callback function, n = %d, hdc = %lx, %lx\n",n,hDC,pGray->dwUserParam));
+
+ Parm16.GrayStringProc.n = (SHORT)n;
+ Parm16.GrayStringProc.data = pGray->dwUserParam;
+ pGray->hdc=Parm16.GrayStringProc.hdc = GETHDC16(hDC);
+ CallBack16(RET_GRAYSTRINGPROC, &Parm16, pGray->vpfnGrayStringProc, (PVPVOID)&iReturn);
+
+ LOGDEBUG(12,(" Graystring callback function returns %x\n",iReturn));
+ return (BOOL)((SHORT)iReturn);
+}
+
+ULONG FASTCALL WU32GrayString(PVDMFRAME pFrame)
+{
+ ULONG ul=0;
+ PSZ psz2;
+ HDC hdc;
+ INT n,wid,hgt;
+ VPVOID vpfn;
+ VPVOID vpstr;
+ GRAYSTRINGDATA Gray;
+ register PGRAYSTRING16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GRAYSTRING16), parg16);
+
+ hdc=HDC32(parg16->f1);
+
+ vpfn = DWORD32(parg16->f3);
+
+ vpstr = DWORD32(parg16->f4);
+
+ n=INT32(parg16->f5);
+
+ wid=INT32(parg16->f8);
+ hgt=INT32(parg16->f9);
+
+
+ if ( HIWORD(vpfn) ) { // SQLWin/repowin passes junk in low word
+
+ Gray.fResetLengthToZero = FALSE;
+
+ if( n==0 ) {
+
+ n = 1; // Prevent USER from doing strlen on &Gray below
+
+ if ( HIWORD(vpstr) != 0 ) { // Blow off small integers right away
+
+ GETVDMPTR(vpstr, 0, psz2); // This might assert on mips, ignore it!
+
+ if ( psz2 ) {
+ try {
+ n = strlen(psz2);
+ if (!n) {
+ n = 1;
+ Gray.fResetLengthToZero = TRUE;
+ }
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ }
+ }
+
+ FREEVDMPTR( psz2 );
+ }
+ }
+
+ if ( wid == 0 || hgt == 0) {
+ if ( HIWORD(vpstr) != 0 ) {
+ GETVDMPTR(vpstr, 0, psz2); // This might assert on mips, ignore it!
+
+ if (psz2) {
+ SIZE size;
+
+ try {
+ GetTextExtentPointA(hdc, (LPCSTR)psz2, n, &size);
+ wid = size.cx;
+ hgt = size.cy;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ }
+ }
+
+ FREEVDMPTR( psz2 );
+ }
+ }
+
+ Gray.vpfnGrayStringProc = DWORD32(parg16->f3);
+ Gray.dwUserParam = vpstr;
+ Gray.hdc = 0;
+
+ LOGDEBUG(12,(" Graystring with callback %lx n,w,h = %d,%d,%d\n",
+ vpstr,n,wid,hgt));
+
+
+ ul = GETBOOL16(GrayString(hdc,
+ HBRUSH32(parg16->f2),
+ (GRAYSTRINGPROC)W32GrayStringProc,
+ (DWORD)&Gray,
+ n,
+ INT32(parg16->f6),
+ INT32(parg16->f7),
+ wid,
+ hgt));
+
+ if( Gray.hdc ) {
+ FREEHOBJ16(Gray.hdc);
+ }
+
+ } else {
+
+ GETPSZPTR(vpstr, psz2);
+
+#ifdef DOESNT_USER_DO_THIS
+ if( n==0 ) {
+ n=strlen(psz2);
+ }
+ if( ((wid == 0) || (hgt == 0)) ) {
+ GetTextExtentPoint(hdc,psz2,n,&sz);
+
+ wid=sz.cx;
+ hgt=sz.cy;
+ }
+#endif
+ ul = GETBOOL16(GrayString(hdc,
+ HBRUSH32(parg16->f2),
+ NULL,
+ (DWORD)psz2,
+ n,
+ INT32(parg16->f6),
+ INT32(parg16->f7),
+ wid,
+ hgt));
+
+ FREEPSZPTR(psz2);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/*++
+ void InvalidateRect(<hwnd>, <lpRect>, <bErase>)
+ HWND <hwnd>;
+ LPRECT <lpRect>;
+ BOOL <bErase>;
+
+ The %InvalidateRect% function invalidates the client area within the given
+ rectangle by adding that rectangle to the window's update region. The
+ invalidated rectangle, along with all other areas in the update region, is
+ marked for painting when the next WM_PAINT message occurs. The invalidated
+ areas accumulate in the update region until the region is processed when the
+ next WM_PAINT message occurs, or the region is validated by using the
+ %ValidateRect% or %ValidateRgn% function.
+
+ The <bErase> parameter specifies whether the background within the update
+ area is to be erased when the update region is processed. If <bErase> is
+ TRUE, the background is erased when the %BeginPaint% function is called;
+ if <bErase> is FALSE, the background remains unchanged. If <bErase> is
+ TRUE for any part of the update region, the background in the entire
+ region is erased, not just in the given part.
+
+ <hwnd>
+ Identifies the window whose update region is to be modified.
+
+ <lpRect>
+ Points to a %RECT% structure that contains the rectangle
+ (in client coordinates) to be added to the update region. If the
+ <lpRect> parameter is NULL, the entire client area is added to the
+ region.
+
+ <bErase>
+ Specifies whether the background within the update region is to
+ be erased.
+
+ This function does not return a value.
+
+ Windows sends a WM_PAINT message to a window whenever its update region is
+ not empty and there are no other messages in the application queue for that
+ window.
+--*/
+
+ULONG FASTCALL WU32InvalidateRect(PVDMFRAME pFrame)
+{
+ RECT t2, *p2;
+ register PINVALIDATERECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(INVALIDATERECT16), parg16);
+ p2 = GETRECT16(parg16->f2, &t2);
+
+ InvalidateRect(
+ HWND32(parg16->f1),
+ p2,
+ BOOL32(parg16->f3)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(1); // Win 3.x always returned 1 as a side-effect of jmping to
+ // IRedrawWindow [core\user\wmupdate.c] - MarkRi 5/93
+}
+
+
+/*++
+ void InvalidateRgn(<hwnd>, <hRgn>, <bErase>)
+ HWND <hwnd>;
+ HRGN <hRgn>;
+ BOOL <bErase>;
+
+ The %InvalidateRgn% function invalidates the client area within the given
+ region by adding it to the current update region of the given window. The
+ invalidated region, along with all other areas in the update region, is
+ marked for painting when the next WM_PAINT message occurs. The invalidated
+ areas accumulate in the update region until the region is processed when the
+ next WM_PAINT message occurs, or the region is validated by using the
+ %ValidateRect% or %ValidateRgn% function.
+
+ The <bErase> parameter specifies whether the background within the update
+ area is to be erased when the update region is processed. If <bErase> is
+ TRUE, the background is erased when the %BeginPaint% function is called; if
+ <bErase> is FALSE, the background remains unchanged. If <bErase> is TRUE for
+ any part of the update region, the background in the entire region is
+ erased, not just in the given part.
+
+ <hwnd>
+ Identifies the window whose update region is to be modified.
+
+ <hRgn>
+ Identifies the region to be added to the update region. The
+ region is assumed to have client coordinates.
+
+ <bErase>
+ Specifies whether the background within the update region is to
+ be erased.
+
+ This function does not return a value.
+
+ Windows sends a WM_PAINT message to a window whenever its update region is
+ not empty and there are no other messages in the application queue for that
+ window.
+
+ The given region must have been previously created by using one of the
+ region functions (for more information, see Chapter 1, Window Manager
+ Interface Functions).
+--*/
+
+ULONG FASTCALL WU32InvalidateRgn(PVDMFRAME pFrame)
+{
+ register PINVALIDATERGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(INVALIDATERGN16), parg16);
+
+ InvalidateRgn(
+ HWND32(parg16->f1),
+ HRGN32(parg16->f2),
+ BOOL32(parg16->f3)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(1); // Win 3.x always returned 1 as a side-effect of jmping to
+ // IRedrawWindow [core\user\wmupdate.c] - MarkRi 5/93
+}
+
+
+/*++
+ void InvertRect(<hDC>, <lpRect>)
+ HDC <hDC>;
+ LPRECT <lpRect>;
+
+ The %InvertRect% function inverts the contents of the given rectangle. On
+ monochrome displays, the %InvertRect% function makes white pixels black, and
+ black pixels white. On color displays, the inversion depends on how colors
+ are generated for the display. Calling %InvertRect% twice with the same
+ rectangle restores the display to its previous colors.
+
+ <hDC>
+ Identifies the device context.
+
+ <lpRect>
+ Points to a %RECT% structure that contains the logical coordinates of
+ the rectangle to be inverted.
+
+ This function does not return a value.
+
+ The %InvertRect% function compares the values of the %top%, %bottom%,
+ %left%, and %right% members of the specified rectangle. If %bottom% is less
+ than or equal to %top%, or if %right% is less than or equal to %left%, the
+ rectangle is not drawn.
+--*/
+
+ULONG FASTCALL WU32InvertRect(PVDMFRAME pFrame)
+{
+ RECT t2;
+ register PINVERTRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(INVERTRECT16), parg16);
+
+ WOW32VERIFY(GETRECT16(parg16->f2, &t2));
+
+ InvertRect(
+ HDC32(parg16->f1),
+ &t2
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+ULONG FASTCALL WU32LoadBitmap(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ PSZ psz2;
+ register PLOADBITMAP16 parg16;
+ LPBYTE pResData = NULL;
+
+ GETARGPTR(pFrame, sizeof(LOADBITMAP16), parg16);
+ GETPSZIDPTR(parg16->f2, psz2);
+ GETMISCPTR(parg16->f3, pResData);
+
+ ul = GETHBITMAP16((pfnOut.pfnWOWLoadBitmapA)(HINSTRES32(parg16->f1),
+ psz2,
+ pResData,
+ parg16->f4));
+
+ FREEMISCPTR(pResData);
+ FREEPSZIDPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32WOWGetIdFromDirectory(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ LPBYTE pResData = NULL;
+ register PWOWGETIDFROMDIRECTORY16 parg16;
+
+ GETARGPTR(pFrame, sizeof(WOWGETIDFROMDIRECTORY16), parg16);
+ GETMISCPTR (parg16->f1, pResData);
+
+ ul = (ULONG) MAKEINTRESOURCE((pfnOut.pfnWOWGetIdFromDirectory)(pResData,
+ parg16->f2)); // RT_ICON or CURSOR
+
+
+ FREEMISCPTR(pResData);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/*++
+ void MessageBeep(<wType>)
+ WORD <wType>;
+
+ The %MessageBeep% function generates a beep at the system speaker.
+
+ <wType>
+ Is not used. It should be set to zero.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32MessageBeep(PVDMFRAME pFrame)
+{
+ register PMESSAGEBEEP16 parg16;
+
+ GETARGPTR(pFrame, sizeof(MESSAGEBEEP16), parg16);
+
+ MessageBeep(
+ WORD32(parg16->f1)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ BOOL OpenIcon(<hwnd>)
+ HWND <hwnd>;
+
+ The %OpenIcon% function activates and displays an iconic (minimized)
+ window. Windows restores it to its original size and position.
+
+ <hwnd>
+ Identifies the window.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function is successful. Otherwise, it is FALSE.
+--*/
+
+ULONG FASTCALL WU32OpenIcon(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register POPENICON16 parg16;
+
+ GETARGPTR(pFrame, sizeof(OPENICON16), parg16);
+
+ ul = GETBOOL16(OpenIcon(
+ HWND32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void ReleaseCapture(VOID)
+
+ The %ReleaseCapture% function releases the mouse capture and restores normal
+ input processing. A window with the mouse capture receives all mouse input
+ regardless of the position of the cursor.
+
+ This function has no parameters.
+
+ This function does not return a value.
+
+ An application calls this function after calling the %SetCapture% function.
+--*/
+
+ULONG FASTCALL WU32ReleaseCapture(PVDMFRAME pFrame)
+{
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ReleaseCapture();
+
+ RETURN(0);
+}
+
+
+/*++
+ int ReleaseDC(<hwnd>, <hDC>)
+ HWND <hwnd>;
+ HDC <hDC>;
+
+ The %ReleaseDC% function releases a device context, freeing it for use by
+ other applications. The effect of the %ReleaseDC% function depends on the
+ device-context type. It only frees common and window device contexts. It has
+ no effect on class or private device contexts.
+
+ <hwnd>
+ Identifies the window whose device context is to be released.
+
+ <hDC>
+ Identifies the device context to be released.
+
+ The return value specifies whether the device context is released. It is 1
+ if the device context is released. Otherwise, it is zero.
+
+ The application must call the %ReleaseDC% function for each call to the
+ %GetWindowDC% function and for each call to the %GetDC% function that
+ retrieves a common device context.
+--*/
+
+ULONG FASTCALL WU32ReleaseDC(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PRELEASEDC16 parg16;
+ HAND16 htask16 = CURRENTPTD()->htask16;
+
+ GETARGPTR(pFrame, sizeof(RELEASEDC16), parg16);
+
+ CURRENTPTD()->ulLastDesktophDC = 0;
+
+ CacheReleasedDC(htask16, parg16->f1, parg16->f2);
+ ul = TRUE;
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HANDLE RemoveProp(<hwnd>, <lpString>)
+ HWND <hwnd>;
+ LPSTR <lpString>;
+
+ The %RemoveProp% function removes an entry from the property list of the
+ specified window. The character string specified by the <lpString> parameter
+ identifies the entry to be removed.
+
+ The %RemoveProp% function returns the data handle associated with the string
+ so that the application can free the data associated with the handle.
+
+ <hwnd>
+ Identifies the window whose property list is to be changed.
+
+ <lpString>
+ Points to a null-terminated string or to an atom that identifies a
+ string. If an atom is given, it must have been previously created by
+ means of the %AddAtom% function. The atom, a 16-bit value, must be
+ placed in the low-order word of <lpString>; the high-order word must be
+ zero.
+
+ The return value identifies the given string. It is NULL if the string
+ cannot be found in the given property list.
+
+ An application must free the data handles associated with entries removed
+ from a property list. The application should only remove those properties
+ which it added to the property list.
+--*/
+
+ULONG FASTCALL WU32RemoveProp(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PREMOVEPROP16 parg16;
+
+ GETARGPTR(pFrame, sizeof(REMOVEPROP16), parg16);
+ GETPSZIDPTR(parg16->f2, psz2);
+
+ ul = (HAND16)RemoveProp(
+ HWND32(parg16->f1),
+ psz2
+ );
+
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL ScrollDC(<hDC>, <dx>, <dy>, <lprcScroll>, <lprcClip>, <hrgnUpdate>,
+ <lprcUpdate>)
+ HDC <hDC>;
+ int <dx>;
+ int <dy>;
+ LPRECT <lprcScroll>;
+ LPRECT <lprcClip>;
+ HRGN <hrgnUpdate>;
+ LPRECT <lprcUpdate>;
+
+ The %ScrollDC% function scrolls a rectangle of bits horizontally and
+ vertically. The <lprcScroll> parameter points to the rectangle to be
+ scrolled, the <dx> parameter specifies the number of units to be scrolled
+ horizontally, and the <dy> parameter specifies the number of units to be
+ scrolled vertically.
+
+ <hDC>
+ Identifies the device context that contains the bits to be scrolled.
+
+ <dx>
+ Specifies the number of horizontal scroll units.
+
+ <dy>
+ Specifies the number of vertical scroll units.
+
+ <lprcScroll>
+ Points to the %RECT% structure that contains the
+ coordinates of the scrolling rectangle.
+
+ <lprcClip>
+ Points to the %RECT% structure that contains the
+ coordinates of the clipping rectangle. When this rectangle is smaller
+ than the original pointed to by <lprcScroll>, scrolling occurs only in
+ the smaller rectangle.
+
+ <hrgnUpdate>
+ Identifies the region uncovered by the scrolling process. The
+ %ScrollDC% function defines this region; it is not necessarily a
+ rectangle.
+
+ <lprcUpdate>
+ Points to the %RECT% structure that, upon return, contains
+ the coordinates of the rectangle that bounds the scrolling update
+ region. This is the largest rectangular area that requires repainting.
+
+ This value specifies the outcome of the function. It is TRUE if scrolling is
+ executed. Otherwise, it is FALSE.
+
+ If the <lprcUpdate> parameter is NULL, Windows does not compute the update
+ rectangle. If both the <hrgnUpdate> and <lprcUpdate> parameters are NULL,
+ Windows does not compute the update region. If <hrgnUpdate> is not NULL,
+ Windows assumes that it contains a valid region handle to the region
+ uncovered by the scrolling process (defined by the %ScrollDC% function).
+
+ An application should use the %ScrollWindow% function when it is necessary
+ to scroll the entire client area of a window. Otherwise, it should use
+ %ScrollDC%.
+--*/
+
+ULONG FASTCALL WU32ScrollDC(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT t4;
+ RECT t5;
+ RECT t7;
+ register PSCROLLDC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SCROLLDC16), parg16);
+
+ ul = GETBOOL16(ScrollDC(
+ HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ GETRECT16(parg16->f4, &t4),
+ GETRECT16(parg16->f5, &t5),
+ HRGN32(parg16->f6),
+ &t7
+ ));
+
+ PUTRECT16(parg16->f7, &t7);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HWND SetCapture(<hwnd>)
+ HWND <hwnd>;
+
+ The %SetCapture% function causes all subsequent mouse input to be sent to
+ the window specified by the <hwnd> parameter, regardless of the position of
+ the cursor.
+
+ <hwnd>
+ Identifies the window that is to receive the mouse input.
+
+ The return value identifies the window that previously received all mouse
+ input. It is NULL if there is no such window.
+
+ When the window no longer requires all mouse input, the application should
+ call the %ReleaseCapture% function so that other windows can receive mouse
+ input.
+--*/
+
+ULONG FASTCALL WU32SetCapture(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETCAPTURE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETCAPTURE16), parg16);
+
+ // MS Works Ver 3.0B has an unintialized local variable. We need to make
+ // sure it see's a positive int value in the location on the stack where we
+ // write the 32-bit thunk address for fast dispatching to this thunk.
+
+ if (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_SETCAPSTACK) {
+ // wCallID has already been used for dispatch so we can overwrite it.
+ pFrame->wCallID = 0x100;
+ }
+
+ ul = GETHWND16(SetCapture(HWND32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void SetDoubleClickTime(<wCount>)
+ WORD <wCount>;
+
+ The %SetDoubleClickTime% function sets the double-click time for the
+ mouse. A double-click is a series of two clicks of the mouse button, the
+ second occurring within a specified time after the first. The double-click
+ time is the maximum number of milliseconds that may occur between the first
+ and second clicks of a double-click.
+
+ <wCount>
+ Specifies the number of milliseconds that can occur between
+ double-clicks.
+
+ This function does not return a value.
+
+ If the <wCount> parameter is set to zero, Windows will use the default
+ double-click time of 500 milliseconds.
+
+ The %SetDoubleClickTime% function alters the double-click time for all
+ windows in the system.
+--*/
+
+ULONG FASTCALL WU32SetDoubleClickTime(PVDMFRAME pFrame)
+{
+ register PSETDOUBLECLICKTIME16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETDOUBLECLICKTIME16), parg16);
+
+ SetDoubleClickTime(
+ WORD32(parg16->f1)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+ULONG FASTCALL WU32SetEventHook(PVDMFRAME pFrame)
+{
+ PTD ptd;
+ PTDB pTDB;
+ DWORD dwButtonPushed;
+ CHAR szErrorMessage[200];
+ char szModName[9];
+ char szTitle[100];
+ register PSETEVENTHOOK16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETEVENTHOOK16), parg16);
+
+ // Retail Build
+
+ ptd = CURRENTPTD();
+ if (ptd->dwFlags & TDF_FORCETASKEXIT) {
+ goto SetEventHookExit;
+ }
+
+ pTDB = (PVOID)SEGPTR(ptd->htask16,0);
+
+ RtlZeroMemory(szModName, sizeof(szModName));
+ RtlCopyMemory(szModName, pTDB->TDB_ModName, sizeof(szModName)-1);
+
+ if (!LoadString(hmodWOW32, iszEventHook,
+ szErrorMessage, sizeof(szErrorMessage)/sizeof(CHAR)))
+ {
+ szErrorMessage[0] = 0;
+ }
+ if (!LoadString(hmodWOW32, iszApplication,
+ szTitle, sizeof(szTitle)/sizeof(CHAR)))
+ {
+ szTitle[0] = 0;
+ }
+ strcat(szTitle, szModName);
+
+ dwButtonPushed = WOWSysErrorBox(
+ szTitle,
+ szErrorMessage,
+ SEB_CLOSE | SEB_DEFBUTTON,
+ 0,
+ SEB_IGNORE
+ );
+
+ if (dwButtonPushed != 3) {
+ //
+ // If user typed Cancel or Any of the above fail,
+ // force the task to die.
+ //
+
+ GETFRAMEPTR(ptd->vpStack, pFrame);
+ pFrame->wRetID = RET_FORCETASKEXIT;
+
+ ptd->dwFlags |= TDF_FORCETASKEXIT;
+ }
+
+SetEventHookExit:
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ HWND SetFocus(<hwnd>)
+ HWND <hwnd>;
+
+ The %SetFocus% function assigns the input focus to the window specified by
+ the <hwnd> parameter. The input focus directs all subsequent keyboard input
+ to the given window. The window, if any, that previously had the input focus
+ loses it. If <hwnd> is NULL, key strokes are ignored.
+
+ The %SetFocus% function sends a WM_KILLFOCUS message to the window that
+ loses the input focus and a WM_SETFOCUS message to the window that receives
+ the input focus. It also activates either the window that receives the focus
+ or the parent of the window that receives the focus.
+
+ <hwnd>
+ Identifies the window to receive the keyboard input.
+
+ The return value identifies the window that previously had the input focus.
+ It is NULL if there is no such window.
+
+ If a window is active but doesn't have the focus (that is, no window has the
+ focus), any key pressed will produce the WM_SYSCHAR, WM_SYSKEYDOWN, or
+ WM_SYSKEYUP message. If the VK_MENU key is also pressed, the <lParam>
+ parameter of the message will have bit 30 set. Otherwise, the messages that
+ are produced do <not> have this bit set.
+--*/
+
+ULONG FASTCALL WU32SetFocus(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETFOCUS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETFOCUS16), parg16);
+
+ ul = GETHWND16(SetFocus(HWND32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void SetKeyboardState(<lpKeyState>)
+ LPBYTE <lpKeyState>;
+
+ The %SetKeyboardState% function copies the 256 bytes pointed to by the
+ <lpKeyState> parameter into the Windows keyboard-state table.
+
+ <lpKeyState>
+ Points to an array of 256 bytes that contains keyboard key states.
+
+ This function does not return a value.
+
+ In many cases, an application should call the %GetKeyboardState% function
+ first to initialize the 256-byte array. The application should then change
+ the desired bytes.
+
+ %SetKeyboardState% sets the LEDs and BIOS flags for the ^NUMLOCK^,
+ ^CAPSLOCK^, and ^SCROLL LOCK^ keys according to the toggle state of the
+ VK_NUMLOCK, VK_CAPITAL, and VK_OEM_SCROLL entries of the array.
+
+ For more information, see the description of %GetKeyboardState%, earlier in
+ this chapter.
+--*/
+
+ULONG FASTCALL WU32SetKeyboardState(PVDMFRAME pFrame)
+{
+ PBYTE p1;
+ register PSETKEYBOARDSTATE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETKEYBOARDSTATE16), parg16);
+ GETVDMPTR(parg16->f1, 256, p1);
+
+ SetKeyboardState(
+ p1
+ );
+
+ FREEVDMPTR(p1);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ BOOL SetProp(<hwnd>, <lpString>, <hData>)
+ HWND <hwnd>;
+ LPSTR <lpString>;
+ HANDLE <hData>;
+
+ The %SetProp% function adds a new entry or changes an existing entry in the
+ property list of the specified window. The %SetProp% function adds a new
+ entry to the list if the character string specified by the <lpString>
+ parameter does not already exist in the list. The new entry contains the
+ string and the handle. Otherwise, the function replaces the string's current
+ handle with the one specified by the <hData> parameter.
+
+ The <hData> parameter can contain any 16-bit value useful to the
+ application.
+
+ <hwnd>
+ Identifies the window whose property list is to receive the new entry.
+
+ <lpString>
+ Points to a null-terminated string or an atom that identifies a string.
+ If an atom is given, it must have been previously created by using the
+ %AddAtom% function. The atom, a 16-bit value, must be placed in the
+ low-order word of <lpString>; the high-order word must be zero.
+
+ <hData>
+ Identifies a data handle to be copied to the property list.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ data handle and string are added to the property list. Otherwise, it is
+ FALSE.
+
+ The application is responsible for removing all entries it has added to the
+ property list before destroying the window (that is, before the application
+ processes the WM_DESTROY message). The %RemoveProp% function must be used to
+ remove entries from a property list.
+--*/
+
+ULONG FASTCALL WU32SetProp(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PSETPROP16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETPROP16), parg16);
+ GETPSZIDPTR(parg16->f2, psz2);
+
+ // don't do any aliasing of the data handle, it can be anything.
+
+ ul = GETBOOL16(SetProp(
+ HWND32(parg16->f1),
+ psz2,
+ (HAND32)parg16->f3
+ ));
+
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int SetScrollPos(<hwnd>, <nBar>, <nPos>, <bRedraw>)
+ HWND <hwnd>;
+ int <nBar>;
+ int <nPos>;
+ BOOL <bRedraw>;
+
+ The %SetScrollPos% function sets the current position of a scroll-bar thumb
+ to that specified by the <nPos> parameter and, if specified, redraws the
+ scroll bar to reflect the new position.
+
+ <hwnd>
+ Identifies the window whose scroll bar is to be set.
+
+ <nBar>
+ Specifies the scroll bar to be set. It can be one of the following
+ values:
+
+ SB_CTL
+ Sets the position of a scroll-bar control. In this case, the hwnd
+ parameter must be the handle of a scroll-bar control.
+
+ SB_HORZ
+ Sets a window's horizontal scroll-bar position.
+
+ SB_VERT
+ Sets a window's vertical scroll-bar position.
+
+ <nPos>
+ Specifies the new position. It must be within the scrolling range.
+
+ <bRedraw>
+ Specifies whether the scroll bar should be redrawn to reflect the
+ new position. If the <bRedraw> parameter is TRUE, the scroll bar is
+ redrawn. If it is FALSE, it is not redrawn.
+
+ The return value specifies the previous position of the scroll-bar thumb.
+
+ Setting the <bRedraw> parameter to zero is useful whenever the scroll bar
+ will be redrawn by a subsequent call to another function.
+--*/
+
+ULONG FASTCALL WU32SetScrollPos(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETSCROLLPOS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETSCROLLPOS16), parg16);
+
+ ul = GETINT16(SetScrollPos(
+ HWND32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ BOOL32(parg16->f4)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void SetScrollRange(<hwnd>, <nBar>, <nMinPos>, <nMaxPos>, <bRedraw>)
+ HWND <hwnd>;
+ int <nBar>;
+ int <nMinPos>;
+ int <nMaxPos>;
+ BOOL <bRedraw>;
+
+ The %SetScrollRange% function sets minimum and maximum position values for
+ the given scroll bar. It can also be used to hide or show standard scroll
+ bars by setting the <nMinPos> and <nMaxPos> parameters to zero.
+
+ <hwnd>
+ Identifies a window or a scroll-bar control, depending on the value of
+ the nBar parameter.
+
+ <nBar>
+ the scroll bar to be set. It can be one of the following
+ values:
+
+ SB_CTL
+ Sets the range of a scroll-bar control. In this case, the hwnd parameter
+ must be the handle of a scroll-bar control.
+
+ SB_HORZ
+ Sets a window's horizontal scroll-bar range.
+
+ SB_VERT
+ Sets a window's vertical scroll-bar range.
+
+ <nMinPos>
+ Specifies the minimum scrolling position.
+
+ <nMaxPos>
+ Specifies the maximum scrolling position.
+
+ <bRedraw>
+ Specifies whether or not the scroll bar should be redrawn to
+ reflect the change. If the <bRedraw> parameter is TRUE, the scroll
+ bar is redrawn. If it is FALSE, it is not redrawn.
+
+ This function does not return a value.
+
+ An application should not call this function to hide a scroll bar while
+ processing a scroll-bar notification message.
+
+ If %SetScrollRange% immediately follows the %SetScrollPos% function, the
+ <bRedraw> parameter in %SetScrollPos% should be set to zero to prevent the
+ scroll bar from being drawn twice.
+
+ The difference between the values specified by the <nMinPos> and <nMaxPos>
+ parameters must not be greater than 32,767.
+--*/
+
+ULONG FASTCALL WU32SetScrollRange(PVDMFRAME pFrame)
+{
+ register PSETSCROLLRANGE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETSCROLLRANGE16), parg16);
+
+ SetScrollRange(
+ HWND32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ BOOL32(parg16->f5)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ void SetSysColors(<cDspElements>, <aiDspElements>, <aRgbValues>)
+ int <cDspElements>;
+ LPINT <aiDspElements>;
+ LPDWORD <aRgbValues>;
+
+ The %SetSysColors% function sets the system colors for one or more display
+ elements. Display elements are the various parts of a window and the Windows
+ display that appear on the system display screen.
+
+ The %SetSysColors% function sends a WM_SYSCOLORCHANGE message to all windows
+ to inform them of the change in color. It also directs Windows to repaint
+ the affected portions of all currently visible windows.
+
+ <cDspElements>
+ Specifies the number of display elements in the <aiDspElements> array.
+
+ <aiDspElements>
+ Points to an array of integers that specify the display elements
+ to be changed. For a list of possible display elements, see the following
+ "Comments" section.
+
+ <aRgbValues>
+ Points to an array of unsigned long integers that contains the new RGB
+ color value for each display element in the <aiDspElements> array.
+
+ This function does not return a value.
+
+ The %SetSysColors% function changes the current Windows session only. The
+ new colors are not saved when Windows terminates.
+
+ The following is the list of display elements that may be used in the array
+ of display elements pointed to by the <aiDspElements> parameter:
+
+ COLOR_ACTIVEBORDER
+ Active window border.
+
+ COLOR_ACTIVECAPTION
+ Active window caption.
+
+ COLOR_APPWORKSPACE
+ Background color of multiple document interface (MDI) applications.
+
+ COLOR_BACKGROUND
+ Desktop.
+
+ COLOR_BTNFACE
+ Face shading on push buttons.
+
+ COLOR_BTNSHADOW
+ Edge shading on push buttons.
+
+ COLOR_BTNTEXT
+ Text on push buttons.
+
+ COLOR_CAPTIONTEXT
+ Text in caption, size box, scroll-bar arrow box.
+
+ COLOR_GRAYTEXT
+ Grayed (disabled) text. This color is set to 0 if the current display
+ driver does not support a solid gray color.
+
+ COLOR_HIGHLIGHT
+ Items selected item in a control.
+
+ COLOR_HIGHLIGHTTEXT
+ Text of item selected in a control.
+
+ COLOR_INACTIVEBORDER
+ Inactive window border.
+
+ COLOR_INACTIVECAPTION
+ Inactive window caption.
+
+ COLOR_INACTIVECAPTIONTEXT
+ Color of text in an inactive caption.
+
+ COLOR_MENU
+ Menu background.
+
+ COLOR_MENUTEXT
+ Text in menus.
+
+ COLOR_SCROLLBAR
+ Scroll-bar gray area.
+
+ COLOR_WINDOW
+ Window background.
+
+ COLOR_WINDOWFRAME
+ Window frame.
+
+ COLOR_WINDOWTEXT
+ Text in windows.
+--*/
+
+#define SSC_BUF_SIZE 256
+
+ULONG FASTCALL WU32SetSysColors(PVDMFRAME pFrame)
+{
+ PINT p2;
+ PDWORD p3;
+ register PSETSYSCOLORS16 parg16;
+ INT BufElements[SSC_BUF_SIZE];
+
+ GETARGPTR(pFrame, sizeof(SETSYSCOLORS16), parg16);
+ p2 = STACKORHEAPALLOC(INT32(parg16->f1) * sizeof(INT), sizeof(BufElements), BufElements);
+ getintarray16(parg16->f2, INT32(parg16->f1), p2);
+ GETDWORDARRAY16(parg16->f3, INT32(parg16->f1), p3);
+
+ if (SetSysColors(
+ INT32(parg16->f1),
+ p2,
+ p3
+ ) == FALSE) {
+#ifndef i386
+ PDWORD p4;
+ ULONG BufRGB [SSC_BUF_SIZE];
+
+ // On RISC platforms, SetSysColors could fail if the third parameter
+ // is unaligned. We need to check that and copy it to an aligned
+ // buffer before making this call. Win16 SetSysColor never fails
+ // so on x86 if this ever fails under NT, it will just pass through.
+
+ if ((ULONG)p3 & 3) {
+
+ p4 = STACKORHEAPALLOC(INT32(parg16->f1) * sizeof(INT), sizeof(BufRGB), BufRGB);
+
+ RtlMoveMemory ((PVOID)p4, (CONST VOID *)p3,
+ INT32(parg16->f1) * sizeof(ULONG));
+
+
+ SetSysColors(
+ INT32(parg16->f1),
+ p2,
+ p4
+ );
+ STACKORHEAPFREE(p4, BufRGB);
+ }
+#endif
+
+ }
+
+ FREEDWORDARRAY16(p3);
+ STACKORHEAPFREE(p2, BufElements);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+#ifdef NEVER
+// this is implemented locally now
+
+/*++
+ HWND SetSysModalWindow(<hwnd>)
+ HWND <hwnd>;
+
+ The %SetSysModalWindow% function makes the specified window a system-modal
+ window.
+
+ <hwnd>
+ Identifies the window to be made system modal.
+
+ The return value identifies the window that was previously the system-modal
+ window.
+
+ If another window is made the active window (for example, the system-modal
+ window creates a dialog box that becomes the active window), the active
+ window becomes the system-modal window. When the original window becomes
+ active again, it is system modal. To end the system-modal state, destroy the
+ system-modal window.
+--*/
+
+ULONG FASTCALL WU32SetSysModalWindow(PVDMFRAME pFrame)
+{
+ RETURN(0);
+}
+
+#endif // NEVER
+
+/*++
+ void ShowOwnedPopups(<hwnd>, <fShow>)
+
+ The %ShowOwnedPopups% function shows or hides all pop-up windows that are
+ associated with the <hwnd> parameter. If the <fShow> parameter is TRUE,
+ all hidden pop-up windows are shown; if <fShow> is FALSE, all visible pop-up
+ windows are hidden.
+
+ <hwnd>
+ Identifies the window that owns the pop-up windows that are to be shown
+ or hidden.
+
+ <fShow>
+ Specifies whether or not pop-up windows are hidden. It is TRUE if all
+ hidden pop-up windows should be shown; it is FALSE if all visible pop-up
+ windows should be hidden.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32ShowOwnedPopups(PVDMFRAME pFrame)
+{
+ register PSHOWOWNEDPOPUPS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SHOWOWNEDPOPUPS16), parg16);
+
+ ShowOwnedPopups(
+ HWND32(parg16->f1),
+ BOOL32(parg16->f2)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ BOOL SwapMouseButton(<bSwap>)
+
+ The %SwapMouseButton% function reverses the meaning of left and right mouse
+ buttons. If the <bSwap> parameter is TRUE, the left button generates
+ right-button mouse messages and the right button generates left-button
+ messages. If <bSwap> is FALSE, the buttons are restored to their original
+ meaning.
+
+ <bSwap>
+ Specifies whether the button meanings are reversed or restored.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ fuction reversed the meaning of the mouse buttons. Otherwise, it is FALSE.
+
+ Button swapping is provided as a convenience to people who use the mouse
+ with their left hands. The %SwapMouseButton% function is usually called by
+ the control panel only. Although applications are free to call the function,
+ the mouse is a shared resource and reversing the meaning of the mouse button
+ affects all applications.
+--*/
+
+ULONG FASTCALL WU32SwapMouseButton(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSWAPMOUSEBUTTON16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SWAPMOUSEBUTTON16), parg16);
+
+ ul = GETBOOL16(SwapMouseButton(
+ BOOL32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void InvalidateRect(<hwnd>, <lpRect>, <bErase>)
+ HWND <hwnd>;
+ LPRECT <lpRect>;
+ BOOL <bErase>;
+
+ The %InvalidateRect% function invalidates the client area within the given
+ rectangle by adding that rectangle to the window's update region. The
+ invalidated rectangle, along with all other areas in the update region, is
+ marked for painting when the next WM_PAINT message occurs. The invalidated
+ areas accumulate in the update region until the region is processed when the
+ next WM_PAINT message occurs, or the region is validated by using the
+ %ValidateRect% or %ValidateRgn% function.
+
+ The <bErase> parameter specifies whether the background within the update
+ area is to be erased when the update region is processed. If <bErase> is
+ TRUE, the background is erased when the %BeginPaint% function is called;
+ if <bErase> is FALSE, the background remains unchanged. If <bErase> is
+ TRUE for any part of the update region, the background in the entire
+ region is erased, not just in the given part.
+
+ <hwnd>
+ Identifies the window whose update region is to be modified.
+
+ <lpRect>
+ Points to a %RECT% structure that contains the rectangle
+ (in client coordinates) to be added to the update region. If the
+ <lpRect> parameter is NULL, the entire client area is added to the
+ region.
+
+ <bErase>
+ Specifies whether the background within the update region is to
+ be erased.
+
+ This function does not return a value.
+
+ Windows sends a WM_PAINT message to a window whenever its update region is
+ not empty and there are no other messages in the application queue for that
+ window.
+--*/
+
+ULONG FASTCALL WU32ValidateRect(PVDMFRAME pFrame)
+{
+ RECT t2, *p2;
+ register PVALIDATERECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(VALIDATERECT16), parg16);
+ p2 = GETRECT16(parg16->f2, &t2);
+
+ ValidateRect(
+ HWND32(parg16->f1),
+ p2
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(1); // Win 3.x always returned 1 as a side-effect of jmping to
+ // IRedrawWindow [core\user\wmupdate.c] - MarkRi 5/93
+}
+
+
+/*++
+ void InvalidateRgn(<hwnd>, <hRgn>, <bErase>)
+ HWND <hwnd>;
+ HRGN <hRgn>;
+ BOOL <bErase>;
+
+ The %InvalidateRgn% function invalidates the client area within the given
+ region by adding it to the current update region of the given window. The
+ invalidated region, along with all other areas in the update region, is
+ marked for painting when the next WM_PAINT message occurs. The invalidated
+ areas accumulate in the update region until the region is processed when the
+ next WM_PAINT message occurs, or the region is validated by using the
+ %ValidateRect% or %ValidateRgn% function.
+
+ The <bErase> parameter specifies whether the background within the update
+ area is to be erased when the update region is processed. If <bErase> is
+ TRUE, the background is erased when the %BeginPaint% function is called; if
+ <bErase> is FALSE, the background remains unchanged. If <bErase> is TRUE for
+ any part of the update region, the background in the entire region is
+ erased, not just in the given part.
+
+ <hwnd>
+ Identifies the window whose update region is to be modified.
+
+ <hRgn>
+ Identifies the region to be added to the update region. The
+ region is assumed to have client coordinates.
+
+ <bErase>
+ Specifies whether the background within the update region is to
+ be erased.
+
+ This function does not return a value.
+
+ Windows sends a WM_PAINT message to a window whenever its update region is
+ not empty and there are no other messages in the application queue for that
+ window.
+
+ The given region must have been previously created by using one of the
+ region functions (for more information, see Chapter 1, Window Manager
+ Interface Functions).
+--*/
+
+ULONG FASTCALL WU32ValidateRgn(PVDMFRAME pFrame)
+{
+ register PVALIDATERGN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(VALIDATERGN16), parg16);
+
+ ValidateRgn(
+ HWND32(parg16->f1),
+ HRGN32(parg16->f2)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(1); // Win 3.x always returned 1 as a side-effect of jmping to
+ // IRedrawWindow [core\user\wmupdate.c] - MarkRi 5/93
+}
+
+
+/*++
+ BOOL WinHelp(<hwnd>, <lpHelpFile>, <wCommand>, <dwData>)
+ HWND <hwnd>;
+ LPSTR <lpHelpFile>;
+ WORD <wCommand>;
+ DWORD <dwData>;
+
+ This function invokes the Windows Help application and passes optional data
+ indicating the nature of the help requested by the application. The
+ application specifies the name and, where required, the directory path of
+ the help file which the Help application is to display.
+
+ <hwnd>
+ Identifies the window requesting help.
+
+ <lpHelpFile>
+ Points to a null-terminated string containing the directory
+ path, if needed, and the name of the help file which the Help
+ application is to display.
+
+ <wCommand>
+ Specifies the type of help requested. It may be any one of the
+ following values:
+
+ HELP_CONTEXT
+ Displays help for a particular context identified by a 32-bit unsigned
+ integer value in dwData.
+
+ HELP_HELPONHELP
+ Displays help for using the help application itself. If the <wCommand>
+ parameter is set to HELP_HELPONHELP, %WinHelp% ignores the
+ <lpHelpFile> and <dwData> parameters.
+
+ HELP_INDEX
+ Displays the index of the specified help file. An application should use
+ this value only for help files with a single index. It should not use
+ this value with HELP_SETINDEX.
+
+ HELP_MULTIKEY
+ Displays help for a key word in an alternate keyword table.
+
+ HELP_QUIT
+ Notifies the help application that the specified help file is no longer
+ in use.
+
+ HELP_SETINDEX
+ Sets the context specified by the <dwData> parameter as the current
+ index for the help file specified by the <lpHelpFile> parameter. This
+ index remains current until the user accesses a different help file. To
+ help ensure that the correct index remains set, the application should
+ call %WinHelp% with <wCommand> set to HELP_SETINDEX (with <dwData>
+ specifying the corresponding context identifier) following each call to
+ %WinHelp% with <wCommand> set to HELP_CONTEXT. An application should use
+ this value only for help files with more than one index. It should not
+ use this value with HELP_INDEX.
+
+ <dwData>
+ %DWORD% Specifies the context or key word of the help requested. If
+ <wCommand> is HELP_CONTEXT, <dwData> is a 32-bit unsigned integer
+ containing a context-identifier number. If <wCommand> is HELP_KEY,
+ <dwData> is a long pointer to a null-terminated string that contains a
+ key word identifying the help topic. If <wCommand> is HELP_MULTIKEY,
+ <dwData> is a long pointer to a %MULTIKEYHELP% structure.
+ Otherwise, <dwData> is ignored and should be set to NULL.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ function was successful. Otherwise it is FALSE.
+
+ The application must call %WinHelp% with <wCommand> set to HELP_QUIT before
+ closing the window that requested the help. The Help application will not
+ actually terminate until all applications that have requested help have
+ called %WinHelp% with <wCommand> set to HELP_QUIT.
+--*/
+
+#if 0
+// this function no longer thunked
+ULONG FASTCALL WU32WinHelp(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PWINHELP16 parg16;
+ DWORD dwCommand;
+ DWORD dwData;
+ UINT cb;
+ MULTIKEYHELP *lpmkey;
+ PMULTIKEYHELP16 pmkey16;
+ HELPWININFO hwinfo;
+ PHELPWININFO16 phwinfo16;
+
+ GETARGPTR(pFrame, sizeof(WINHELP16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+ dwCommand = WORD32(parg16->f3);
+
+ switch (dwCommand) {
+ case HELP_KEY:
+ case HELP_COMMAND:
+ case HELP_PARTIALKEY:
+ GETPSZPTR(parg16->f4, (PSZ)dwData);
+ break;
+
+ case HELP_MULTIKEY:
+ GETVDMPTR(parg16->f4, sizeof(MULTIKEYHELP16), pmkey16);
+ cb = FETCHWORD(pmkey16->mkSize);
+ FREEVDMPTR(pmkey16);
+ GETVDMPTR(parg16->f4, cb, pmkey16);
+
+ //
+ // It is my understanding that 'mkSize' is the total
+ // data length and NOT just sizeof(MULTIKEYHELP)
+ //
+
+ cb += sizeof(MULTIKEYHELP) - sizeof(MULTIKEYHELP16);
+ lpmkey = (MULTIKEYHELP *)malloc_w(cb);
+ if (lpmkey) {
+ lpmkey->mkSize = cb;
+ lpmkey->mkKeylist = pmkey16->mkKeylist;
+ strcpy(lpmkey->szKeyphrase, pmkey16->szKeyphrase);
+ }
+ FREEVDMPTR(pmkey16);
+ dwData = (DWORD)lpmkey;
+ break;
+
+ case HELP_SETWINPOS:
+ GETVDMPTR(parg16->f4, sizeof(HELPWININFO16), phwinfo16);
+
+ hwinfo.wStructSize = (int)(FETCHWORD(phwinfo16->wStructSize) +
+ (sizeof(HELPWININFO) - sizeof(HELPWININFO16)));
+ hwinfo.x = (int)FETCHSHORT(phwinfo16->x);
+ hwinfo.y = (int)FETCHSHORT(phwinfo16->y);
+ hwinfo.dx = (int)FETCHSHORT(phwinfo16->dx);
+ hwinfo.dy = (int)FETCHSHORT(phwinfo16->dy);
+ hwinfo.wMax = (int)FETCHSHORT(phwinfo16->wMax);
+ hwinfo.rgchMember[0] = (CHAR)phwinfo16->rgchMember[0];
+ hwinfo.rgchMember[1] = (CHAR)phwinfo16->rgchMember[1];
+
+ FREEVDMPTR(phwinfo16);
+ dwData = (DWORD)&hwinfo;
+ break;
+
+ default:
+ dwData = DWORD32(parg16->f4);
+ break;
+ }
+
+ ul = GETBOOL16(WinHelp(HWND32(parg16->f1), psz2, dwCommand, dwData));
+
+ switch (dwCommand) {
+ case HELP_KEY:
+ case HELP_COMMAND:
+ case HELP_PARTIALKEY:
+ FREEPSZPTR((PSZ)dwData);
+ break;
+
+ case HELP_MULTIKEY:
+ if (lpmkey)
+ free_w(lpmkey);
+ break;
+
+ case HELP_SETWINPOS:
+ break;
+
+ default:
+ break;
+ }
+
+
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+#endif
+
+
+#pragma pack(1)
+
+//
+// win16 Module Table structure (based off of ne header)
+// see wow16\inc\newexe.inc
+//
+
+typedef struct _NE_MODULE {
+ USHORT ne_magic; // Magic number
+ USHORT ne_usage; // usage count of module
+ USHORT ne_enttab; // Offset of Entry Table
+ USHORT ne_pnextexe; // sel next module table
+ USHORT ne_pautodata; // offset autodata seg table
+ USHORT ne_pfileinfo; // offset load file info
+ USHORT ne_flags; // Flag word
+ USHORT ne_autodata; // Automatic data segment number
+ USHORT ne_heap; // Initial heap allocation
+ USHORT ne_stack; // Initial stack allocation
+ ULONG ne_csip; // Initial CS:IP setting
+ ULONG ne_sssp; // Initial SS:SP setting
+ USHORT ne_cseg; // Count of file segments
+ USHORT ne_cmod; // Entries in Module Reference Table
+ USHORT ne_cbnrestab; // Size of non-resident name table
+ USHORT ne_segtab; // Offset of Segment Table
+ USHORT ne_rsrctab; // Offset of Resource Table
+ USHORT ne_restab; // Offset of resident name table
+ USHORT ne_modtab; // Offset of Module Reference Table
+ USHORT ne_imptab; // Offset of Imported Names Table
+ ULONG ne_nrestab; // Offset of Non-resident Names Table
+ USHORT ne_cmovent; // Count of movable entries
+ USHORT ne_align; // Segment alignment shift count
+ USHORT ne_cres; // Count of resource segments
+ UCHAR ne_exetyp; // Target Operating system
+ UCHAR ne_flagsothers; // Other .EXE flags
+ USHORT ne_pretthunks; // offset to return thunks
+ USHORT ne_psegrefbytes; // offset to segment ref. bytes
+ USHORT ne_swaparea; // Minimum code swap area size
+ USHORT ne_expver; // Expected Windows version number
+} NEMODULE;
+typedef NEMODULE UNALIGNED *PNEMODULE;
+
+#pragma pack()
+
+//
+// Performs Module cleanup (win31:tmdstroy.c\ModuleUnload())
+//
+void
+ModuleUnload(
+ HAND16 hModule16,
+ BOOL fTaskExit
+ )
+{
+ PNEMODULE pNeModule = SEGPTR(hModule16, 0);
+ PTD ptd = CURRENTPTD();
+
+ if (pNeModule->ne_usage == 1 || fTaskExit) {
+ W32UnhookHooks(hModule16,FALSE);
+ }
+
+ if (fTaskExit) {
+ ptd->dwFlags |= TDF_TASKCLEANUPDONE;
+ (pfnOut.pfnWOWCleanup)(HINSTRES32(ptd->hInst16), (DWORD) ptd->htask16, NULL, 0);
+ }
+
+ if (pNeModule->ne_usage > 1) {
+ return;
+ }
+
+
+ /* WowCleanup, UserSrv private api
+ * It cleans up any USER objects created by this hModule, most notably
+ * classes, and subclassed windows.
+ */
+ (pfnOut.pfnWOWCleanup)((HANDLE)hModule16,
+ 0,
+ (PNEMODULESEG)((ULONG)pNeModule + pNeModule->ne_segtab),
+ pNeModule->ne_cseg
+ );
+
+ RemoveHmodFromCache(hModule16);
+
+}
+
+
+
+
+/*++
+ BOOL SignalProc(<hwnd>, <lpHelpFile>, <wCommand>, <dwData>)
+ HWND <hwnd>;
+ LPSTR <lpHelpFile>;
+ WORD <wCommand>;
+ DWORD <dwData>;
+
+ This function provides the communication link between KERNEL and USER.
+
+--*/
+
+#define SG_EXIT 0x0020
+#define SG_LOAD_DLL 0x0040
+#define SG_EXIT_DLL 0x0080
+#define SG_GP_FAULT 0x0666
+
+
+
+ULONG FASTCALL WU32SignalProc(PVDMFRAME pFrame)
+{
+ WORD message;
+ LONG lparam;
+ register PSIGNALPROC16 parg16;
+ HAND16 hModule16;
+ PTD ptd;
+
+ GETARGPTR(pFrame, sizeof(SIGNALPROC16), parg16);
+ message = FETCHWORD(parg16->f2);
+
+ switch( message ) {
+ case SG_EXIT:
+ case SG_GP_FAULT:
+ lparam = FETCHDWORD(parg16->f4);
+ ptd = CURRENTPTD();
+ ptd->dwFlags |= TDF_INITCALLBACKSTACK | TDF_IGNOREINPUT;
+ ModuleUnload(GetExePtr16((HAND16)HIWORD(lparam)), TRUE);
+ FreeCursorIconAlias(ptd->htask16, CIALIAS_HTASK);
+ break;
+
+ case SG_LOAD_DLL:
+ break;
+
+ case SG_EXIT_DLL:
+ hModule16 = FETCHWORD(parg16->f1);
+ ModuleUnload(hModule16, FALSE);
+ FreeCursorIconAlias(hModule16, CIALIAS_HMOD);
+ break;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+
+
+
+// This routine checks the RECT structure (in PAINTSTRUCT) on BeginPaint
+// call and updates its fields for maximum positive and minimum negative
+// numbers for 16 bit apps to be compatible with win 3.1.
+//
+
+void W32FixPaintRect (VPVOID vpPaint, LPPAINTSTRUCT ps)
+{
+ SHORT i;
+ PPAINTSTRUCT16 pps16;
+
+ GETVDMPTR(vpPaint, sizeof(PAINTSTRUCT16), pps16);
+
+ if (i = ConvertInt16 (ps->rcPaint.left)) {
+ STORESHORT(pps16->rcPaint.left, i);
+ }
+
+ if (i = ConvertInt16 (ps->rcPaint.top)) {
+ STORESHORT(pps16->rcPaint.top, i);
+ }
+
+ if (i = ConvertInt16 (ps->rcPaint.right)) {
+ STORESHORT(pps16->rcPaint.right, i);
+ }
+
+ if (i = ConvertInt16 (ps->rcPaint.bottom)) {
+ STORESHORT(pps16->rcPaint.bottom, i);
+ }
+
+ FLUSHVDMPTR(vpPaint, sizeof(PAINTSTRUCT16), pps16);
+ FREEVDMPTR(pps16);
+}
+
+SHORT ConvertInt16 (LONG x)
+{
+ if (x > (LONG)0x7fff)
+ return((SHORT)0x7fff);
+
+ if (x < (LONG)0xffff8000)
+ return((SHORT)0x8000);
+
+ return ((SHORT)0);
+}
diff --git a/private/mvdm/wow32/wuser.h b/private/mvdm/wow32/wuser.h
new file mode 100644
index 000000000..137e7e381
--- /dev/null
+++ b/private/mvdm/wow32/wuser.h
@@ -0,0 +1,93 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUSER.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+typedef struct _GRAYSTRINGDATA { /* graystringdata */
+ VPPROC vpfnGrayStringProc; // 16-bit function
+ DWORD dwUserParam; // user param
+ HDC16 hdc;
+ BOOL fResetLengthToZero;
+} GRAYSTRINGDATA, *PGRAYSTRINGDATA;
+
+
+
+ULONG FASTCALL WU32BeginPaint(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CreateIcon(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DestroyIcon(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DragDetect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DragObject(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DrawFocusRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DrawIcon(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DrawText(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EnableHardwareInput(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EndPaint(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EnumProps(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ExcludeUpdateRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WU32FillWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32FillRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32FrameRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetAsyncKeyState(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetCapture(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetDC(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetDoubleClickTime(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetFocus(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetInputState(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetLastActivePopup(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetProp(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetScrollPos(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetScrollRange(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetTimerResolution(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetUpdateRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetUpdateRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GlobalAddAtom(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GlobalDeleteAtom(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GlobalFindAtom(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GlobalGetAtomName(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GrayString(PVDMFRAME pFrame);
+ULONG FASTCALL WU32InvalidateRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32InvalidateRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WU32InvertRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsCharAlpha(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsCharAlphaNumeric(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsCharLower(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsCharUpper(PVDMFRAME pFrame);
+ULONG FASTCALL WU32LoadBitmap(PVDMFRAME pFrame);
+ULONG FASTCALL WU32LoadString(PVDMFRAME pFrame);
+ULONG FASTCALL WU32MessageBeep(PVDMFRAME pFrame);
+ULONG FASTCALL WU32OffsetRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32OpenIcon(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ReleaseCapture(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ReleaseDC(PVDMFRAME pFrame);
+ULONG FASTCALL WU32RemoveProp(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ScrollDC(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetCapture(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetDoubleClickTime(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetEventHook(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetFocus(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetKeyboardState(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetProp(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetScrollPos(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetScrollRange(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetSysColors(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ShowOwnedPopups(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SwapMouseButton(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ValidateRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ValidateRgn(PVDMFRAME pFrame);
+ULONG FASTCALL WU32WinHelp(PVDMFRAME pFrame);
+ULONG FASTCALL WU32lstrcmp(PVDMFRAME pFrame);
+ULONG FASTCALL WU32lstrcmpi(PVDMFRAME pFrame);
+ULONG FASTCALL WU32wvsprintf(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SignalProc(PVDMFRAME pFrame);
+
+ULONG FASTCALL WU32WOWGetIdFromDirectory(PVDMFRAME pFrame);
+void W32FixPaintRect (VPVOID vpPaint, LPPAINTSTRUCT ps);
+SHORT ConvertInt16 (LONG x);
diff --git a/private/mvdm/wow32/wuser31.c b/private/mvdm/wow32/wuser31.c
new file mode 100644
index 000000000..ae505ee49
--- /dev/null
+++ b/private/mvdm/wow32/wuser31.c
@@ -0,0 +1,931 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUSER31.C
+ * WOW32 16-bit Win 3.1 User API support
+ *
+ * History:
+ * Created 16-Mar-1992 by Chandan S. Chauhan (ChandanC)
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wuser31.c);
+
+ULONG FASTCALL WU32DlgDirSelectComboBoxEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PDLGDIRSELECTCOMBOBOXEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DLGDIRSELECTCOMBOBOXEX16), parg16);
+ GETVDMPTR(parg16->f2, INT32(parg16->f3), psz2);
+
+ ul = GETBOOL16(DlgDirSelectComboBoxEx(
+ HWND32(parg16->f1),
+ psz2,
+ INT32(parg16->f3),
+ WORD32(parg16->f4) // we zero-extend window IDs everywhere
+ ));
+
+ FLUSHVDMPTR(parg16->f2, INT32(parg16->f3), psz2);
+ FREEVDMPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32DlgDirSelectEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PDLGDIRSELECTEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DLGDIRSELECTEX16), parg16);
+ GETVDMPTR(parg16->f2, INT32(parg16->f3), psz2);
+
+ ul = GETBOOL16(DlgDirSelectEx(
+ HWND32(parg16->f1),
+ psz2,
+ INT32(parg16->f3),
+ WORD32(parg16->f4)
+ ));
+
+ FLUSHVDMPTR(parg16->f2, INT32(parg16->f3), psz2);
+ FREEVDMPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32EnableScrollBar(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+
+ register PENABLESCROLLBAR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENABLESCROLLBAR16), parg16);
+
+ ul = GETBOOL16(EnableScrollBar(HWND32(parg16->f1),
+ WORD32(parg16->f2),
+ WORD32(parg16->f3)));
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32GetClipCursor(PVDMFRAME pFrame)
+{
+ RECT Rect;
+ register PGETCLIPCURSOR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCLIPCURSOR16), parg16);
+
+ GetClipCursor(&Rect);
+
+ PUTRECT16(parg16->f1, &Rect);
+
+ FREEARGPTR(parg16);
+
+ RETURN (0); // GetClipCursor has no return value
+}
+
+
+ULONG FASTCALL WU32GetCursor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETHCURSOR16(GetCursor());
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32GetDCEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETDCEX16 parg16;
+ HAND16 htask16 = pFrame->wTDB;
+
+ GETARGPTR(pFrame, sizeof(GETDCEX16), parg16);
+
+ ul = GETHDC16(GetDCEx(HWND32(parg16->f1),
+ HRGN32(parg16->f2),
+ DWORD32(parg16->f3)));
+
+ if (ul)
+ StoreDC(htask16, parg16->f1, (HAND16)ul);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32GetMessageExtraInfo(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETLONG16(GetMessageExtraInfo());
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32GetOpenClipboardWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ ul = GETHWND16(GetOpenClipboardWindow());
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32IsMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISMENU16), parg16);
+
+ ul = GETBOOL16(IsMenu(HMENU32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32LockWindowUpdate(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PLOCKWINDOWUPDATE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(LOCKWINDOWUPDATE16), parg16);
+
+ ul = GETBOOL16(LockWindowUpdate(HWND32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32RedrawWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ RECT Rect, *p2;
+ register PREDRAWWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(REDRAWWINDOW16), parg16);
+
+ p2 = GETRECT16 (parg16->f2, &Rect);
+
+ ul = GETBOOL16(RedrawWindow(HWND32(parg16->f1),
+ p2,
+ HRGN32(parg16->f3),
+ WORD32(parg16->f4)));
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32ScrollWindowEx(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSCROLLWINDOWEX16 parg16;
+
+ RECT RectScroll, *p4;
+ RECT RectClip, *p5;
+ RECT RectUpdate;
+
+ GETARGPTR(pFrame, sizeof(SCROLLWINDOWEX16), parg16);
+ p4 = GETRECT16 (parg16->f4, &RectScroll);
+ p5 = GETRECT16 (parg16->f5, &RectClip);
+
+ ul = GETINT16(ScrollWindowEx(HWND32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ p4,
+ p5,
+ HRGN32(parg16->f6),
+ &RectUpdate,
+ UINT32(parg16->f8)));
+
+ PUTRECT16 (parg16->f7, &RectUpdate);
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32SystemParametersInfo(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PSYSTEMPARAMETERSINFO16 parg16;
+ UINT wParam;
+ LONG vParam;
+ LOGFONT lf;
+ INT iMouse[3];
+ PVOID lpvParam;
+ PWORD16 lpw;
+ PDWORD16 lpdw;
+ RECT rect;
+#ifndef _X86_
+ DWORD dwSize;
+ LPBYTE lpFree = NULL;
+#endif
+
+ GETARGPTR(pFrame, sizeof(SYSTEMPARAMETERSINFO16), parg16);
+
+ // Assume these parameters fly straight through; fix them up per option
+ // if they don't
+ wParam = parg16->f2;
+ lpvParam = &vParam;
+
+ switch (parg16->f1) {
+
+ case SPI_GETICONTITLELOGFONT:
+ wParam = sizeof(LOGFONT);
+ lpvParam = &lf;
+ break;
+
+ case SPI_SETICONTITLELOGFONT:
+ GETLOGFONT16(parg16->f3, &lf);
+ wParam = sizeof(LOGFONT);
+ lpvParam = &lf;
+ break;
+
+ case SPI_GETMOUSE:
+ case SPI_SETMOUSE:
+ lpvParam = iMouse;
+ break;
+
+ case SPI_SETDESKPATTERN:
+ // For the pattern if wParam == -1 then no string for lpvParam copy as is
+ if (parg16->f2 == 0xFFFF) {
+ wParam = 0xFFFFFFFF;
+ lpvParam = (PVOID)parg16->f3;
+ break;
+ }
+ // Otherwise fall through and do a string check
+
+ case SPI_SETDESKWALLPAPER:
+ // lpvParam (f3) is may be 0,-1 or a string
+ if (parg16->f3 == 0xFFFF) {
+ lpvParam = (PVOID)0xFFFFFFFF;
+ break;
+ }
+ if (parg16->f3 == 0) {
+ lpvParam = (PVOID)NULL;
+ break;
+ }
+ // Otherwise fall through and do a string copy
+
+ case SPI_LANGDRIVER:
+ GETPSZPTR(parg16->f3, lpvParam);
+ break;
+
+ //
+ // SPI_GET structures pointed to by pvParam, size in first dword of struct.
+ // Note all these assume the Win16 and Win32 structures are equal.
+ // These are all new for Win95 and thankfully that's true. However unlike
+ // Win95 we need to ensure the buffer passed to Win32 is aligned on RISC.
+ // To have common code to thunk all these various structures, we align to
+ // 16 bytes.
+ //
+
+ case SPI_GETACCESSTIMEOUT:
+ case SPI_GETANIMATION:
+ case SPI_GETNONCLIENTMETRICS:
+ case SPI_GETMINIMIZEDMETRICS:
+ case SPI_GETICONMETRICS:
+ case SPI_GETFILTERKEYS:
+ case SPI_GETSTICKYKEYS:
+ case SPI_GETTOGGLEKEYS:
+ case SPI_GETMOUSEKEYS:
+ case SPI_GETSOUNDSENTRY:
+#ifndef _X86_
+ GETMISCPTR(parg16->f3, lpdw);
+ dwSize = *lpdw;
+ lpFree = malloc_w(dwSize + 16);
+ lpvParam = (LPVOID)(((DWORD)lpFree + 16) & ~(16 - 1));
+ *(PDWORD16)lpvParam = dwSize;
+ break;
+#endif // otherwise fall through to simple struct case
+
+ //
+ // SPI_SET structures pointed to by pvParam, size in first dword of struct.
+ // Note all these assume the Win16 and Win32 structures are equal.
+ // These are all new for Win95 and thankfully that's true. However unlike
+ // Win95 we need to ensure the buffer passed to Win32 is aligned on RISC.
+ // To have common code to thunk all these various structures, we align to
+ // 16 bytes.
+ //
+
+ case SPI_SETANIMATION:
+ case SPI_SETICONMETRICS:
+ case SPI_SETMINIMIZEDMETRICS:
+ case SPI_SETNONCLIENTMETRICS:
+ case SPI_SETACCESSTIMEOUT:
+#ifndef _X86_
+ GETMISCPTR(parg16->f3, lpdw);
+ dwSize = *lpdw;
+ lpFree = malloc_w(dwSize + 16);
+ lpvParam = (LPVOID)(((DWORD)lpFree + 16) & ~(16 - 1));
+ RtlCopyMemory(lpvParam, lpdw, dwSize);
+ break;
+#endif // otherwise fall through to simple struct case
+
+ //
+ // structures pointed to by pvParam, size in uiParam or first dword.
+ // Note all these assume the Win16 and Win32 structures are equal.
+ // These are all new for Win95 and thankfully that's true.
+ //
+
+ case SPI_GETHIGHCONTRAST:
+ case SPI_GETSERIALKEYS:
+ case SPI_SETDEFAULTINPUTLANG:
+ case SPI_SETFILTERKEYS:
+ case SPI_SETHIGHCONTRAST:
+ case SPI_SETMOUSEKEYS:
+ case SPI_SETSERIALKEYS:
+ case SPI_SETSHOWSOUNDS:
+ case SPI_SETSOUNDSENTRY:
+ case SPI_SETSTICKYKEYS:
+ case SPI_SETTOGGLEKEYS:
+ GETMISCPTR(parg16->f3, lpvParam);
+ break;
+
+ //
+ // pvParam points to WORD or BOOL
+ //
+
+ case SPI_GETBEEP:
+ case SPI_GETBORDER:
+ case SPI_GETDRAGFULLWINDOWS:
+ case SPI_GETFASTTASKSWITCH:
+ case SPI_GETFONTSMOOTHING:
+ case SPI_GETGRIDGRANULARITY:
+ case SPI_GETICONTITLEWRAP:
+ case SPI_GETKEYBOARDSPEED:
+ case SPI_GETKEYBOARDDELAY:
+ case SPI_GETKEYBOARDPREF:
+ case SPI_GETLOWPOWERACTIVE:
+ case SPI_GETLOWPOWERTIMEOUT:
+ case SPI_GETMENUDROPALIGNMENT:
+ case SPI_GETMOUSETRAILS:
+ case SPI_GETPOWEROFFACTIVE:
+ case SPI_GETPOWEROFFTIMEOUT:
+ case SPI_GETSCREENREADER:
+ case SPI_GETSCREENSAVEACTIVE:
+ case SPI_GETSCREENSAVETIMEOUT:
+ case SPI_GETSHOWSOUNDS:
+ case SPI_SCREENSAVERRUNNING:
+ break;
+
+ //
+ // pvParam points to DWORD
+ //
+
+ case SPI_GETDEFAULTINPUTLANG:
+ break;
+
+ //
+ // pvParam not used
+ //
+
+ case SPI_GETWINDOWSEXTENSION:
+ case SPI_ICONHORIZONTALSPACING:
+ case SPI_ICONVERTICALSPACING:
+ case SPI_SETBEEP:
+ case SPI_SETBORDER:
+ case SPI_SETDOUBLECLICKTIME:
+ case SPI_SETDOUBLECLKHEIGHT:
+ case SPI_SETDOUBLECLKWIDTH:
+ case SPI_SETDRAGFULLWINDOWS:
+ case SPI_SETDRAGHEIGHT:
+ case SPI_SETDRAGWIDTH:
+ case SPI_SETFASTTASKSWITCH:
+ case SPI_SETFONTSMOOTHING:
+ case SPI_SETGRIDGRANULARITY:
+ case SPI_SETHANDHELD:
+ case SPI_SETICONTITLEWRAP:
+ case SPI_SETKEYBOARDDELAY:
+ case SPI_SETKEYBOARDPREF:
+ case SPI_SETKEYBOARDSPEED:
+ case SPI_SETLANGTOGGLE:
+ case SPI_SETLOWPOWERACTIVE:
+ case SPI_SETLOWPOWERTIMEOUT:
+ case SPI_SETMENUDROPALIGNMENT:
+ case SPI_SETMOUSEBUTTONSWAP:
+ case SPI_SETMOUSETRAILS:
+ case SPI_SETPENWINDOWS:
+ case SPI_SETPOWEROFFACTIVE:
+ case SPI_SETPOWEROFFTIMEOUT:
+ case SPI_SETSCREENREADER:
+ case SPI_SETSCREENSAVEACTIVE:
+ case SPI_SETSCREENSAVETIMEOUT:
+ break;
+
+ //
+ // pvParam points to a RECT
+ //
+
+ case SPI_GETWORKAREA:
+ case SPI_SETWORKAREA:
+ GETRECT16(parg16->f3, &rect);
+ lpvParam = &rect;
+ break;
+
+
+ default:
+#ifdef DEBUG
+ {
+ DWORD dwSaveOptions = flOptions;
+ flOptions |= OPT_DEBUG;
+ LOGDEBUG(0, ("WARNING SystemParametersInfo case %d not pre-thunked in WOW!\n", parg16->f1));
+ flOptions = dwSaveOptions;
+ }
+#endif
+ break;
+ }
+
+
+ ul = SystemParametersInfo(
+ UINT32(parg16->f1),
+ wParam,
+ lpvParam,
+ UINT32(parg16->f4)
+ );
+
+
+ switch (parg16->f1) {
+ case SPI_GETICONTITLELOGFONT:
+ PUTLOGFONT16(parg16->f3, sizeof(LOGFONT), lpvParam);
+ break;
+
+ case SPI_SETICONTITLELOGFONT:
+ break;
+
+ case SPI_GETMOUSE:
+ case SPI_SETMOUSE:
+ PUTINTARRAY16(parg16->f3, 3, lpvParam);
+ break;
+
+ case SPI_LANGDRIVER:
+ case SPI_SETDESKWALLPAPER:
+ FREEPSZPTR(lpvParam);
+ break;
+
+ case SPI_ICONHORIZONTALSPACING:
+ case SPI_ICONVERTICALSPACING:
+ // optional outee
+ if (!parg16->f3)
+ break;
+
+ // fall through
+
+
+ //
+ // pvParam points to WORD or BOOL
+ //
+
+ case SPI_GETBEEP:
+ case SPI_GETBORDER:
+ case SPI_GETDRAGFULLWINDOWS:
+ case SPI_GETFASTTASKSWITCH:
+ case SPI_GETFONTSMOOTHING:
+ case SPI_GETGRIDGRANULARITY:
+ case SPI_GETICONTITLEWRAP:
+ case SPI_GETKEYBOARDSPEED:
+ case SPI_GETKEYBOARDDELAY:
+ case SPI_GETKEYBOARDPREF:
+ case SPI_GETLOWPOWERACTIVE:
+ case SPI_GETLOWPOWERTIMEOUT:
+ case SPI_GETMENUDROPALIGNMENT:
+ case SPI_GETMOUSETRAILS:
+ case SPI_GETPOWEROFFACTIVE:
+ case SPI_GETPOWEROFFTIMEOUT:
+ case SPI_GETSCREENREADER:
+ case SPI_GETSCREENSAVEACTIVE:
+ case SPI_GETSCREENSAVETIMEOUT:
+ case SPI_GETSHOWSOUNDS:
+ case SPI_SCREENSAVERRUNNING:
+ GETVDMPTR(FETCHDWORD(parg16->f3), sizeof(*lpw), lpw);
+
+ *lpw = (WORD)(*(LPLONG)lpvParam);
+
+ FLUSHVDMPTR(FETCHDWORD(parg16->f3), sizeof(*lpw), lpw);
+ FREEVDMPTR(lpw);
+
+ break;
+
+ //
+ // pvParam points to DWORD
+ //
+
+ case SPI_GETDEFAULTINPUTLANG:
+ GETVDMPTR(FETCHDWORD(parg16->f3), sizeof(*lpdw), lpdw);
+
+ *lpdw = *(LPDWORD)lpvParam;
+
+ FLUSHVDMPTR(FETCHDWORD(parg16->f3), sizeof(*lpdw), lpdw);
+ FREEVDMPTR(lpdw);
+
+ break;
+
+ //
+ // SPI_GET structures pointed to by pvParam, size in first dword of struct.
+ // Note all these assume the Win16 and Win32 structures are equal.
+ // These are all new for Win95 and thankfully that's true. However unlike
+ // Win95 we need to ensure the buffer passed to Win32 is aligned. In order
+ // to have common code to thunk all these various structures, we align to
+ // 16 bytes.
+ //
+
+ case SPI_GETACCESSTIMEOUT:
+ case SPI_GETANIMATION:
+ case SPI_GETNONCLIENTMETRICS:
+ case SPI_GETMINIMIZEDMETRICS:
+ case SPI_GETICONMETRICS:
+ case SPI_GETFILTERKEYS:
+ case SPI_GETSTICKYKEYS:
+ case SPI_GETTOGGLEKEYS:
+ case SPI_GETMOUSEKEYS:
+ case SPI_GETSOUNDSENTRY:
+#ifndef _X86_
+ RtlCopyMemory(lpdw, lpvParam, dwSize);
+ FREEMISCPTR(lpdw);
+ break;
+#endif // otherwise fall through to simple struct case
+
+ //
+ // SPI_SET structures pointed to by pvParam, size in first dword of struct.
+ // Note all these assume the Win16 and Win32 structures are equal.
+ // These are all new for Win95 and thankfully that's true. However unlike
+ // Win95 we need to ensure the buffer passed to Win32 is aligned. In order
+ // to have common code to thunk all these various structures, we align to
+ // 16 bytes.
+ //
+
+ case SPI_SETANIMATION:
+ case SPI_SETICONMETRICS:
+ case SPI_SETMINIMIZEDMETRICS:
+ case SPI_SETNONCLIENTMETRICS:
+ case SPI_SETACCESSTIMEOUT:
+#ifndef _X86_
+ FREEMISCPTR(lpdw);
+ break;
+#endif // otherwise fall through to simple struct case
+
+ //
+ // structures pointed to by pvParam, size in uiParam or first dword.
+ // Note all these assume the Win16 and Win32 structures are equal.
+ // These are all new for Win95 and thankfully that's true.
+ //
+
+ case SPI_GETHIGHCONTRAST:
+ case SPI_GETSERIALKEYS:
+ case SPI_SETDEFAULTINPUTLANG:
+ case SPI_SETFILTERKEYS:
+ case SPI_SETHIGHCONTRAST:
+ case SPI_SETMOUSEKEYS:
+ case SPI_SETSERIALKEYS:
+ case SPI_SETSHOWSOUNDS:
+ case SPI_SETSOUNDSENTRY:
+ case SPI_SETSTICKYKEYS:
+ case SPI_SETTOGGLEKEYS:
+ FREEMISCPTR(lpvParam);
+ break;
+
+
+ //
+ // pvParam not used
+ //
+
+ case SPI_GETWINDOWSEXTENSION:
+ case SPI_SETBEEP:
+ case SPI_SETBORDER:
+ case SPI_SETDOUBLECLICKTIME:
+ case SPI_SETDOUBLECLKHEIGHT:
+ case SPI_SETDOUBLECLKWIDTH:
+ case SPI_SETDRAGFULLWINDOWS:
+ case SPI_SETDRAGHEIGHT:
+ case SPI_SETDRAGWIDTH:
+ case SPI_SETFASTTASKSWITCH:
+ case SPI_SETFONTSMOOTHING:
+ case SPI_SETGRIDGRANULARITY:
+ case SPI_SETHANDHELD:
+ case SPI_SETICONTITLEWRAP:
+ case SPI_SETKEYBOARDDELAY:
+ case SPI_SETKEYBOARDPREF:
+ case SPI_SETKEYBOARDSPEED:
+ case SPI_SETLANGTOGGLE:
+ case SPI_SETLOWPOWERACTIVE:
+ case SPI_SETLOWPOWERTIMEOUT:
+ case SPI_SETMENUDROPALIGNMENT:
+ case SPI_SETMOUSEBUTTONSWAP:
+ case SPI_SETMOUSETRAILS:
+ case SPI_SETPENWINDOWS:
+ case SPI_SETPOWEROFFACTIVE:
+ case SPI_SETPOWEROFFTIMEOUT:
+ case SPI_SETSCREENREADER:
+ case SPI_SETSCREENSAVEACTIVE:
+ case SPI_SETSCREENSAVETIMEOUT:
+ break;
+
+ //
+ // pvParam points to a RECT
+ //
+
+ case SPI_GETWORKAREA:
+ case SPI_SETWORKAREA:
+ PUTRECT16(parg16->f3, &rect);
+ break;
+
+
+ default:
+#ifdef DEBUG
+ {
+ DWORD dwSaveOptions = flOptions;
+ flOptions |= OPT_DEBUG;
+ LOGDEBUG(0, ("WARNING SystemParametersInfo case %d not post-thunked in WOW!\n", parg16->f1));
+ flOptions = dwSaveOptions;
+ }
+#endif
+ break;
+ }
+
+#ifndef _X86_
+ if (lpFree) {
+ free_w(lpFree);
+ }
+#endif
+
+ FREEARGPTR(parg16);
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32SetWindowPlacement(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PSETWINDOWPLACEMENT16 parg16;
+
+ WINDOWPLACEMENT wndpl;
+
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWPLACEMENT16), parg16);
+
+ WINDOWPLACEMENT16TO32(parg16->f2, &wndpl);
+
+ ul = GETBOOL16(SetWindowPlacement(HWND32(parg16->f1),
+ &wndpl));
+
+ FREEARGPTR(parg16);
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32GetWindowPlacement(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PGETWINDOWPLACEMENT16 parg16;
+
+ WINDOWPLACEMENT wndpl;
+
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWPLACEMENT16), parg16);
+
+ wndpl.length = sizeof(WINDOWPLACEMENT);
+
+ ul = GETBOOL16(GetWindowPlacement(HWND32(parg16->f1),
+ &wndpl));
+
+ WINDOWPLACEMENT32TO16(parg16->f2, &wndpl);
+
+ FREEARGPTR(parg16);
+ RETURN (ul);
+}
+
+
+
+
+
+ULONG FASTCALL WU32GetFreeSystemResources(PVDMFRAME pFrame)
+{
+ register PGETFREESYSTEMRESOURCES16 parg16;
+ ULONG ul = 0;
+
+ GETARGPTR(pFrame, sizeof(GETFREESYSTEMRESOURCES16), parg16);
+
+
+#ifdef APRIL15 // Win32 doesn't have GetFreeSystemResources
+
+ ul = GETUINT16(GetFreeSystemResources(
+ WORD32(parg16->f1)
+ ));
+
+#else
+
+ ul = 90;
+
+#endif
+
+ FREEARGPTR(parg16);
+
+ RETURN (ul);
+}
+
+
+ULONG FASTCALL WU32GetQueueStatus(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+
+#if 0
+ UNREFERENCED_PARAMETER(pFrame);
+
+ LOGDEBUG(0, ("WOW : WU32GetQueueStatus() (Win 3.1) : contact ChandanC"));
+#else
+ register PGETQUEUESTATUS16 parg16;
+ GETARGPTR(pFrame, sizeof(GETQUEUESTATUS16), parg16);
+
+ ul = GetQueueStatus((UINT)parg16->f1);
+
+ FREEARGPTR(parg16);
+
+#endif
+
+ RETURN (ul);
+}
+
+ULONG FASTCALL WU32ExitWindowsExec(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PEXITWINDOWSEXEC16 parg16;
+ LPSTR lpstrProgName;
+ LPSTR lpstrCmdLine;
+ UINT lengthProgName;
+ UINT lengthCmdLine;
+ BYTE abT[512];
+
+
+ GETARGPTR(pFrame, sizeof(EXITWINDOWSEXEC16), parg16);
+
+ GETPSZPTR(parg16->vpProgName, lpstrProgName);
+ GETPSZPTR(parg16->vpCmdLine, lpstrCmdLine);
+
+ lengthProgName = (lpstrProgName) ? strlen(lpstrProgName) : 0;
+ lengthCmdLine = (lpstrCmdLine) ? strlen(lpstrCmdLine) : 0;
+
+ WOW32ASSERT(sizeof(abT) > (lengthProgName+lengthCmdLine+2));
+
+ strcpy(abT, "" );
+ if ( lpstrProgName ) {
+ strcpy(abT, lpstrProgName );
+ }
+ if ( lpstrCmdLine ) {
+ strcat(abT, " " );
+ strcat(abT, lpstrCmdLine );
+ }
+
+ //
+ // We write the commandline to registry "WOW/EWExecCmdLine"
+ // If the system logs off successfully, after reboot, we read
+ // the registry and exec the specfied app before launching any
+ // wow app in any wow vdm. We donot launch the app before logoff
+ // because winlogon doesn't allow any app to be execed during
+ // the logoff process.
+ // - nanduri
+
+ // only one exitwindowsexec call at a time.
+ // if value/key exists, return error.
+
+ if (!W32EWExecData(EWEXEC_QUERY, abT, sizeof(abT))) {
+ HANDLE hevT;
+
+ // only one exitwindowsexec call at a time.
+ // if event exits, return error.
+
+ if (hevT = CreateEvent(NULL, TRUE, FALSE, WOWSZ_EWEXECEVENT)) {
+ if (GetLastError() == 0) {
+ // wake up any waiting threads (in w32ewexecer)
+
+ SetEvent(hevT);
+
+ // Write the data to the registry
+
+ if (W32EWExecData(EWEXEC_SET, abT, strlen(abT)+1)) {
+ DWORD dwlevel;
+ DWORD dwflags;
+
+ if (!GetProcessShutdownParameters(&dwlevel, &dwflags)) {
+ dwlevel = 0x280; // default level per docs
+ dwflags = 0;
+ }
+
+ //
+ // 0xff = last system reserved level Logically makes this last user
+ // process to shutdown. This takes care of Multiple WOW VDMs
+ //
+
+ SetProcessShutdownParameters(0xff, 0);
+
+ //
+ // EWX_NOTIFY private bit for WOW. Generates queue message
+ // WM_ENDSESSION, if any process cancels logoff/shutdown.
+
+ if (ExitWindowsEx(EWX_LOGOFF | EWX_NOTIFY, 0)) {
+ MSG msg;
+
+ //
+ // PeekMessage yields to other WOW tasks. We effectively
+ // freeze the current task by removing all input messages.
+ // Loop terminates only if WM_ENDSESSION message has been
+ // received. This message is posted by winsrv if any process
+ // in the system cancels logoff.
+ //
+
+ while (TRUE) {
+ if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
+ if ((msg.message >= WM_MOUSEFIRST &&
+ msg.message <= WM_MOUSELAST) ||
+ (msg.message >= WM_KEYFIRST &&
+ msg.message <= WM_KEYLAST) ||
+ (msg.message >= WM_NCMOUSEMOVE &&
+ msg.message <= WM_NCMBUTTONDBLCLK)) {
+
+ // don't dispatch the message
+
+ }
+ else if (msg.message == WM_ENDSESSION) {
+ WOW32ASSERT((msg.hwnd == 0) && (msg.wParam == 0));
+ break;
+ }
+ else {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+ }
+
+ //
+ // Here if logoff was cancelled.
+ // Set defaults and delete the associated value from registry.
+ //
+
+ SetProcessShutdownParameters(dwlevel, dwflags);
+ if (!W32EWExecData(EWEXEC_DEL, (LPSTR)NULL, 0)) {
+ WOW32ASSERT(FALSE);
+ }
+ }
+ }
+ CloseHandle(hevT);
+ }
+ }
+
+ LOGDEBUG(0,("WOW: ExitWindowsExec failed\r\n"));
+ FREEARGPTR(parg16);
+ return 0;
+}
+
+ULONG FASTCALL WU32MapWindowPoints(PVDMFRAME pFrame)
+{
+ LPPOINT p3;
+ register PMAPWINDOWPOINTS16 parg16;
+ POINT BufferT[128];
+
+
+ GETARGPTR(pFrame, sizeof(MAPWINDOWPOINTS16), parg16);
+ p3 = STACKORHEAPALLOC(parg16->f4 * sizeof(POINT), sizeof(BufferT), BufferT);
+ getpoint16(parg16->f3, parg16->f4, p3);
+
+ MapWindowPoints(
+ HWND32(parg16->f1),
+ HWND32(parg16->f2),
+ p3,
+ INT32(parg16->f4)
+ );
+
+ PUTPOINTARRAY16(parg16->f3, parg16->f4, p3);
+ STACKORHEAPFREE(p3, BufferT);
+ FREEARGPTR(parg16);
+
+ RETURN(1);
+}
diff --git a/private/mvdm/wow32/wuser31.h b/private/mvdm/wow32/wuser31.h
new file mode 100644
index 000000000..27425ee27
--- /dev/null
+++ b/private/mvdm/wow32/wuser31.h
@@ -0,0 +1,87 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUSER31.H
+ * WOW32 16-bit Win 3.1 User API support
+ *
+ * History:
+ * Created 16-Mar-1992 by Chandan S. Chauhan (ChandanC)
+--*/
+
+#define WINDOWPLACEMENT16TO32(vp,lp) {\
+ LPWINDOWPLACEMENT16 lp16;\
+ GETVDMPTR(vp, sizeof(WINDOWPLACEMENT16), lp16);\
+ (lp)->length = sizeof(WINDOWPLACEMENT);\
+ (lp)->flags = FETCHWORD(lp16->flags);\
+ (lp)->showCmd = FETCHWORD(lp16->showCmd);\
+ (lp)->ptMinPosition.x = (INT) FETCHSHORT(lp16->ptMinPosition.x);\
+ (lp)->ptMinPosition.y = (INT) FETCHSHORT(lp16->ptMinPosition.y);\
+ (lp)->ptMaxPosition.x = (INT) FETCHSHORT(lp16->ptMaxPosition.x);\
+ (lp)->ptMaxPosition.y = (INT) FETCHSHORT(lp16->ptMaxPosition.y);\
+ (lp)->rcNormalPosition.left = (INT) FETCHSHORT(lp16->rcNormalPosition.left);\
+ (lp)->rcNormalPosition.top = (INT) FETCHSHORT(lp16->rcNormalPosition.top);\
+ (lp)->rcNormalPosition.right = (INT) FETCHSHORT(lp16->rcNormalPosition.right);\
+ (lp)->rcNormalPosition.bottom = (INT) FETCHSHORT(lp16->rcNormalPosition.bottom);\
+ FREEVDMPTR(lp16);\
+}
+
+
+
+#define WINDOWPLACEMENT32TO16(vp,lp) {\
+ LPWINDOWPLACEMENT16 lp16;\
+ GETVDMPTR(vp, sizeof(WINDOWPLACEMENT16), lp16);\
+ STOREWORD(lp16->length, sizeof(WINDOWPLACEMENT16));\
+ STOREWORD(lp16->flags, (lp)->flags);\
+ STOREWORD(lp16->showCmd, (lp)->showCmd);\
+ STORESHORT(lp16->ptMinPosition.x, (lp)->ptMinPosition.x);\
+ STORESHORT(lp16->ptMinPosition.y, (lp)->ptMinPosition.y);\
+ STORESHORT(lp16->ptMaxPosition.x, (lp)->ptMaxPosition.x);\
+ STORESHORT(lp16->ptMaxPosition.y, (lp)->ptMaxPosition.y);\
+ STORESHORT(lp16->rcNormalPosition.left, (lp)->rcNormalPosition.left);\
+ STORESHORT(lp16->rcNormalPosition.top, (lp)->rcNormalPosition.top);\
+ STORESHORT(lp16->rcNormalPosition.right, (lp)->rcNormalPosition.right);\
+ STORESHORT(lp16->rcNormalPosition.bottom, (lp)->rcNormalPosition.bottom);\
+ FLUSHVDMPTR(vp, sizeof(WINDOWPLACEMENT16), lp16);\
+ FREEVDMPTR(lp16);\
+}
+
+
+
+
+ULONG FASTCALL WU32DlgDirSelectComboBoxEx(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DlgDirSelectEx(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EnableScrollBar(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ExitWindowsExec(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetClipCursor(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetCursor(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetDCEx(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetMessageExtraInfo(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetOpenClipboardWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetWindowPlacement(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetFreeSystemResources(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetQueueStatus(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32LockWindowUpdate(PVDMFRAME pFrame);
+ULONG FASTCALL WU32RedrawWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ScrollWindowEx(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetWindowPlacement(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SystemParametersInfo(PVDMFRAME pFrame);
+
+ULONG FASTCALL WU32MapWindowPoints(PVDMFRAME pFrame);
+
+//
+// for ExitWindowsExec support
+//
+
+#define EWEXEC_SET 0
+#define EWEXEC_DEL 1
+#define EWEXEC_QUERY 2
+#define WOWSZ_EWEXECEVENT "WOWEWExecEvent"
+#define WOWSZ_EWEXECVALUE "EWExecCmdLine"
+
+BOOL W32EWExecData(DWORD fnid, LPSTR lpData, DWORD cb);
+BOOL W32EWExecer(VOID);
+
diff --git a/private/mvdm/wow32/wusercli.c b/private/mvdm/wow32/wusercli.c
new file mode 100644
index 000000000..c93e9f1b6
--- /dev/null
+++ b/private/mvdm/wow32/wusercli.c
@@ -0,0 +1,711 @@
+//**************************************************************************
+// wusercli.c :
+// Contains all functions that execute USER32 client code on 16bitside.
+// Most of these functions don't exist on x86 builds. So any changes
+// to these files must be reflected in wow16\user\usercli.asm
+//
+// - nanduri
+//**************************************************************************
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wusercli.c);
+
+#ifndef PMODE32 // NOT INCLUDED IN I386/PMODE32
+
+//**************************************************************************
+// WU32ClientToScreen -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32ClientToScreen(PVDMFRAME pFrame)
+{
+ POINT t2;
+ register PCLIENTTOSCREEN16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CLIENTTOSCREEN16), parg16);
+ GETPOINT16(parg16->f2, &t2);
+
+ ClientToScreen( HWND32(parg16->f1), &t2 );
+
+ PUTPOINT16(parg16->f2, &t2);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+//**************************************************************************
+// WU32GetClassName -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetClassName(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PGETCLASSNAME16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCLASSNAME16), parg16);
+ ALLOCVDMPTR(parg16->f2, parg16->f3, psz2);
+
+ ul = GETINT16(GetClassName( HWND32(parg16->f1), psz2, INT32(parg16->f3)));
+
+ FLUSHVDMPTR(parg16->f2, strlen(psz2)+1, psz2);
+ FREEVDMPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32GetClientRect -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetClientRect(PVDMFRAME pFrame)
+{
+ RECT t2;
+ register PGETCLIENTRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCLIENTRECT16), parg16);
+
+ /*
+ * Home Design Gold 2.0
+ *
+ * If the call fails, don't overwrite the passed-in
+ * rect.
+ */
+ if (GetClientRect(HWND32(parg16->hwnd), &t2)) {
+ PUTRECT16(parg16->vpRect, &t2);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+
+//**************************************************************************
+// WU32GetCursorPos -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetCursorPos(PVDMFRAME pFrame)
+{
+ POINT t1;
+ register PGETCURSORPOS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETCURSORPOS16), parg16);
+
+ GetCursorPos( &t1 );
+
+ PUTPOINT16(parg16->f1, &t1);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+//**************************************************************************
+// WU32GetDesktopWindow -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetDesktopWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETHWND16(GetDesktopWindow());
+
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32GetDlgItem -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetDlgItem(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETDLGITEM16 parg16;
+
+ //
+ // pass the child ID zero-extended. this ID is the hMenu param to
+ // CreateWindow, so USER gets this ID with hiword = 0.
+ // Visual Basic relies on this.
+ //
+
+
+ GETARGPTR(pFrame, sizeof(GETDLGITEM16), parg16);
+
+ ul = GETHWND16(GetDlgItem(HWND32(parg16->f1),WORD32(parg16->f2)));
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_DBASEHANDLEBUG) {
+ ((PTDB)SEGPTR(pFrame->wTDB,0))->TDB_CompatHandle = (USHORT) ul;
+ }
+
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32GetMenu -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETMENU16), parg16);
+
+ ul = GETHMENU16(GetMenu(HWND32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//**************************************************************************
+// WU32GetMenuItemCount -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetMenuItemCount(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETMENUITEMCOUNT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETMENUITEMCOUNT16), parg16);
+
+ ul = GETWORD16(GetMenuItemCount( HMENU32(parg16->f1) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32GetMenuItemID -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetMenuItemID(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETMENUITEMID16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETMENUITEMID16), parg16);
+
+ ul = GETWORD16(GetMenuItemID( HMENU32(parg16->f1), INT32(parg16->f2) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//**************************************************************************
+// WU32GetMenuState -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetMenuState(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETMENUSTATE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETMENUSTATE16), parg16);
+
+ ul = GETWORD16(GetMenuState( HMENU32(parg16->f1), WORD32(parg16->f2), WORD32(parg16->f3) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32GetNextWindow -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetNextWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETNEXTWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETNEXTWINDOW16), parg16);
+
+ ul = GETHWND16(GetNextWindow(HWND32(parg16->f1), WORD32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32GetParent -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetParent(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETPARENT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETPARENT16), parg16);
+
+ ul = GETHWND16(GetParent(HWND32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+//**************************************************************************
+// WU32GetSubMenu -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetSubMenu(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETSUBMENU16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETSUBMENU16), parg16);
+
+ ul = GETHMENU16(GetSubMenu(HMENU32(parg16->f1), INT32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//**************************************************************************
+// WU32GetSysColor -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetSysColor(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETSYSCOLOR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETSYSCOLOR16), parg16);
+
+ ul = GETDWORD16(GetSysColor( INT32(parg16->f1) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//**************************************************************************
+// WU32GetSystemMetrics -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetSystemMetrics(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETSYSTEMMETRICS16 parg16;
+ int sm;
+
+ GETARGPTR(pFrame, sizeof(GETSYSTEMMETRICS16), parg16);
+
+ sm = INT32(parg16->f1);
+
+ ul = GETINT16(GetSystemMetrics(sm) );
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32GetTopWindow -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetTopWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETTOPWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETTOPWINDOW16), parg16);
+
+ ul = GETHWND16(GetTopWindow(HWND32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//**************************************************************************
+// WU32GetWindow -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOW16), parg16);
+
+ ul = GETHWND16(GetWindow(HWND32(parg16->f1), WORD32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32GetWindowRect -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetWindowRect(PVDMFRAME pFrame)
+{
+ RECT t2;
+ register PGETWINDOWRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWRECT16), parg16);
+
+ /*
+ * Home Design Gold 2.0
+ *
+ * If the call fails, don't overwrite the passed-in
+ * rect.
+ */
+ if (GetWindowRect(HWND32(parg16->f1), &t2)) {
+ PUTRECT16(parg16->f2, &t2);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+
+//**************************************************************************
+// WU32IsWindow -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32IsWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISWINDOW16), parg16);
+
+ ul = GETBOOL16(IsWindow( HWND32(parg16->f1) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32ScreenToClient -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32ScreenToClient(PVDMFRAME pFrame)
+{
+ POINT t2;
+ register PSCREENTOCLIENT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SCREENTOCLIENT16), parg16);
+ GETPOINT16(parg16->f2, &t2);
+
+ ScreenToClient( HWND32(parg16->f1), &t2 );
+
+ PUTPOINT16(parg16->f2, &t2);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+//**************************************************************************
+// WU32IsChild -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32IsChild(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISCHILD16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISCHILD16), parg16);
+
+ ul = GETBOOL16(IsChild( HWND32(parg16->f1), HWND32(parg16->f2) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//**************************************************************************
+// WU32IsIconic -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32IsIconic(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISICONIC16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISICONIC16), parg16);
+
+ ul = GETBOOL16(IsIconic( HWND32(parg16->f1) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//**************************************************************************
+// WU32IsWindowEnabled -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32IsWindowEnabled(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISWINDOWENABLED16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISWINDOWENABLED16), parg16);
+
+ ul = GETBOOL16(IsWindowEnabled( HWND32(parg16->f1) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//**************************************************************************
+// WU32IsWindowVisible -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32IsWindowVisible(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISWINDOWVISIBLE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISWINDOWVISIBLE16), parg16);
+
+ ul = GETBOOL16(IsWindowVisible( HWND32(parg16->f1) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32IsZoomed -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32IsZoomed(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PISZOOMED16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ISZOOMED16), parg16);
+
+ ul = GETBOOL16(IsZoomed( HWND32(parg16->f1) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//**************************************************************************
+// WU32GetTickCount -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetTickCount(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = (ULONG)GetTickCount();
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_GRAINYTICS) {
+
+ //
+ // round down to the nearest 55ms this is for RelayGold, which
+ // spins calling this API until consecutive calls return a delta
+ // greater than 52.
+ //
+
+ ul = ul - (ul % 55);
+ }
+
+ RETURN(ul);
+}
+
+
+#endif // ALL THE ABOVE NOT INCLUDED FOR I386/PMODE32
+
+
+
+//**************************************************************************
+// On I386 all these functions her handled on clientside. But conditionally
+// they may endup doing the actual work via these thunks.
+//
+// So any changes here like 'win31 compatiblity code' may have to be added
+// in mvdm\wow16\user\usercli.asm too.
+//
+// - nanduri
+//**************************************************************************
+
+
+//**************************************************************************
+// WU32DefHookProc -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32DefHookProc(PVDMFRAME pFrame)
+{
+ ULONG ul = 0;
+ register PDEFHOOKPROC16 parg16;
+ HOOKSTATEDATA HkData;
+ ULONG hHook16;
+ INT iHookCode;
+ INT nCode;
+ LONG wParam;
+ LONG lParam;
+ LPINT lpiFunc;
+
+ GETARGPTR(pFrame, sizeof(DEFHOOKPROC16), parg16);
+
+ nCode = INT32(parg16->f1);
+ wParam = WORD32(parg16->f2);
+ lParam = DWORD32(parg16->f3);
+
+ GETMISCPTR(parg16->f4, lpiFunc);
+ hHook16 = FETCHDWORD(*lpiFunc);
+ FREEVDMPTR(lpiFunc);
+
+ if (ISVALIDHHOOK(hHook16)) {
+ iHookCode = GETHHOOKINDEX(hHook16);
+ HkData.iIndex = iHookCode;
+ if ( W32GetHookStateData( &HkData ) ) {
+ ul = (ULONG)WU32StdDefHookProc(nCode, wParam, lParam, iHookCode);
+ }
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32EnableMenuItem -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32EnableMenuItem(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PENABLEMENUITEM16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENABLEMENUITEM16), parg16);
+
+ ul = GETBOOL16(EnableMenuItem( HMENU32(parg16->f1), WORD32(parg16->f2),
+ WORD32(parg16->f3) ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+//**************************************************************************
+// WU32GetKeyState -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetKeyState(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ SHORT sTmp;
+ register PGETKEYSTATE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETKEYSTATE16), parg16);
+
+ sTmp = GetKeyState(INT32(parg16->f1));
+
+ // compatiblity:
+ // MSTEST (testdrvr.exe) tests the bit 0x80 for checking the
+ // shift key state. This works in win31 because the keystate in win31 is
+ // one byte long and because of similar code below
+ //
+ // win31 code is similar to:
+ // mov al, byte ptr keystate
+ // cbw
+ // ret
+ //
+ // if 'al' is 0x80, cbw will make ax = 0xff80 and thus in win31
+ // (state & 0x8000) and (state & 0x0080) will work and mean the same.
+ //
+
+ ul = (ULONG)((sTmp & 0x8000) ? (sTmp | 0x80) : sTmp);
+
+
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+//**************************************************************************
+// WU32GetKeyboardState -
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32GetKeyboardState(PVDMFRAME pFrame)
+{
+ PBYTE pb1;
+ register PGETKEYBOARDSTATE16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETKEYBOARDSTATE16), parg16);
+ ALLOCVDMPTR(parg16->f1, 256, pb1);
+
+#ifdef HACK32 // bug 5704
+ if (pb1) {
+ GetKeyboardState( pb1 );
+ }
+#else
+ GetKeyboardState( pb1 );
+#endif
+
+ FLUSHVDMPTR(parg16->f1, 256, pb1);
+ FREEVDMPTR(pb1);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
diff --git a/private/mvdm/wow32/wusercli.h b/private/mvdm/wow32/wusercli.h
new file mode 100644
index 000000000..cbf1b3d68
--- /dev/null
+++ b/private/mvdm/wow32/wusercli.h
@@ -0,0 +1,98 @@
+//**************************************************************************
+// wusercli.h : prototypes for thunks that may be handled on 16bit side
+//
+//**************************************************************************
+
+ULONG FASTCALL WU32DefHookProc(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EnableMenuItem(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetKeyState(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetKeyboardState(PVDMFRAME pFrame);
+
+
+#ifdef PMODE32
+
+#define WU32CLIENTTOSCREEN LOCALAPI
+#define WU32GETCLASSNAME LOCALAPI
+#define WU32GETCLIENTRECT LOCALAPI
+#define WU32GETCURSORPOS LOCALAPI
+#define WU32GETDESKTOPWINDOW LOCALAPI
+#define WU32GETDLGITEM LOCALAPI
+#define WU32GETMENU LOCALAPI
+#define WU32GETMENUITEMCOUNT LOCALAPI
+#define WU32GETMENUITEMID LOCALAPI
+#define WU32GETMENUSTATE LOCALAPI
+#define WU32GETNEXTWINDOW LOCALAPI
+#define WU32GETPARENT LOCALAPI
+#define WU32GETSUBMENU LOCALAPI
+#define WU32GETSYSCOLOR LOCALAPI
+#define WU32GETSYSTEMMETRICS LOCALAPI
+#define WU32GETTICKCOUNT LOCALAPI
+#define WU32GETTOPWINDOW LOCALAPI
+#define WU32GETWINDOW LOCALAPI
+#define WU32GETWINDOWRECT LOCALAPI
+#define WU32ISCHILD LOCALAPI
+#define WU32ISICONIC LOCALAPI
+#define WU32ISWINDOW LOCALAPI
+#define WU32ISWINDOWENABLED LOCALAPI
+#define WU32ISWINDOWVISIBLE LOCALAPI
+#define WU32ISZOOMED LOCALAPI
+#define WU32SCREENTOCLIENT LOCALAPI
+
+#else
+
+#define WU32CLIENTTOSCREEN WU32ClientToScreen
+#define WU32GETCLASSNAME WU32GetClassName
+#define WU32GETCLIENTRECT WU32GetClientRect
+#define WU32GETCURSORPOS WU32GetCursorPos
+#define WU32GETDESKTOPWINDOW WU32GetDesktopWindow
+#define WU32GETDLGITEM WU32GetDlgItem
+#define WU32GETMENU WU32GetMenu
+#define WU32GETMENUITEMCOUNT WU32GetMenuItemCount
+#define WU32GETMENUITEMID WU32GetMenuItemID
+#define WU32GETMENUSTATE WU32GetMenuState
+#define WU32GETNEXTWINDOW WU32GetNextWindow
+#define WU32GETPARENT WU32GetParent
+#define WU32GETSUBMENU WU32GetSubMenu
+#define WU32GETSYSCOLOR WU32GetSysColor
+#define WU32GETSYSTEMMETRICS WU32GetSystemMetrics
+#define WU32GETTICKCOUNT WU32GetTickCount
+#define WU32GETTOPWINDOW WU32GetTopWindow
+#define WU32GETWINDOW WU32GetWindow
+#define WU32GETWINDOWRECT WU32GetWindowRect
+#define WU32ISCHILD WU32IsChild
+#define WU32ISICONIC WU32IsIconic
+#define WU32ISWINDOW WU32IsWindow
+#define WU32ISWINDOWENABLED WU32IsWindowEnabled
+#define WU32ISWINDOWVISIBLE WU32IsWindowVisible
+#define WU32ISZOOMED WU32IsZoomed
+#define WU32SCREENTOCLIENT WU32ScreenToClient
+
+ULONG FASTCALL WU32ClientToScreen(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetClassName(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetClientRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetCursorPos(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetDesktopWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetDlgItem(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetMenuItemCount(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetMenuItemID(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetMenuState(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetNextWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetParent(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetSubMenu(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetSysColor(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetSystemMetrics(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetTopWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetWindowRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ScreenToClient(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsChild(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsIconic(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsWindowEnabled(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsWindowVisible(PVDMFRAME pFrame);
+ULONG FASTCALL WU32IsZoomed(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetTickCount(PVDMFRAME pFrame);
+
+#endif
+
diff --git a/private/mvdm/wow32/wutbl.h b/private/mvdm/wow32/wutbl.h
new file mode 100644
index 000000000..14eaab992
--- /dev/null
+++ b/private/mvdm/wow32/wutbl.h
@@ -0,0 +1,24 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUTBL.H
+ * WOW32 16-bit User API tables
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+/* User dispatch table
+ */
+extern W32 aw32User[];
+
+
+
+#ifdef DEBUG_OR_WOWPROFILE
+extern INT iUserMax;
+#endif
diff --git a/private/mvdm/wow32/wutbl2.h b/private/mvdm/wow32/wutbl2.h
new file mode 100644
index 000000000..e87fb1886
--- /dev/null
+++ b/private/mvdm/wow32/wutbl2.h
@@ -0,0 +1,659 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, 1992, 1993 Microsoft Corporation
+ *
+ * WUTBL2.h
+ * WOW32 user API thunks
+ *
+ * This file is included into the master thunk table.
+ *
+--*/
+
+
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_USER, 0)},
+ {W32FUN(WU32MessageBox, "MESSAGEBOX", MOD_USER, sizeof(MESSAGEBOX16))},
+ {W32FUN(LOCALAPI, "OLDEXITWINDOWS", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENABLEOEMLAYER", MOD_USER, 0)},
+ {W32FUN(NOPAPI, "DISABLEOEMLAYER", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "INITAPP", MOD_USER, 0)},
+ {W32FUN(WU32PostQuitMessage, "POSTQUITMESSAGE", MOD_USER, sizeof(POSTQUITMESSAGE16))},
+ {W32FUN(WU32ExitWindows, "EXITWINDOWS", MOD_USER, sizeof(EXITWINDOWS16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0010 ***/
+ {W32FUN(WU32SetTimer, "SETTIMER", MOD_USER, sizeof(SETTIMER16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETSYSTEMTIMER", MOD_USER, 0)},
+ {W32FUN(WU32KillTimer, "KILLTIMER", MOD_USER, sizeof(KILLTIMER16))},
+ {W32FUN(WU32GETTICKCOUNT, "GETTICKCOUNT", MOD_USER, 0)},
+ {W32FUN(WU32GetTimerResolution, "GETTIMERRESOLUTION", MOD_USER, 0)},
+ {W32FUN(WU32GETTICKCOUNT, "GETCURRENTTIME", MOD_USER, 0)},
+ {W32FUN(WU32ClipCursor, "CLIPCURSOR", MOD_USER, sizeof(CLIPCURSOR16))},
+ {W32FUN(WU32GETCURSORPOS, "GETCURSORPOS", MOD_USER, sizeof(GETCURSORPOS16))},
+ {W32FUN(WU32SetCapture, "SETCAPTURE", MOD_USER, sizeof(SETCAPTURE16))},
+ {W32FUN(WU32ReleaseCapture, "RELEASECAPTURE", MOD_USER, 0)},
+
+ /*** 0020 ***/
+ {W32FUN(WU32SetDoubleClickTime, "SETDOUBLECLICKTIME", MOD_USER, sizeof(SETDOUBLECLICKTIME16))},
+ {W32FUN(WU32GetDoubleClickTime, "GETDOUBLECLICKTIME", MOD_USER, 0)},
+ {W32FUN(WU32SetFocus, "SETFOCUS", MOD_USER, sizeof(SETFOCUS16))},
+ {W32FUN(WU32GetFocus, "GETFOCUS", MOD_USER, 0)},
+ {W32FUN(WU32RemoveProp, "REMOVEPROP", MOD_USER, sizeof(REMOVEPROP16))},
+ {W32FUN(WU32GetProp, "GETPROP", MOD_USER, sizeof(GETPROP16))},
+ {W32FUN(WU32SetProp, "SETPROP", MOD_USER, sizeof(SETPROP16))},
+ {W32FUN(WU32EnumProps, "ENUMPROPS", MOD_USER, sizeof(ENUMPROPS16))},
+ {W32FUN(WU32CLIENTTOSCREEN, "CLIENTTOSCREEN", MOD_USER, sizeof(CLIENTTOSCREEN16))},
+ {W32FUN(WU32SCREENTOCLIENT, "SCREENTOCLIENT", MOD_USER, sizeof(SCREENTOCLIENT16))},
+
+ /*** 0030 ***/
+ {W32FUN(WU32WindowFromPoint, "WINDOWFROMPOINT", MOD_USER, sizeof(WINDOWFROMPOINT16))},
+ {W32FUN(WU32ISICONIC, "ISICONIC", MOD_USER, sizeof(ISICONIC16))},
+ {W32FUN(WU32GETWINDOWRECT, "GETWINDOWRECT", MOD_USER, sizeof(GETWINDOWRECT16))},
+ {W32FUN(WU32GETCLIENTRECT, "GETCLIENTRECT", MOD_USER, sizeof(GETCLIENTRECT16))},
+ {W32FUN(WU32EnableWindow, "ENABLEWINDOW", MOD_USER, sizeof(ENABLEWINDOW16))},
+ {W32FUN(WU32ISWINDOWENABLED, "ISWINDOWENABLED", MOD_USER, sizeof(ISWINDOWENABLED16))},
+ {W32FUN(WU32GetWindowText, "GETWINDOWTEXT", MOD_USER, sizeof(GETWINDOWTEXT16))},
+ {W32FUN(WU32SetWindowText, "SETWINDOWTEXT", MOD_USER, sizeof(SETWINDOWTEXT16))},
+ {W32FUN(WU32GetWindowTextLength, "GETWINDOWTEXTLENGTH", MOD_USER, sizeof(GETWINDOWTEXTLENGTH16))},
+ {W32FUN(WU32BeginPaint, "BEGINPAINT", MOD_USER, sizeof(BEGINPAINT16))},
+
+ /*** 0040 ***/
+ {W32FUN(WU32EndPaint, "ENDPAINT", MOD_USER, sizeof(ENDPAINT16))},
+ {W32FUN(WU32CreateWindow, "CREATEWINDOW", MOD_USER, sizeof(CREATEWINDOW16))},
+ {W32FUN(WU32ShowWindow, "SHOWWINDOW", MOD_USER, sizeof(SHOWWINDOW16))},
+ {W32FUN(WU32CloseWindow, "CLOSEWINDOW", MOD_USER, sizeof(CLOSEWINDOW16))},
+ {W32FUN(WU32OpenIcon, "OPENICON", MOD_USER, sizeof(OPENICON16))},
+ {W32FUN(WU32BringWindowToTop, "BRINGWINDOWTOTOP", MOD_USER, sizeof(BRINGWINDOWTOTOP16))},
+ {W32FUN(WU32GETPARENT, "GETPARENT", MOD_USER, sizeof(GETPARENT16))},
+ {W32FUN(WU32ISWINDOW, "ISWINDOW", MOD_USER, sizeof(ISWINDOW16))},
+ {W32FUN(WU32ISCHILD, "ISCHILD", MOD_USER, sizeof(ISCHILD16))},
+ {W32FUN(WU32ISWINDOWVISIBLE, "ISWINDOWVISIBLE", MOD_USER, sizeof(ISWINDOWVISIBLE16))},
+
+ /*** 0050 ***/
+ {W32FUN(WU32FindWindow, "FINDWINDOW", MOD_USER, sizeof(FINDWINDOW16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "ISTWOBYTECHARPREFIX", MOD_USER, sizeof(ISTWOBYTECHARPREFIX16))},
+ {W32FUN(WU32AnyPopup, "ANYPOPUP", MOD_USER, 0)},
+ {W32FUN(WU32DestroyWindow, "DESTROYWINDOW", MOD_USER, sizeof(DESTROYWINDOW16))},
+ {W32FUN(WU32EnumWindows, "ENUMWINDOWS", MOD_USER, sizeof(ENUMWINDOWS16))},
+ {W32FUN(WU32EnumChildWindows, "ENUMCHILDWINDOWS", MOD_USER, sizeof(ENUMCHILDWINDOWS16))},
+ {W32FUN(WU32MoveWindow, "MOVEWINDOW", MOD_USER, sizeof(MOVEWINDOW16))},
+ {W32FUN(WU32RegisterClass, "REGISTERCLASS", MOD_USER, sizeof(REGISTERCLASS16))},
+ {W32FUN(WU32GETCLASSNAME, "GETCLASSNAME", MOD_USER, sizeof(GETCLASSNAME16))},
+ {W32FUN(WU32SetActiveWindow, "SETACTIVEWINDOW", MOD_USER, sizeof(SETACTIVEWINDOW16))},
+
+ /*** 0060 ***/
+ {W32FUN(WU32GetActiveWindow, "GETACTIVEWINDOW", MOD_USER, 0)},
+ {W32FUN(WU32ScrollWindow, "SCROLLWINDOW", MOD_USER, sizeof(SCROLLWINDOW16))},
+ {W32FUN(WU32SetScrollPos, "SETSCROLLPOS", MOD_USER, sizeof(SETSCROLLPOS16))},
+ {W32FUN(WU32GetScrollPos, "GETSCROLLPOS", MOD_USER, sizeof(GETSCROLLPOS16))},
+ {W32FUN(WU32SetScrollRange, "SETSCROLLRANGE", MOD_USER, sizeof(SETSCROLLRANGE16))},
+ {W32FUN(WU32GetScrollRange, "GETSCROLLRANGE", MOD_USER, sizeof(GETSCROLLRANGE16))},
+ {W32FUN(WU32GetDC, "GETDC", MOD_USER, sizeof(GETDC16))},
+ {W32FUN(WU32GetWindowDC, "GETWINDOWDC", MOD_USER, sizeof(GETWINDOWDC16))},
+ {W32FUN(WU32ReleaseDC, "RELEASEDC", MOD_USER, sizeof(RELEASEDC16))},
+ {W32FUN(WU32SetCursor, "SETCURSOR", MOD_USER, sizeof(SETCURSOR16))},
+
+ /*** 0070 ***/
+ {W32FUN(WU32SetCursorPos, "SETCURSORPOS", MOD_USER, sizeof(SETCURSORPOS16))},
+ {W32FUN(WU32ShowCursor, "SHOWCURSOR", MOD_USER, sizeof(SHOWCURSOR16))},
+ {W32FUN(LOCALAPI, "SETRECT", MOD_USER, sizeof(SETRECT16))},
+ {W32FUN(LOCALAPI, "SETRECTEMPTY", MOD_USER, sizeof(SETRECTEMPTY16))},
+ {W32FUN(LOCALAPI, "COPYRECT", MOD_USER, sizeof(COPYRECT16))},
+ {W32FUN(LOCALAPI, "ISRECTEMPTY", MOD_USER, sizeof(ISRECTEMPTY16))},
+ {W32FUN(LOCALAPI, "PTINRECT", MOD_USER, sizeof(PTINRECT16))},
+ {W32FUN(LOCALAPI, "OFFSETRECT", MOD_USER, sizeof(OFFSETRECT16))},
+ {W32FUN(LOCALAPI, "INFLATERECT", MOD_USER, sizeof(INFLATERECT16))},
+ {W32FUN(LOCALAPI, "INTERSECTRECT", MOD_USER, sizeof(INTERSECTRECT16))},
+
+ /*** 0080 ***/
+ {W32FUN(LOCALAPI, "UNIONRECT", MOD_USER, sizeof(UNIONRECT16))},
+ {W32FUN(WU32FillRect, "FILLRECT", MOD_USER, sizeof(FILLRECT16))},
+ {W32FUN(WU32InvertRect, "INVERTRECT", MOD_USER, sizeof(INVERTRECT16))},
+ {W32FUN(WU32FrameRect, "FRAMERECT", MOD_USER, sizeof(FRAMERECT16))},
+ {W32FUN(WU32DrawIcon, "DRAWICON", MOD_USER, sizeof(DRAWICON16))},
+ {W32FUN(WU32DrawText, "DRAWTEXT", MOD_USER, sizeof(DRAWTEXT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "ICONSIZE", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "DIALOGBOX", MOD_USER, sizeof(DIALOGBOX16))},
+ {W32FUN(WU32EndDialog, "ENDDIALOG", MOD_USER, sizeof(ENDDIALOG16))},
+ {W32FUN(LOCALAPI, "CREATEDIALOG", MOD_USER, sizeof(CREATEDIALOG16))},
+
+ /*** 0090 ***/
+ {W32FUN(WU32IsDialogMessage, "ISDIALOGMESSAGE", MOD_USER, sizeof(ISDIALOGMESSAGE16))},
+ {W32FUN(WU32GETDLGITEM, "GETDLGITEM", MOD_USER, sizeof(GETDLGITEM16))},
+ {W32FUN(WU32SetDlgItemText, "SETDLGITEMTEXT", MOD_USER, sizeof(SETDLGITEMTEXT16))},
+ {W32FUN(WU32GetDlgItemText, "GETDLGITEMTEXT", MOD_USER, sizeof(GETDLGITEMTEXT16))},
+ {W32FUN(WU32SetDlgItemInt, "SETDLGITEMINT", MOD_USER, sizeof(SETDLGITEMINT16))},
+ {W32FUN(WU32GetDlgItemInt, "GETDLGITEMINT", MOD_USER, sizeof(GETDLGITEMINT16))},
+ {W32FUN(WU32CheckRadioButton, "CHECKRADIOBUTTON", MOD_USER, sizeof(CHECKRADIOBUTTON16))},
+ {W32FUN(WU32CheckDlgButton, "CHECKDLGBUTTON", MOD_USER, sizeof(CHECKDLGBUTTON16))},
+ {W32FUN(WU32IsDlgButtonChecked, "ISDLGBUTTONCHECKED", MOD_USER, sizeof(ISDLGBUTTONCHECKED16))},
+ {W32FUN(WU32DlgDirSelect, "DLGDIRSELECT", MOD_USER, sizeof(DLGDIRSELECT16))},
+
+ /*** 0100 ***/
+ {W32FUN(WU32DlgDirList, "DLGDIRLIST", MOD_USER, sizeof(DLGDIRLIST16))},
+ {W32FUN(WU32SendDlgItemMessage, "SENDDLGITEMMESSAGE", MOD_USER, sizeof(SENDDLGITEMMESSAGE16))},
+ {W32FUN(WU32AdjustWindowRect, "ADJUSTWINDOWRECT", MOD_USER, sizeof(ADJUSTWINDOWRECT16))},
+ {W32FUN(WU32MapDialogRect, "MAPDIALOGRECT", MOD_USER, sizeof(MAPDIALOGRECT16))},
+ {W32FUN(WU32MessageBeep, "MESSAGEBEEP", MOD_USER, sizeof(MESSAGEBEEP16))},
+ {W32FUN(WU32FlashWindow, "FLASHWINDOW", MOD_USER, sizeof(FLASHWINDOW16))},
+ {W32FUN(WU32GetKeyState, "GETKEYSTATE", MOD_USER, sizeof(GETKEYSTATE16))},
+ {W32FUN(WU32DefWindowProc, "DEFWINDOWPROC", MOD_USER, sizeof(DEFWINDOWPROC16))},
+ {W32FUN(WU32GetMessage, "GETMESSAGE", MOD_USER, sizeof(GETMESSAGE16))},
+ {W32FUN(WU32PeekMessage, "PEEKMESSAGE", MOD_USER, sizeof(PEEKMESSAGE16))},
+
+ /*** 0110 ***/
+ {W32FUN(WU32PostMessage, "POSTMESSAGE", MOD_USER, sizeof(POSTMESSAGE16))},
+ {W32FUN(WU32SendMessage, "SENDMESSAGE", MOD_USER, sizeof(SENDMESSAGE16))},
+ {W32FUN(WU32WaitMessage, "WAITMESSAGE", MOD_USER, 0)},
+ {W32FUN(WU32TranslateMessage, "TRANSLATEMESSAGE", MOD_USER, sizeof(TRANSLATEMESSAGE16))},
+ {W32FUN(WU32DispatchMessage, "DISPATCHMESSAGE", MOD_USER, sizeof(DISPATCHMESSAGE16))},
+ {W32FUN(WU32ReplyMessage, "REPLYMESSAGE", MOD_USER, sizeof(REPLYMESSAGE16))},
+ {W32FUN(WU32PostAppMessage, "POSTAPPMESSAGE", MOD_USER, sizeof(POSTAPPMESSAGE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETTASKFROMHWND", MOD_USER, 0)},
+ {W32FUN(WU32RegisterWindowMessage, "REGISTERWINDOWMESSAGE", MOD_USER, sizeof(REGISTERWINDOWMESSAGE16))},
+ {W32FUN(WU32GetMessagePos, "GETMESSAGEPOS", MOD_USER, 0)},
+
+ /*** 0120 ***/
+ {W32FUN(WU32GetMessageTime, "GETMESSAGETIME", MOD_USER, 0)},
+ {W32FUN(WU32SetWindowsHookInternal, "SETWINDOWSHOOKINTERNAL", MOD_USER, sizeof(SETWINDOWSHOOKINTERNAL16))},
+ {W32FUN(WU32CallWindowProc, "CALLWINDOWPROC", MOD_USER, sizeof(CALLWINDOWPROC16))},
+ {W32FUN(WU32CallMsgFilter, "CALLMSGFILTER", MOD_USER, sizeof(CALLMSGFILTER16))},
+ {W32FUN(WU32UpdateWindow, "UPDATEWINDOW", MOD_USER, sizeof(UPDATEWINDOW16))},
+ {W32FUN(WU32InvalidateRect, "INVALIDATERECT", MOD_USER, sizeof(INVALIDATERECT16))},
+ {W32FUN(WU32InvalidateRgn, "INVALIDATERGN", MOD_USER, sizeof(INVALIDATERGN16))},
+ {W32FUN(WU32ValidateRect, "VALIDATERECT", MOD_USER, sizeof(VALIDATERECT16))},
+ {W32FUN(WU32ValidateRgn, "VALIDATERGN", MOD_USER, sizeof(VALIDATERGN16))},
+ {W32FUN(WU32GetClassWord, "GETCLASSWORD", MOD_USER, sizeof(GETCLASSWORD16))},
+
+ /*** 0130 ***/
+ {W32FUN(WU32SetClassWord, "SETCLASSWORD", MOD_USER, sizeof(SETCLASSWORD16))},
+ {W32FUN(WU32GetClassLong, "GETCLASSLONG", MOD_USER, sizeof(GETCLASSLONG16))},
+ {W32FUN(WU32SetClassLong, "SETCLASSLONG", MOD_USER, sizeof(SETCLASSLONG16))},
+ {W32FUN(WU32GetWindowWord, "GETWINDOWWORD", MOD_USER, sizeof(GETWINDOWWORD16))},
+ {W32FUN(WU32SetWindowWord, "SETWINDOWWORD", MOD_USER, sizeof(SETWINDOWWORD16))},
+ {W32FUN(WU32GetWindowLong, "GETWINDOWLONG", MOD_USER, sizeof(GETWINDOWLONG16))},
+ {W32FUN(WU32SetWindowLong, "SETWINDOWLONG", MOD_USER, sizeof(SETWINDOWLONG16))},
+ {W32FUN(WU32OpenClipboard, "OPENCLIPBOARD", MOD_USER, sizeof(OPENCLIPBOARD16))},
+ {W32FUN(WU32CloseClipboard, "CLOSECLIPBOARD", MOD_USER, 0)},
+ {W32FUN(WU32EmptyClipboard, "EMPTYCLIPBOARD", MOD_USER, 0)},
+
+ /*** 0140 ***/
+ {W32FUN(WU32GetClipboardOwner, "GETCLIPBOARDOWNER", MOD_USER, 0)},
+ {W32FUN(WU32SetClipboardData, "SETCLIPBOARDDATA", MOD_USER, sizeof(SETCLIPBOARDDATA16))},
+ {W32FUN(WU32GetClipboardData, "GETCLIPBOARDDATA", MOD_USER, sizeof(GETCLIPBOARDDATA16))},
+ {W32FUN(WU32CountClipboardFormats, "COUNTCLIPBOARDFORMATS", MOD_USER, 0)},
+ {W32FUN(WU32EnumClipboardFormats, "ENUMCLIPBOARDFORMATS", MOD_USER, sizeof(ENUMCLIPBOARDFORMATS16))},
+ {W32FUN(WU32RegisterClipboardFormat, "REGISTERCLIPBOARDFORMAT", MOD_USER, sizeof(REGISTERCLIPBOARDFORMAT16))},
+ {W32FUN(WU32GetClipboardFormatName, "GETCLIPBOARDFORMATNAME", MOD_USER, sizeof(GETCLIPBOARDFORMATNAME16))},
+ {W32FUN(WU32SetClipboardViewer, "SETCLIPBOARDVIEWER", MOD_USER, sizeof(SETCLIPBOARDVIEWER16))},
+ {W32FUN(WU32GetClipboardViewer, "GETCLIPBOARDVIEWER", MOD_USER, 0)},
+ {W32FUN(WU32ChangeClipboardChain, "CHANGECLIPBOARDCHAIN", MOD_USER, sizeof(CHANGECLIPBOARDCHAIN16))},
+
+ /*** 0150 ***/
+ {W32FUN(WU32LoadMenu, "LOADMENU", MOD_USER, sizeof(LOADMENU16))},
+ {W32FUN(WU32CreateMenu, "CREATEMENU", MOD_USER, 0)},
+ {W32FUN(WU32DestroyMenu, "DESTROYMENU", MOD_USER, sizeof(DESTROYMENU16))},
+ {W32FUN(WU32ChangeMenu, "CHANGEMENU", MOD_USER, sizeof(CHANGEMENU16))},
+ {W32FUN(WU32CheckMenuItem, "CHECKMENUITEM", MOD_USER, sizeof(CHECKMENUITEM16))},
+ {W32FUN(WU32EnableMenuItem, "ENABLEMENUITEM", MOD_USER, sizeof(ENABLEMENUITEM16))},
+ {W32FUN(WU32GetSystemMenu, "GETSYSTEMMENU", MOD_USER, sizeof(GETSYSTEMMENU16))},
+ {W32FUN(WU32GETMENU, "GETMENU", MOD_USER, sizeof(GETMENU16))},
+ {W32FUN(WU32SetMenu, "SETMENU", MOD_USER, sizeof(SETMENU16))},
+ {W32FUN(WU32GETSUBMENU, "GETSUBMENU", MOD_USER, sizeof(GETSUBMENU16))},
+
+ /*** 0160 ***/
+ {W32FUN(WU32DrawMenuBar, "DRAWMENUBAR", MOD_USER, sizeof(DRAWMENUBAR16))},
+ {W32FUN(WU32GetMenuString, "GETMENUSTRING", MOD_USER, sizeof(GETMENUSTRING16))},
+ {W32FUN(WU32HiliteMenuItem, "HILITEMENUITEM", MOD_USER, sizeof(HILITEMENUITEM16))},
+ {W32FUN(WU32CreateCaret, "CREATECARET", MOD_USER, sizeof(CREATECARET16))},
+ {W32FUN(WU32DestroyCaret, "DESTROYCARET", MOD_USER, 0)},
+ {W32FUN(WU32SetCaretPos, "SETCARETPOS", MOD_USER, sizeof(SETCARETPOS16))},
+ {W32FUN(WU32HideCaret, "HIDECARET", MOD_USER, sizeof(HIDECARET16))},
+ {W32FUN(WU32ShowCaret, "SHOWCARET", MOD_USER, sizeof(SHOWCARET16))},
+ {W32FUN(WU32SetCaretBlinkTime, "SETCARETBLINKTIME", MOD_USER, sizeof(SETCARETBLINKTIME16))},
+ {W32FUN(WU32GetCaretBlinkTime, "GETCARETBLINKTIME", MOD_USER, 0)},
+
+ /*** 0170 ***/
+ {W32FUN(WU32ArrangeIconicWindows, "ARRANGEICONICWINDOWS", MOD_USER, sizeof(ARRANGEICONICWINDOWS16))},
+ {W32FUN(LOCALAPI, "WINHELP", MOD_USER, sizeof(WINHELP16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "SWITCHTOTHISWINDOW", MOD_USER, 0)},
+ {W32FUN(WU32LoadCursor, "LOADCURSOR", MOD_USER, sizeof(LOADCURSOR16))},
+ {W32FUN(WU32LoadCursor, "LOADICON", MOD_USER, sizeof(LOADICON16))},
+ {W32FUN(WU32LoadBitmap, "LOADBITMAP", MOD_USER, sizeof(LOADBITMAP16))},
+ {W32FUN(LOCALAPI, "LOADSTRING", MOD_USER, sizeof(LOADSTRING16))},
+ {W32FUN(LOCALAPI, "LOADACCELERATORS", MOD_USER, sizeof(LOADACCELERATORS16))},
+ {W32FUN(WU32TranslateAccelerator, "TRANSLATEACCELERATOR", MOD_USER, sizeof(TRANSLATEACCELERATOR16))},
+ {W32FUN(WU32GETSYSTEMMETRICS, "GETSYSTEMMETRICS", MOD_USER, sizeof(GETSYSTEMMETRICS16))},
+
+ /*** 0180 ***/
+ {W32FUN(WU32GETSYSCOLOR, "GETSYSCOLOR", MOD_USER, sizeof(GETSYSCOLOR16))},
+ {W32FUN(WU32SetSysColors, "SETSYSCOLORS", MOD_USER, sizeof(SETSYSCOLORS16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "KILLSYSTEMTIMER", MOD_USER, 0)},
+ {W32FUN(WU32GetCaretPos, "GETCARETPOS", MOD_USER, sizeof(GETCARETPOS16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "QUERYSENDMESSAGE", MOD_USER, sizeof(QUERYSENDMESSAGE16))},
+ {W32FUN(WU32GrayString, "GRAYSTRING", MOD_USER, sizeof(GRAYSTRING16))},
+ {W32FUN(WU32SwapMouseButton, "SWAPMOUSEBUTTON", MOD_USER, sizeof(SWAPMOUSEBUTTON16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "ENDMENU", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "SETSYSMODALWINDOW", MOD_USER, sizeof(SETSYSMODALWINDOW16))},
+ {W32FUN(LOCALAPI, "GETSYSMODALWINDOW", MOD_USER, 0)},
+
+ /*** 0190 ***/
+ {W32FUN(WU32GetUpdateRect, "GETUPDATERECT", MOD_USER, sizeof(GETUPDATERECT16))},
+ {W32FUN(WU32ChildWindowFromPoint, "CHILDWINDOWFROMPOINT", MOD_USER, sizeof(CHILDWINDOWFROMPOINT16))},
+ {W32FUN(WU32InSendMessage, "INSENDMESSAGE", MOD_USER, 0)},
+ {W32FUN(WU32IsClipboardFormatAvailable, "ISCLIPBOARDFORMATAVAILABLE",MOD_USER, sizeof(ISCLIPBOARDFORMATAVAILABLE16))},
+ {W32FUN(WU32DlgDirSelectComboBox, "DLGDIRSELECTCOMBOBOX", MOD_USER, sizeof(DLGDIRSELECTCOMBOBOX16))},
+ {W32FUN(WU32DlgDirListComboBox, "DLGDIRLISTCOMBOBOX", MOD_USER, sizeof(DLGDIRLISTCOMBOBOX16))},
+ {W32FUN(WU32TabbedTextOut, "TABBEDTEXTOUT", MOD_USER, sizeof(TABBEDTEXTOUT16))},
+ {W32FUN(WU32GetTabbedTextExtent, "GETTABBEDTEXTEXTENT", MOD_USER, sizeof(GETTABBEDTEXTEXTENT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "CASCADECHILDWINDOWS", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "TILECHILDWINDOWS", MOD_USER, 0)},
+
+ /*** 0200 ***/
+ {W32FUN(WU32OpenComm, "OPENCOMM", MOD_USER, sizeof(OPENCOMM16))},
+ {W32FUN(WU32SetCommState, "SETCOMMSTATE", MOD_USER, sizeof(SETCOMMSTATE16))},
+ {W32FUN(WU32GetCommState, "GETCOMMSTATE", MOD_USER, sizeof(GETCOMMSTATE16))},
+ {W32FUN(WU32GetCommError, "GETCOMMERROR", MOD_USER, sizeof(GETCOMMERROR16))},
+ {W32FUN(WU32ReadComm, "READCOMM", MOD_USER, sizeof(READCOMM16))},
+ {W32FUN(WU32WriteComm, "WRITECOMM", MOD_USER, sizeof(WRITECOMM16))},
+ {W32FUN(WU32TransmitCommChar, "TRANSMITCOMMCHAR", MOD_USER, sizeof(TRANSMITCOMMCHAR16))},
+ {W32FUN(WU32CloseComm, "CLOSECOMM", MOD_USER, sizeof(CLOSECOMM16))},
+ {W32FUN(WU32SetCommEventMask, "SETCOMMEVENTMASK", MOD_USER, sizeof(SETCOMMEVENTMASK16))},
+ {W32FUN(WU32GetCommEventMask, "GETCOMMEVENTMASK", MOD_USER, sizeof(GETCOMMEVENTMASK16))},
+
+ /*** 0210 ***/
+ {W32FUN(WU32SetCommBreak, "SETCOMMBREAK", MOD_USER, sizeof(SETCOMMBREAK16))},
+ {W32FUN(WU32ClearCommBreak, "CLEARCOMMBREAK", MOD_USER, sizeof(CLEARCOMMBREAK16))},
+ {W32FUN(WU32UngetCommChar, "UNGETCOMMCHAR", MOD_USER, sizeof(UNGETCOMMCHAR16))},
+ {W32FUN(WU32BuildCommDCB, "BUILDCOMMDCB", MOD_USER, sizeof(BUILDCOMMDCB16))},
+ {W32FUN(WU32EscapeCommFunction, "ESCAPECOMMFUNCTION", MOD_USER, sizeof(ESCAPECOMMFUNCTION16))},
+ {W32FUN(WU32FlushComm, "FLUSHCOMM", MOD_USER, sizeof(FLUSHCOMM16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "USERSEEUSERDO", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOOKUPMENUHANDLE", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "DIALOGBOXINDIRECT", MOD_USER, sizeof(DIALOGBOXINDIRECT16))},
+ {W32FUN(LOCALAPI, "CREATEDIALOGINDIRECT", MOD_USER, sizeof(CREATEDIALOGINDIRECT16))},
+
+ /*** 0220 ***/
+ {W32FUN(WU32LoadMenuIndirect, "LOADMENUINDIRECT", MOD_USER, sizeof(LOADMENUINDIRECT16))},
+ {W32FUN(WU32ScrollDC, "SCROLLDC", MOD_USER, sizeof(SCROLLDC16))},
+ {W32FUN(WU32GetKeyboardState, "GETKEYBOARDSTATE", MOD_USER, sizeof(GETKEYBOARDSTATE16))},
+ {W32FUN(WU32SetKeyboardState, "SETKEYBOARDSTATE", MOD_USER, sizeof(SETKEYBOARDSTATE16))},
+ {W32FUN(WU32GetWindowTask, "GETWINDOWTASK", MOD_USER, sizeof(GETWINDOWTASK16))},
+ {W32FUN(WU32EnumTaskWindows, "ENUMTASKWINDOWS", MOD_USER, sizeof(ENUMTASKWINDOWS16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOCKINPUT", MOD_USER, sizeof(LOCKINPUT16))},
+ {W32FUN(WU32GetNextDlgGroupItem, "GETNEXTDLGGROUPITEM", MOD_USER, sizeof(GETNEXTDLGGROUPITEM16))},
+ {W32FUN(WU32GetNextDlgTabItem, "GETNEXTDLGTABITEM", MOD_USER, sizeof(GETNEXTDLGTABITEM16))},
+ {W32FUN(WU32GETTOPWINDOW, "GETTOPWINDOW", MOD_USER, sizeof(GETTOPWINDOW16))},
+
+ /*** 0230 ***/
+ {W32FUN(WU32GETNEXTWINDOW, "GETNEXTWINDOW", MOD_USER, sizeof(GETNEXTWINDOW16))},
+ {W32FUN(LOCALAPI, "GETSYSTEMDEBUGSTATE", MOD_USER, 0)},
+ {W32FUN(WU32SetWindowPos, "SETWINDOWPOS", MOD_USER, sizeof(SETWINDOWPOS16))},
+ {W32FUN(WU32SetParent, "SETPARENT", MOD_USER, sizeof(SETPARENT16))},
+ {W32FUN(WU32UnhookWindowsHook, "UNHOOKWINDOWSHOOK", MOD_USER, sizeof(UNHOOKWINDOWSHOOK16))},
+ {W32FUN(WU32DefHookProc, "DEFHOOKPROC", MOD_USER, sizeof(DEFHOOKPROC16))},
+ {W32FUN(WU32GetCapture, "GETCAPTURE", MOD_USER, 0)},
+ {W32FUN(WU32GetUpdateRgn, "GETUPDATERGN", MOD_USER, sizeof(GETUPDATERGN16))},
+ {W32FUN(WU32ExcludeUpdateRgn, "EXCLUDEUPDATERGN", MOD_USER, sizeof(EXCLUDEUPDATERGN16))},
+ {W32FUN(WU32DialogBoxParam, "DIALOGBOXPARAM", MOD_USER, sizeof(DIALOGBOXPARAM16))},
+
+ /*** 0240 ***/
+ {W32FUN(LOCALAPI, "DIALOGBOXINDIRECTPARAM", MOD_USER, sizeof(DIALOGBOXINDIRECTPARAM16))},
+ {W32FUN(LOCALAPI, "CREATEDIALOGPARAM", MOD_USER, sizeof(CREATEDIALOGPARAM16))},
+ {W32FUN(LOCALAPI, "CREATEDIALOGINDIRECTPARAM",MOD_USER, sizeof(CREATEDIALOGINDIRECTPARAM16))},
+ {W32FUN(WU32GetDialogBaseUnits, "GETDIALOGBASEUNITS", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "EQUALRECT", MOD_USER, sizeof(EQUALRECT16))},
+ {W32FUN(WU32EnableCommNotification, "ENABLECOMMNOTIFICATION", MOD_USER, sizeof(ENABLECOMMNOTIFICATION16))},
+ {W32FUN(WU32ExitWindowsExec, "EXITWINDOWSEXEC", MOD_USER, 0)},
+ {W32FUN(WU32GetCursor, "GETCURSOR", MOD_USER, 0)},
+ {W32FUN(WU32GetOpenClipboardWindow, "GETOPENCLIPBOARDWINDOW", MOD_USER, 0)},
+ {W32FUN(WU32GetAsyncKeyState, "GETASYNCKEYSTATE", MOD_USER, sizeof(GETASYNCKEYSTATE16))},
+
+ /*** 0250 ***/
+ {W32FUN(WU32GETMENUSTATE, "GETMENUSTATE", MOD_USER, sizeof(GETMENUSTATE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "SENDDRIVERMESSAGE", MOD_USER, sizeof(SENDDRIVERMESSAGE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "OPENDRIVER", MOD_USER, sizeof(OPENDRIVER16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "CLOSEDRIVER", MOD_USER, sizeof(CLOSEDRIVER16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETDRIVERMODULEHANDLE", MOD_USER, sizeof(GETDRIVERMODULEHANDLE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "DEFDRIVERPROC", MOD_USER, sizeof(DEFDRIVERPROC16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETDRIVERINFO", MOD_USER, sizeof(GETDRIVERINFO16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETNEXTDRIVER", MOD_USER, sizeof(GETNEXTDRIVER16))},
+ {W32FUN(WU32MapWindowPoints, "MAPWINDOWPOINTS", MOD_USER, sizeof(MAPWINDOWPOINTS16))},
+ {W32FUN(WU32BeginDeferWindowPos, "BEGINDEFERWINDOWPOS", MOD_USER, sizeof(BEGINDEFERWINDOWPOS16))},
+
+ /*** 0260 ***/
+ {W32FUN(WU32DeferWindowPos, "DEFERWINDOWPOS", MOD_USER, sizeof(DEFERWINDOWPOS16))},
+ {W32FUN(WU32EndDeferWindowPos, "ENDDEFERWINDOWPOS", MOD_USER, sizeof(ENDDEFERWINDOWPOS16))},
+ {W32FUN(WU32GETWINDOW, "GETWINDOW", MOD_USER, sizeof(GETWINDOW16))},
+ {W32FUN(WU32GETMENUITEMCOUNT, "GETMENUITEMCOUNT", MOD_USER, sizeof(GETMENUITEMCOUNT16))},
+ {W32FUN(WU32GETMENUITEMID, "GETMENUITEMID", MOD_USER, sizeof(GETMENUITEMID16))},
+ {W32FUN(WU32ShowOwnedPopups, "SHOWOWNEDPOPUPS", MOD_USER, sizeof(SHOWOWNEDPOPUPS16))},
+ {W32FUN(WU32SetMessageQueue, "SETMESSAGEQUEUE", MOD_USER, sizeof(SETMESSAGEQUEUE16))},
+ {W32FUN(WU32ShowScrollBar, "SHOWSCROLLBAR", MOD_USER, sizeof(SHOWSCROLLBAR16))},
+ {W32FUN(WU32GlobalAddAtom, "GLOBALADDATOM", MOD_USER, sizeof(GLOBALADDATOM16))},
+ {W32FUN(WU32GlobalDeleteAtom, "GLOBALDELETEATOM", MOD_USER, sizeof(GLOBALDELETEATOM16))},
+
+ /*** 0270 ***/
+ {W32FUN(WU32GlobalFindAtom, "GLOBALFINDATOM", MOD_USER, sizeof(GLOBALFINDATOM16))},
+ {W32FUN(WU32GlobalGetAtomName, "GLOBALGETATOMNAME", MOD_USER, sizeof(GLOBALGETATOMNAME16))},
+ {W32FUN(WU32ISZOOMED, "ISZOOMED", MOD_USER, sizeof(ISZOOMED16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "CONTROLPANELINFO", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETNEXTQUEUEWINDOW", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "REPAINTSCREEN", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOCKMYTASK", MOD_USER, 0)},
+ {W32FUN(WU32GetDlgCtrlID, "GETDLGCTRLID", MOD_USER, sizeof(GETDLGCTRLID16))},
+ {W32FUN(WU32GETDESKTOPWINDOW, "GETDESKTOPHWND", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETDESKPATTERN", MOD_USER, 0)},
+
+ /*** 0280 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "SETSYSTEMMENU", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SNAPWINDOW", MOD_USER, 0)},
+ {W32FUN(WU32SelectPalette, "SELECTPALETTE", MOD_USER, sizeof(SELECTPALETTE16))},
+ {W32FUN(WU32RealizePalette, "REALIZEPALETTE", MOD_USER, sizeof(REALIZEPALETTE16))},
+ {W32FUN(WU32GetFreeSystemResources, "GETFREESYSTEMRESOURCES", MOD_USER, sizeof(GETFREESYSTEMRESOURCES16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETDESKWALLPAPER", MOD_USER, 0)},
+ {W32FUN(WU32GETDESKTOPWINDOW, "GETDESKTOPWINDOW", MOD_USER, 0)},
+ {W32FUN(WU32GetLastActivePopup, "GETLASTACTIVEPOPUP", MOD_USER, sizeof(GETLASTACTIVEPOPUP16))},
+ {W32FUN(WU32GetMessageExtraInfo, "GETMESSAGEEXTRAINFO", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "KEYBD_EVENT", MOD_USER, 0)},
+
+ /*** 0290 ***/
+ {W32FUN(WU32RedrawWindow, "REDRAWWINDOW", MOD_USER, sizeof(REDRAWWINDOW16))},
+ {W32FUN(WU32SetWindowsHookEx, "SETWINDOWSHOOKEX", MOD_USER, sizeof(SETWINDOWSHOOKEX16))},
+ {W32FUN(WU32UnhookWindowsHookEx, "UNHOOKWINDOWSHOOKEX", MOD_USER, sizeof(UNHOOKWINDOWSHOOKEX16))},
+ {W32FUN(WU32CallNextHookEx, "CALLNEXTHOOKEX", MOD_USER, sizeof(CALLNEXTHOOKEX16))},
+ {W32FUN(WU32LockWindowUpdate, "LOCKWINDOWUPDATE", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "MOUSE_EVENT", MOD_USER, 0)},
+
+ /*** 0300 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "EDITWNDPROC", MOD_USER, sizeof(SENDMESSAGE16))},
+ {W32FUN(LOCALAPI, "STATICWNDPROC", MOD_USER, sizeof(SENDMESSAGE16))},
+ {W32FUN(LOCALAPI, "BUTTONWNDPROC", MOD_USER, sizeof(SENDMESSAGE16))},
+ {W32FUN(LOCALAPI, "SBWNDPROC", MOD_USER, sizeof(SENDMESSAGE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "DESKTOPWNDPROC", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "MENUWINDOWPROC", MOD_USER, sizeof(SENDMESSAGE16))},
+ {W32FUN(LOCALAPI, "LBOXCTLWNDPROC", MOD_USER, sizeof(SENDMESSAGE16))},
+ {W32FUN(WU32DefDlgProc, "DEFDLGPROC", MOD_USER, sizeof(DEFDLGPROC16))},
+ {W32FUN(WU32GetClipCursor, "GETCLIPCURSOR", MOD_USER, sizeof(GETCLIPCURSOR16))},
+
+ /*** 0310 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "CONTSCROLL", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "CARETBLINKPROC", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SENDMESSAGE2", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "POSTMESSAGE2", MOD_USER, 0)},
+ {W32FUN(WU32SignalProc, "SIGNALPROC", MOD_USER, sizeof(SIGNALPROC16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "XCSTODS", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "COMPUPDATERECT", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "COMPUPDATERGN", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETWC2", MOD_USER, 0)},
+ {W32FUN(WU32ScrollWindowEx, "SCROLLWINDOWEX", MOD_USER, sizeof(SCROLLWINDOWEX16))},
+
+ /*** 0320 ***/
+ {W32FUN(WU32SysErrorBox, "SYSERRORBOX", MOD_USER, sizeof(SYSERRORBOX16))},
+ {W32FUN(WU32SetEventHook, "SETEVENTHOOK", MOD_USER, sizeof(SETEVENTHOOK16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "WINOLDAPPHACKOMATIC", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETMESSAGE2", MOD_USER, 0)},
+ {W32FUN(WU32FillWindow, "FILLWINDOW", MOD_USER, sizeof(FILLWINDOW16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "PAINTRECT", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETCONTROLBRUSH", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "KILLTIMER2", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETTIMER2", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "MENUITEMSTATE", MOD_USER, 0)},
+
+ /*** 0330 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "SETGETKBDSTATE", MOD_USER, 0)},
+ {W32FUN(WU32EnableHardwareInput, "ENABLEHARDWAREINPUT", MOD_USER, sizeof(ENABLEHARDWAREINPUT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "USERYIELD", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "ISUSERIDLE", MOD_USER, 0)},
+ {W32FUN(WU32GetQueueStatus, "GETQUEUESTATUS", MOD_USER, sizeof(GETQUEUESTATUS16))},
+ {W32FUN(WU32GetInputState, "GETINPUTSTATE", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOADCURSORICONHANDLER", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "GETMOUSEEVENTPROC", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0340 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "WINFARFRAME", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "_FFFE_FARFRAME", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETFILEPORTNAME", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "COMBOBOXCTLWNDPROC", MOD_USER, sizeof(SENDMESSAGE16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "TITLEWNDPROC", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "FILEPORTDLGPROC", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SWITCHWNDPROC", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0350 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "TABTHETEXTOUTFORWIMPS", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "BROADCASTMESSAGE", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOADDIBCURSORHANDLER", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOADDIBICONHANDLER", MOD_USER, 0)},
+ {W32FUN(WU32IsMenu, "ISMENU", MOD_USER, sizeof(ISMENU16))},
+ {W32FUN(WU32GetDCEx, "GETDCEX", MOD_USER, sizeof(GETDCEX16))},
+
+ /*** 0360 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "COPYICON", MOD_USER, sizeof(COPYICON16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "COPYCURSOR", MOD_USER, sizeof(COPYCURSOR16))},
+
+ /*** 0370 ***/
+ {W32FUN(WU32GetWindowPlacement, "GETWINDOWPLACEMENT", MOD_USER, sizeof(GETWINDOWPLACEMENT16))},
+ {W32FUN(WU32SetWindowPlacement, "SETWINDOWPLACEMENT", MOD_USER, sizeof(SETWINDOWPLACEMENT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "SUBTRACTRECT", MOD_USER, sizeof(SUBTRACTRECT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0380 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0390 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0400 ***/
+ {W32FUN(WU32FinalUserInit, "FINALUSERINIT", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(WU32GetPriorityClipboardFormat, "GETPRIORITYCLIPBOARDFORMAT",MOD_USER, sizeof(GETPRIORITYCLIPBOARDFORMAT16))},
+ {W32FUN(WU32UnregisterClass, "UNREGISTERCLASS", MOD_USER, sizeof(UNREGISTERCLASS16))},
+ {W32FUN(WU32GetClassInfo, "GETCLASSINFO", MOD_USER, sizeof(GETCLASSINFO16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(WU32CreateCursor, "CREATECURSOR", MOD_USER, sizeof(CREATECURSOR16))},
+ {W32FUN(WU32CreateIcon, "CREATEICON", MOD_USER, sizeof(CREATEICON16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "CREATECURSORICONINDIRECT", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "MB_DLGPROC", MOD_USER, 0)},
+
+ /*** 0410 ***/
+ {W32FUN(WU32InsertMenu, "INSERTMENU", MOD_USER, sizeof(INSERTMENU16))},
+ {W32FUN(WU32AppendMenu, "APPENDMENU", MOD_USER, sizeof(APPENDMENU16))},
+ {W32FUN(WU32RemoveMenu, "REMOVEMENU", MOD_USER, sizeof(REMOVEMENU16))},
+ {W32FUN(WU32DeleteMenu, "DELETEMENU", MOD_USER, sizeof(DELETEMENU16))},
+ {W32FUN(WU32ModifyMenu, "MODIFYMENU", MOD_USER, sizeof(MODIFYMENU16))},
+ {W32FUN(WU32CreatePopupMenu, "CREATEPOPUPMENU", MOD_USER, 0)},
+ {W32FUN(WU32TrackPopupMenu, "TRACKPOPUPMENU", MOD_USER, sizeof(TRACKPOPUPMENU16))},
+ {W32FUN(WU32GetMenuCheckMarkDimensions, "GETMENUCHECKMARKDIMENSIONS",MOD_USER, 0)},
+ {W32FUN(WU32SetMenuItemBitmaps, "SETMENUITEMBITMAPS", MOD_USER, sizeof(SETMENUITEMBITMAPS16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0420 ***/
+ {W32FUN(LOCALAPI, "_WSPRINTF", MOD_USER, sizeof(WSPRINTF16))},
+ {W32FUN(LOCALAPI, "WVSPRINTF", MOD_USER, sizeof(WVSPRINTF16))},
+ {W32FUN(WU32DlgDirSelectEx, "DLGDIRSELECTEX", MOD_USER, sizeof(DLGDIRSELECTEX16))},
+ {W32FUN(WU32DlgDirSelectComboBoxEx, "DLGDIRSELECTCOMBOBOXEX", MOD_USER, sizeof(DLGDIRSELECTCOMBOBOXEX16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0430 ***/
+ {W32FUN(WU32lstrcmp, "LSTRCMP", MOD_USER, 0)},
+ {W32FUN(WU32AnsiUpper, "ANSIUPPER", MOD_USER, sizeof(ANSIUPPER16))},
+ {W32FUN(WU32AnsiLower, "ANSILOWER", MOD_USER, sizeof(ANSILOWER16))},
+ {W32FUN(WU32IsCharAlpha, "ISCHARALPHA", MOD_USER, sizeof(ISCHARALPHA16))},
+ {W32FUN(WU32IsCharAlphaNumeric, "ISCHARALPHANUMERIC", MOD_USER, sizeof(ISCHARALPHANUMERIC16))},
+ {W32FUN(WU32IsCharUpper, "ISCHARUPPER", MOD_USER, sizeof(ISCHARUPPER16))},
+ {W32FUN(WU32IsCharLower, "ISCHARLOWER", MOD_USER, sizeof(ISCHARLOWER16))},
+ {W32FUN(WU32AnsiUpperBuff, "ANSIUPPERBUFF", MOD_USER, sizeof(ANSIUPPERBUFF16))},
+ {W32FUN(WU32AnsiLowerBuff, "ANSILOWERBUFF", MOD_USER, sizeof(ANSILOWERBUFF16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0440 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "MDICLIENTWNDPROC", MOD_USER, sizeof(SENDMESSAGE16))},
+ {W32FUN(WU32DefFrameProc, "DEFFRAMEPROC", MOD_USER, sizeof(DEFFRAMEPROC16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(WU32DefMDIChildProc, "DEFMDICHILDPROC", MOD_USER, sizeof(DEFMDICHILDPROC16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0450 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(WU32TranslateMDISysAccel, "TRANSLATEMDISYSACCEL", MOD_USER, sizeof(TRANSLATEMDISYSACCEL16))},
+ {W32FUN(WU32CreateWindowEx, "CREATEWINDOWEX", MOD_USER, sizeof(CREATEWINDOWEX16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "LBOXCARETBLINKER", MOD_USER, 0)},
+ {W32FUN(WU32AdjustWindowRectEx, "ADJUSTWINDOWRECTEX", MOD_USER, sizeof(ADJUSTWINDOWRECTEX16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "GETICONID", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "LOADICONHANDLER", MOD_USER, 0)},
+ {W32FUN(WU32DestroyIcon, "DESTROYICON", MOD_USER, sizeof(DESTROYICON16))},
+ {W32FUN(WU32DestroyCursor, "DESTROYCURSOR", MOD_USER, sizeof(DESTROYCURSOR16))},
+ {W32FUN(LOCALAPI, "DUMPICON", MOD_USER, 0)},
+
+ /*** 0460 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "GETINTERNALWINDOWPOS", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SETINTERNALWINDOWPOS", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "CALCCHILDSCROLL", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "SCROLLCHILDREN", MOD_USER, 0)},
+ {W32FUN(WU32DragObject, "DRAGOBJECT", MOD_USER, sizeof(DRAGOBJECT16))},
+ {W32FUN(WU32DragDetect, "DRAGDETECT", MOD_USER, sizeof(DRAGDETECT16))},
+ {W32FUN(WU32DrawFocusRect, "DRAWFOCUSRECT", MOD_USER, sizeof(DRAWFOCUSRECT16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0470 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "STRINGFUNC", MOD_USER, 0)},
+ {W32FUN(WU32lstrcmpi, "LSTRCMPI", MOD_USER, 0)},
+ {W32FUN(WU32AnsiNext, "ANSINEXT", MOD_USER, sizeof(ANSINEXT16))},
+ {W32FUN(WU32AnsiPrev, "ANSIPREV", MOD_USER, sizeof(ANSIPREV16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0480 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(WU32EnableScrollBar, "ENABLESCROLLBAR", MOD_USER, sizeof(ENABLESCROLLBAR16))},
+ {W32FUN(WU32SystemParametersInfo, "SYSTEMPARAMETERSINFO", MOD_USER, sizeof(SYSTEMPARAMETERSINFO16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0490 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+
+ /*** 0500 ***/
+ {W32FUN(LOCALAPI, "FARCALLNETDRIVER", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETOPENJOB", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETCLOSEJOB", MOD_USER, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETHOLDJOB", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETRELEASEJOB", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETCANCELJOB", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETSETJOBCOPIES", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETWATCHQUEUE", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETUNWATCHQUEUE", MOD_USER, 0)},
+
+ /*** 0510 ***/
+ {W32FUN(LOCALAPI, "WNETLOCKQUEUEDATA", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETUNLOCKQUEUEDATA", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETGETCONNECTION", MOD_USER, sizeof(WNETGETCONNECTION16))},
+ {W32FUN(LOCALAPI, "WNETGETCAPS", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETDEVICEMODE", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETBROWSEDIALOG", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETGETUSER", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETADDCONNECTION", MOD_USER, sizeof(WNETADDCONNECTION16))},
+ {W32FUN(LOCALAPI, "WNETCANCELCONNECTION", MOD_USER, sizeof(WNETCANCELCONNECTION16))},
+ {W32FUN(LOCALAPI, "WNETGETERROR", MOD_USER, 0)},
+
+ /*** 0520 ***/
+ {W32FUN(LOCALAPI, "WNETGETERRORTEXT", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETENABLE", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETDISABLE", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETRESTORECONNECTION", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETWRITEJOB", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETCONNECTDIALOG", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETDISCONNECTDIALOG", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETCONNECTIONDIALOG", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETVIEWQUEUEDIALOG", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETPROPERTYDIALOG", MOD_USER, 0)},
+
+ /*** 0530 ***/
+ {W32FUN(LOCALAPI, "WNETGETDIRECTORYTYPE", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETDIRECTORYNOTIFY", MOD_USER, 0)},
+ {W32FUN(LOCALAPI, "WNETGETPROPERTYTEXT", MOD_USER, 0)},
+ {W32FUN(WU32NotifyWow, "NOTIFYWOW", MOD_USER, sizeof(NOTIFYWOW16))},
+ {W32FUN(WU32WOWGetIdFromDirectory, "WOWGETIDFROMDIRECTORY", MOD_USER, sizeof(WOWGETIDFROMDIRECTORY16))},
+ {W32FUN(WU32WordBreakProc, "WORDBREAKPROC", MOD_USER, sizeof(WORDBREAKPROC16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_USER, 0)},
+ {W32FUN(WU32MouseEvent, "MOUSEEVENT", MOD_USER, sizeof(MOUSEEVENT16))},
+ {W32FUN(WU32KeybdEvent, "KEYBDEVENT", MOD_USER, sizeof(KEYBDEVENT16))},
diff --git a/private/mvdm/wow32/wutext.c b/private/mvdm/wow32/wutext.c
new file mode 100644
index 000000000..95e4df0b6
--- /dev/null
+++ b/private/mvdm/wow32/wutext.c
@@ -0,0 +1,72 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUTEXT.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wutext.c);
+
+
+ULONG FASTCALL WU32GetTabbedTextExtent(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ PINT p5;
+ register PGETTABBEDTEXTEXTENT16 parg16;
+ INT BufferT[256];
+
+ GETARGPTR(pFrame, sizeof(GETTABBEDTEXTEXTENT16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+ p5 = STACKORHEAPALLOC(parg16->f4 * sizeof(INT), sizeof(BufferT), BufferT);
+ getintarray16(parg16->f5, parg16->f4, p5);
+
+ ul = GETDWORD16(GetTabbedTextExtent(HDC32(parg16->f1), psz2,
+ INT32(parg16->f3), INT32(parg16->f4), p5 ));
+
+ STACKORHEAPFREE(p5, BufferT);
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+ULONG FASTCALL WU32TabbedTextOut(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz4;
+ PINT p7;
+ register PTABBEDTEXTOUT16 parg16;
+ INT BufferT[256];
+
+ GETARGPTR(pFrame, sizeof(TABBEDTEXTOUT16), parg16);
+ GETPSZPTR(parg16->f4, psz4);
+ p7 = STACKORHEAPALLOC(parg16->f6 * sizeof(INT), sizeof(BufferT), BufferT);
+ getintarray16(parg16->f7, parg16->f6, p7);
+
+ ul = GETLONG16(TabbedTextOut(
+ HDC32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ psz4,
+ INT32(parg16->f5),
+ INT32(parg16->f6),
+ p7,
+ INT32(parg16->f8)
+ ));
+
+ STACKORHEAPFREE(p7, BufferT);
+ FREEPSZPTR(psz4);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wutext.h b/private/mvdm/wow32/wutext.h
new file mode 100644
index 000000000..11fe9a45f
--- /dev/null
+++ b/private/mvdm/wow32/wutext.h
@@ -0,0 +1,17 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUTEXT.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+
+ULONG FASTCALL WU32GetTabbedTextExtent(PVDMFRAME pFrame);
+ULONG FASTCALL WU32TabbedTextOut(PVDMFRAME pFrame);
diff --git a/private/mvdm/wow32/wutmr.c b/private/mvdm/wow32/wutmr.c
new file mode 100644
index 000000000..693a78eb3
--- /dev/null
+++ b/private/mvdm/wow32/wutmr.c
@@ -0,0 +1,686 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUTMR.C
+ * WOW32 16-bit User Timer API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+ * 24-Feb-1993 reworked to use array of timer functions - barryb
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wutmr.c);
+
+LIST_ENTRY TimerList;
+
+// Element Zero is unused.
+
+STATIC PTMR aptmrWOWTimers[] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+ };
+
+
+STATIC TIMERPROC afnTimerFuncs[] = {
+ NULL, W32Timer1, W32Timer2, W32Timer3,
+ W32Timer4, W32Timer5, W32Timer6, W32Timer7,
+ W32Timer8, W32Timer9, W32Timer10, W32Timer11,
+ W32Timer12, W32Timer13, W32Timer14, W32Timer15,
+ W32Timer16, W32Timer17, W32Timer18, W32Timer19,
+ W32Timer20, W32Timer21, W32Timer22, W32Timer23,
+ W32Timer24, W32Timer25, W32Timer26, W32Timer27
+ };
+
+
+/* Timer mapping functions
+ *
+ * The basic 16-bit timer mapping operations are Add, Find and Free. When
+ * a 16-bit app calls SetTimer, we call Win32's SetTimer with W32TimerProc
+ * in place of the 16-bit proc address. Assuming the timer is successfully
+ * allocated, we add the timer to our own table, recording the 16-bit proc
+ * address.
+ */
+
+
+//
+// Search for a timer by its 16-bit information. Looks in the list of
+// active timers. If the timer is found by this routine, then SetTimer()
+// has been called and KillTimer() has not yet been called.
+//
+PTMR IsDuplicateTimer16(HWND16 hwnd16, HTASK16 htask16, WORD wIDEvent)
+{
+ register PTMR ptmr;
+ register INT iTimer;
+
+ //
+ // Excel calls SetTimer with hwnd==NULL but dispatches the
+ // WM_TIMER messages with hwnd!=NULL. so call it a match if
+ // hwnd16!=NULL and ptmr->hwnd16==NULL
+ //
+
+ for (iTimer=1; iTimer<NUMEL(aptmrWOWTimers); iTimer++) {
+
+ ptmr = aptmrWOWTimers[iTimer];
+
+ if (ptmr) {
+ if (LOWORD(ptmr->dwEventID) == wIDEvent &&
+ ptmr->htask16 == htask16 &&
+ (ptmr->hwnd16 == hwnd16 || !ptmr->hwnd16)) {
+
+ return ptmr;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+//
+// Search for a timer by its 32-bit information. Looks in the list of
+// all timers (including those that have already been killed by KillTimer().
+//
+//
+PTMR FindTimer32(HWND16 hwnd16, DWORD dwIDEvent)
+{
+ register PTMR ptmr;
+ HAND16 htask16;
+
+ htask16 = CURRENTPTD()->htask16;
+
+ //
+ // Excel calls SetTimer with hwnd==NULL but dispatches the
+ // WM_TIMER messages with hwnd!=NULL. so call it a match if
+ // hwnd16!=NULL and ptmr->hwnd16==NULL
+ //
+
+ for (ptmr = (PTMR)TimerList.Flink; ptmr != (PTMR)&TimerList; ptmr = (PTMR)ptmr->TmrList.Flink) {
+
+ if (ptmr->dwEventID == dwIDEvent &&
+ ptmr->htask16 == htask16 &&
+ (ptmr->hwnd16 == hwnd16 || (hwnd16 && !ptmr->hwnd16))) {
+
+ return ptmr;
+ }
+ }
+
+ return (PTMR)NULL;
+}
+
+
+//
+// Search for a timer by its 16-bit information. Looks in the list of
+// all timers (including those that have already been killed by KillTimer().
+//
+//
+PTMR FindTimer16(HWND16 hwnd16, HTASK16 htask16, WORD wIDEvent)
+{
+ register PTMR ptmr;
+
+ //
+ // Excel calls SetTimer with hwnd==NULL but dispatches the
+ // WM_TIMER messages with hwnd!=NULL. so call it a match if
+ // hwnd16!=NULL and ptmr->hwnd16==NULL
+ //
+
+ for (ptmr = (PTMR)TimerList.Flink; ptmr != (PTMR)&TimerList; ptmr = (PTMR)ptmr->TmrList.Flink) {
+
+ if (LOWORD(ptmr->dwEventID) == wIDEvent &&
+ ptmr->htask16 == htask16 &&
+ (ptmr->hwnd16 == hwnd16 || (hwnd16 && !ptmr->hwnd16))) {
+
+ return ptmr;
+ }
+ }
+
+ return (PTMR)NULL;
+}
+
+
+//
+// Search for a killed timer by its 16-bit information.
+//
+//
+PTMR FindKilledTimer16(HWND16 hwnd16, HTASK16 htask16, WORD wIDEvent)
+{
+ register PTMR ptmr;
+
+ for (ptmr = (PTMR)TimerList.Flink; ptmr != (PTMR)&TimerList; ptmr = (PTMR)ptmr->TmrList.Flink) {
+
+ if (ptmr->wIndex == 0 &&
+ ptmr->htask16 == htask16 &&
+ ptmr->hwnd16 == hwnd16 &&
+ (LOWORD(ptmr->dwEventID) == wIDEvent || !hwnd16)) {
+ // 1. the timer has been killed and
+ // 2. the timer is in this task and
+ // 3. the hwnds match (both might be 0) and
+ // 4. the IDs match, or the hwnds are both 0 (in that case,
+ // IDs are ignored)
+
+ return ptmr;
+ }
+ }
+
+ return (PTMR)NULL;
+}
+
+
+VOID FreeTimer16(PTMR ptmr)
+{
+ WOW32ASSERT(ptmr->wIndex == 0 || ptmr == aptmrWOWTimers[ptmr->wIndex]);
+ aptmrWOWTimers[ptmr->wIndex] = NULL;
+ RemoveEntryList(&ptmr->TmrList);
+ free_w(ptmr);
+}
+
+
+VOID DestroyTimers16(HTASK16 htask16)
+{
+ PTMR ptmr, next;
+
+ for (ptmr = (PTMR)TimerList.Flink; ptmr != (PTMR)&TimerList; ptmr = next) {
+
+ next = (PTMR)ptmr->TmrList.Flink;
+ if (ptmr->htask16 == htask16) {
+
+ //
+ // don't call KillTimer() if the timer was associated with
+ // a window and the window is gone, USER has already
+ // cleaned it up.
+ //
+
+ if (ptmr == aptmrWOWTimers[ptmr->wIndex] && (!ptmr->hwnd32 || IsWindow(ptmr->hwnd32))) {
+ if ( KillTimer(ptmr->hwnd32, ptmr->dwEventID) ) {
+ LOGDEBUG(LOG_IMPORTANT,
+ ("DestroyTimers16:Killed %04x\n",ptmr->dwEventID));
+ } else {
+ LOGDEBUG(LOG_ERROR,
+ ("DestroyTimers16:FAILED %04x\n",ptmr->dwEventID));
+ }
+ }
+ FreeTimer16(ptmr);
+ }
+
+ }
+}
+
+
+VOID W32TimerFunc(UINT index, HWND hwnd, UINT idEvent, DWORD dwTime)
+{
+ PARM16 Parm16;
+ register PTMR ptmr;
+
+ ptmr = aptmrWOWTimers[index];
+
+ if ( !ptmr ) {
+ LOGDEBUG(LOG_ALWAYS,(" W32TimerFunc ERROR: cannot find timer %08x\n", idEvent));
+ return;
+ }
+
+ if (ptmr->dwEventID != idEvent) {
+ //
+ // This is an extra timer message which was already in the message
+ // queue when the app called KillTimer(). The PTMR isn't in the
+ // array, but it is still linked into the TimerList.
+ //
+ LOGDEBUG(LOG_WARNING,(" W32TimerFunc WARNING: Timer %08x called after KillTimer()\n", idEvent));
+ for (ptmr = (PTMR)TimerList.Flink; ptmr != (PTMR)&TimerList; ptmr = (PTMR)ptmr->TmrList.Flink) {
+ if (ptmr->dwEventID == idEvent) {
+ break;
+ }
+ }
+
+ if ( ptmr == (PTMR)&TimerList ) {
+ LOGDEBUG(LOG_ALWAYS,(" W32TimerFunc ERROR: cannot find timer %08x (second case)\n", idEvent));
+ return;
+ }
+ }
+
+ Parm16.WndProc.hwnd = ptmr->hwnd16;
+ Parm16.WndProc.wMsg = WM_TIMER;
+ Parm16.WndProc.wParam = LOWORD(ptmr->dwEventID);
+ Parm16.WndProc.lParam = dwTime;
+ Parm16.WndProc.hInst = 0; // callback16 defaults to ss
+
+ CallBack16(RET_WNDPROC, &Parm16, ptmr->vpfnTimerProc, NULL);
+}
+
+
+/*++
+ BOOL KillTimer(<hwnd>, <nIDEvent>)
+ HWND <hwnd>;
+ INT <nIDEvent>;
+
+ The %KillTimer% function kills the timer event identified by the <hwnd> and
+ <nIDEvent> parameters. Any pending WM_TIMER messages associated with the
+ timer are removed from the message queue.
+
+ <hwnd>
+ Identifies the window associated with the given timer event. This must
+ be the same value passed as the hwnd parameter to the SetTimer function
+ call that created the timer event.
+
+ <nIDEvent>
+ Specifies the timer event to be killed. If the application called
+ %SetTimer% with the <hwnd> parameter set to NULL, this must be the event
+ identifier returned by %SetTimer%. If the <hwnd> parameter of %SetTimer%
+ was a valid window handle, <nIDEvent> must be the value of the
+ <nIDEvent> parameter passed to %SetTimer%.
+
+ The return value specifies the outcome of the function. It is TRUE if the
+ event was killed. It is FALSE if the %KillTimer% function could not find the
+ specified timer event.
+--*/
+
+ULONG FASTCALL WU32KillTimer(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PTMR ptmr;
+ register PKILLTIMER16 parg16;
+ HWND16 hwnd16;
+ WORD wIDEvent;
+ HAND16 htask16;
+
+ GETARGPTR(pFrame, sizeof(KILLTIMER16), parg16);
+
+ htask16 = CURRENTPTD()->htask16;
+ hwnd16 = (HWND16)parg16->f1;
+ wIDEvent = parg16->f2;
+
+ ptmr = IsDuplicateTimer16(hwnd16, htask16, wIDEvent);
+
+ if (ptmr) {
+ ul = GETBOOL16(KillTimer(ptmr->hwnd32, ptmr->dwEventID));
+ aptmrWOWTimers[ptmr->wIndex] = NULL;
+ ptmr->wIndex = 0;
+ }
+ else {
+ ul = 0;
+ LOGDEBUG(LOG_IMPORTANT,(" WU32KillTimer ERROR: cannot find timer %04x\n", wIDEvent));
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ WORD SetTimer(<hwnd>, <nIDEvent>, <wElapse>, <lpTimerFunc>)
+ HWND <hwnd>;
+ int <nIDEvent>;
+ WORD <wElapse>;
+ FARPROC <lpTimerFunc>;
+
+ The %SetTimer% function creates a system timer event. When a timer event
+ occurs, Windows passes a WM_TIMER message to the application-supplied
+ function specified by the <lpTimerFunc> parameter. The function can then
+ process the event. A NULL value for <lpTimerFunc> causes WM_TIMER messages
+ to be placed in the application queue.
+
+ <hwnd>
+ Identifies the window to be associated with the timer. If hwnd is NULL,
+ no window is associated with the timer.
+
+ <nIDEvent>
+ Specifies a nonzero timer-event identifier if the <hwnd> parameter
+ is not NULL.
+
+ <wElapse>
+ Specifies the elapsed time (in milliseconds) between timer
+ events.
+
+ <lpTimerFunc>
+ Is the procedure-instance address of the function to be
+ notified when the timer event takes place. If <lpTimerFunc> is NULL, the
+ WM_TIMER message is placed in the application queue, and the %hwnd%
+ member of the %MSG% structure contains the <hwnd> parameter given in the
+ %SetTimer% function call. See the following Comments section for
+ details.
+
+ The return value specifies the integer identifier for the new timer event.
+ If the <hwnd> parameter is NULL, an application passes this value to the
+ %KillTimer% function to kill the timer event. The return value is zero if
+ the timer was not created.
+
+ Timers are a limited global resource; therefore, it is important that an
+ application check the value returned by the %SetTimer% function to verify
+ that a timer is actually available.
+
+ To install a timer function, %SetTimer% must receive a procedure-instance
+ address of the function, and the function must be exported in the
+ application's module-definition file. A procedure-instance address can be
+ created using the %MakeProcInstance% function.
+
+ The callback function must use the Pascal calling convention and must be
+ declared %FAR%.
+
+ Callback Function:
+
+ WORD FAR PASCAL <TimerFunc>(<hwnd>, <wMsg>, <nIDEvent>, <dwTime>)
+ HWND <hwnd>;
+ WORD <wMsg>;
+ int <nIDEvent>;
+ DWORD <dwTime>;
+
+ <TimerFunc> is a placeholder for the application-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the application's module-definition file.
+
+ <hwnd>
+ Identifies the window associated with the timer event.
+
+ <wMsg>
+ Specifies the WM_TIMER message.
+
+ <nIDEvent>
+ Specifies the timer's ID.
+
+ <dwTime>
+ Specifies the current system time.
+--*/
+
+ULONG FASTCALL WU32SetTimer(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PTMR ptmr;
+ register PSETTIMER16 parg16;
+ HWND16 hwnd16;
+ WORD wIDEvent;
+ WORD wElapse;
+ DWORD vpfnTimerProc;
+ DWORD dwTimerProc32;
+ HAND16 htask16;
+ INT iTimer;
+
+ GETARGPTR(pFrame, sizeof(SETTIMER16), parg16);
+
+ ul = 0;
+
+ htask16 = CURRENTPTD()->htask16;
+ hwnd16 = (HWND16)parg16->f1;
+ wIDEvent = parg16->f2;
+ wElapse = parg16->f3;
+
+ // Don't allow WOW apps to set a timer with a period of less than
+ // 55 ms. Myst and Winstone depend on this.
+ if (wElapse < 55) wElapse = 55;
+
+ vpfnTimerProc = VPFN32(parg16->f4);
+
+ ptmr = IsDuplicateTimer16(hwnd16, htask16, wIDEvent);
+
+ if (!ptmr) {
+
+ // Loop through the slots in the timer array
+
+ iTimer = 2;
+ while (iTimer < NUMEL(aptmrWOWTimers)) {
+ /*
+ ** Find a slot in the arrays for which
+ ** no pointer has yet been allocated.
+ */
+ if ( !aptmrWOWTimers[iTimer] ) {
+
+ //
+ // See if there is already thunking information for this
+ // timer. If there is, delete it from the list of timer
+ // info and re-use its memory because this new timer
+ // superceeds the old thunking information.
+ //
+ ptmr = FindKilledTimer16(hwnd16, htask16, wIDEvent);
+ if (ptmr) {
+
+ RemoveEntryList(&ptmr->TmrList);
+
+ } else {
+
+ // Allocate a TMR structure for the new timer
+ ptmr = malloc_w(sizeof(TMR));
+
+ }
+
+ aptmrWOWTimers[iTimer] = ptmr;
+
+ if (!ptmr) {
+ LOGDEBUG(LOG_ALWAYS,(" WOW32 ERROR: TMR allocation failure\n"));
+ return 0;
+ }
+
+ break; // Fall out into initialization code
+ }
+ iTimer++;
+ }
+ if (iTimer >= NUMEL(aptmrWOWTimers)) {
+ LOGDEBUG(LOG_ALWAYS,(" WOW32 ERROR: out of timer slots\n"));
+ return 0;
+ }
+
+ // Initialize the constant parts of the TMR structure (done on 1st SetTimer)
+ InsertHeadList(&TimerList, &ptmr->TmrList);
+ ptmr->hwnd16 = hwnd16;
+ ptmr->hwnd32 = HWND32(hwnd16);
+ ptmr->htask16 = htask16;
+ ptmr->wIndex = (WORD)iTimer;
+ }
+
+
+ // Setup the changeable parts of the TMR structure (done for every SetTimer)
+
+ if (vpfnTimerProc) {
+ dwTimerProc32 = (DWORD)afnTimerFuncs[ptmr->wIndex];
+ } else {
+ dwTimerProc32 = (DWORD)NULL;
+ }
+
+ ptmr->vpfnTimerProc = vpfnTimerProc;
+ ptmr->dwTimerProc32 = dwTimerProc32;
+
+ ul = SetTimer(
+ ptmr->hwnd32,
+ (UINT)wIDEvent,
+ (UINT)wElapse,
+ (TIMERPROC)dwTimerProc32 );
+
+ //
+ // USER-generated timerID's are between 0x100 and 0x7fff
+ //
+
+ WOW32ASSERT(HIWORD(ul) == 0);
+
+ if (ul) {
+
+ ptmr->dwEventID = ul;
+
+ //
+ // when hwnd!=NULL and nEventID==0 the API returns 1 to
+ // indicate success but the timer's ID is 0 as requested.
+ //
+
+ if (!wIDEvent && ptmr->hwnd32)
+ ptmr->dwEventID = 0;
+
+ } else {
+
+ // Since the real SetTimer failed, free
+ // our local data using simply our own timer ID
+
+ FreeTimer16(ptmr);
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+VOID CALLBACK W32Timer1(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(1, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer2(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(2, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer3(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(3, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer4(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(4, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer5(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(5, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer6(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(6, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer7(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(7, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer8(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(8, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer9(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(9, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer10(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(10, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer11(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(11, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer12(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(12, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer13(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(13, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer14(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(14, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer15(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(15, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer16(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(16, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer17(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(17, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer18(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(18, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer19(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(19, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer20(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(20, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer21(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(21, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer22(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(22, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer23(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(23, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer24(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(24, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer25(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(25, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer26(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(26, hwnd, idEvent, dwTime);
+}
+
+VOID CALLBACK W32Timer27(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
+{
+ WOW32ASSERT(msg == WM_TIMER);
+ W32TimerFunc(27, hwnd, idEvent, dwTime);
+}
diff --git a/private/mvdm/wow32/wutmr.h b/private/mvdm/wow32/wutmr.h
new file mode 100644
index 000000000..939125046
--- /dev/null
+++ b/private/mvdm/wow32/wutmr.h
@@ -0,0 +1,72 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUTMR.H
+ * WOW32 16-bit User Timer API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+/* Types
+ */
+typedef struct _TMR { /* tmr */
+ LIST_ENTRY TmrList; // TMRs are stored in a list
+ HWND16 hwnd16; // 16-bit handle of owning window, if any
+ HTASK16 htask16; // 16-bit handle of owning task
+ HWND hwnd32; // 32-bit handle of owning window, if any
+ WORD wIndex; // index into array for this timer
+ UINT dwEventID; // 32-bit timer ID (as generated by WIN32)
+ VPPROC vpfnTimerProc; // 16-bit timer proc address
+ DWORD dwTimerProc32; // 32-bit timer proc address
+} TMR, *PTMR, **PPTMR;
+
+
+/* Function prototypes
+ */
+
+VOID CALLBACK W32Timer1(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer2(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer3(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer4(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer5(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer6(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer7(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer8(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer9(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer10(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer11(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer12(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer13(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer14(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer15(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer16(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer17(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer18(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer19(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer20(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer21(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer22(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer23(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer24(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer25(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer26(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+VOID CALLBACK W32Timer27(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime);
+
+
+VOID W32TimerFunc(UINT index, HWND hwnd, UINT idEvent, DWORD dwTime);
+
+
+VOID FreeTimer16(PTMR ptmr);
+VOID DestroyTimers16(HTASK16 htask16);
+
+ULONG FASTCALL WU32KillTimer(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetTimer(PVDMFRAME pFrame);
+
+PTMR FindTimer32(HWND16 hwnd, DWORD dwEventID);
+PTMR FindTimer16(HWND16 hwnd, HTASK16 htask16, WORD wEventID);
+PTMR IsDuplicateTimer16(HWND16 hwnd16, HTASK16 htask16, WORD wEventID);
diff --git a/private/mvdm/wow32/wuwind.c b/private/mvdm/wow32/wuwind.c
new file mode 100644
index 000000000..da66bfcc4
--- /dev/null
+++ b/private/mvdm/wow32/wuwind.c
@@ -0,0 +1,3092 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUWIND.C
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+ * 12-FEB-92 mattfe changed WU32EnumTaskWindows to access 16 bit TDB
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+MODNAME(wuwind.c);
+
+// From wumsg.c [SendDlgItemMesssage caching]
+extern HWND hdlgSDIMCached ;
+
+// From wuman.c [Identify thunked system class WndProcs]
+extern WORD gUser16CS;
+
+// dwExStyle is used by the CreateWindow and CreateWindowEx thunks
+// so that they can use a common procedure (don't worry, the current
+// task cannot be preempted during its use)
+
+STATIC ULONG dwExStyle;
+
+// Some apps (DASHboard from HP) try to get PROGMAN to save its settings
+// in a funky way. This variable is used to help detect these guys.
+// Bobday 5/29/93
+HWND hwndProgman = (HWND)0;
+
+/*++
+ void AdjustWindowRect(<lpRect>, <dwStyle>, <bMenu>)
+ LPRECT <lpRect>;
+ DWORD <dwStyle>;
+ BOOL <bMenu>;
+
+ The %AdjustWindowRect% function computes the required size of the window
+ rectangle based on the desired client-rectangle size. The window rectangle
+ can then be passed to the %CreateWindow% function to create a window whose
+ client area is the desired size. A client rectangle is the smallest
+ rectangle that completely encloses a client area. A window rectangle is the
+ smallest rectangle that completely encloses the window. The dimensions of
+ the resulting window rectangle depend on the window styles and on whether
+ the window has a menu.
+
+ <lpRect>
+ Points to a %RECT% structure that contains the coordinates of the
+ client rectangle.
+
+ <dwStyle>
+ Specifies the window styles of the window whose client rectangle
+ is to be converted.
+
+ <bMenu>
+ Specifies whether the window has a menu.
+
+ This function does not return a value.
+
+ This function assumes a single menu row. If the menu bar wraps to two or
+ more rows, the coordinates are incorrect.
+--*/
+
+ULONG FASTCALL WU32AdjustWindowRect(PVDMFRAME pFrame)
+{
+ RECT t1;
+ register PADJUSTWINDOWRECT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ADJUSTWINDOWRECT16), parg16);
+ WOW32VERIFY(GETRECT16(parg16->f1, &t1));
+
+ AdjustWindowRect(
+ &t1,
+ LONG32(parg16->f2),
+ BOOL32(parg16->f3)
+ );
+
+ PUTRECT16(parg16->f1, &t1);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ void AdjustWindowRectEx(<lpRect>, <dwStyle>, <bMenu>, <dwExStyle>)
+ LPRECT <lpRect>;
+ DWORD <dwStyle>;
+ BOOL <bMenu>;
+ DWORD <dwExStyle>;
+
+ The %AdjustWindowRectEx% function computes the required size of the
+ rectangle of a window with extended style based on the desired
+ client-rectangle size. The window rectangle can then be passed to the
+ %CreateWindowEx% function to create a window whose client area is the
+ desired size.
+
+ A client rectangle is the smallest rectangle that completely encloses a
+ client area. A window rectangle is the smallest rectangle that completely
+ encloses the window. The dimensions of the resulting window rectangle
+ depends on the window styles and on whether the window has a menu.
+
+ <lpRect>
+ Points to a %RECT% structure that contains the coordinates of the
+ client rectangle.
+
+ <dwStyle>
+ Specifies the window styles of the window whose client rectangle
+ is to be converted.
+
+ <bMenu>
+ Specifies whether the window has a menu.
+
+ <dwExStyle>
+ Specifies the extended style of the window being created.
+
+ This function does not return a value.
+
+ This function assumes a single menu row. If the menu bar wraps to two or
+ more rows, the coordinates are incorrect.
+--*/
+
+ULONG FASTCALL WU32AdjustWindowRectEx(PVDMFRAME pFrame)
+{
+ RECT t1;
+ register PADJUSTWINDOWRECTEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ADJUSTWINDOWRECTEX16), parg16);
+ WOW32VERIFY(GETRECT16(parg16->f1, &t1));
+
+ AdjustWindowRectEx(
+ &t1,
+ LONG32(parg16->f2),
+ BOOL32(parg16->f3),
+ DWORD32(parg16->f4)
+ );
+
+ PUTRECT16(parg16->f1, &t1);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ BOOL AnyPopup(VOID)
+
+ The %AnyPopup% function indicates whether a pop-up window exists on the
+ screen. It searches the entire Windows screen, not just the caller's client
+ area. The %AnyPopup% function returns TRUE even if a pop-up window is
+ completely covered by another window.
+
+ This function has no parameters.
+
+ The return value is TRUE if a pop-up window exists. Otherwise, it is
+ FALSE.
+--*/
+
+ULONG FASTCALL WU32AnyPopup(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = GETBOOL16(AnyPopup());
+
+ RETURN(ul);
+}
+
+
+/*++
+ WORD ArrangeIconicWindows(<hwnd>)
+ HWND <hwnd>;
+
+ The %ArrangeIconicWindows% function arranges all the minimized (iconic)
+ child windows of the window specified by the <hwnd> parameter.
+
+ <hwnd>
+ Identifies the window.
+
+ The return value is the height of one row of icons, or zero if there were no
+ icons.
+
+ Applications that maintain their own iconic child windows call this function
+ to arrange icons in a client window. This function also arranges icons on
+ the desktop window, which covers the entire screen. The %GetDesktopWindow%
+ function retrieves the window handle of the desktop window.
+
+ To arrange iconic MDI child windows in an MDI client window, an application
+ sends the WM_MDIICONARRANGE message to the MDI client window.
+--*/
+
+ULONG FASTCALL WU32ArrangeIconicWindows(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PARRANGEICONICWINDOWS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ARRANGEICONICWINDOWS16), parg16);
+
+ ul = GETWORD16(ArrangeIconicWindows(
+ HWND32(parg16->hwnd)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HANDLE BeginDeferWindowPos(<nNumWindows>)
+ int <nNumWindows>;
+
+ The %BeginDeferWindowPos% function allocates memory to contain a multiple
+ window-position data structure and returns a handle to the structure. The
+ %DeferWindowPos% function fills this structure with information about the
+ target position for a window that is about to be moved. The
+ %EndDeferWindowPos% function accepts this structure and instantaneously
+ repositions the windows using the information stored in the structure.
+
+ <nNumWindows>
+ Specifies the initial number of windows for which position information
+ is to be stored in the structure. The %DeferWindowPos% function
+ increases the size of the structure if needed.
+
+ The return value identifies the multiple window-position structure. The
+ return value is NULL if system resources are not available to allocate the
+ structure.
+--*/
+
+ULONG FASTCALL WU32BeginDeferWindowPos(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PBEGINDEFERWINDOWPOS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(BEGINDEFERWINDOWPOS16), parg16);
+
+ ul = GETHDWP16(BeginDeferWindowPos(
+ INT32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL BringWindowToTop(<hwnd>)
+ HWND <hwnd>;
+
+ The %BringWindowToTop% function brings a pop-up or child window to the top
+ of a stack of overlapping windows. In addition, it activates pop-up and
+ top-level windows. The %BringWindowToTop% function should be used to uncover
+ any window that is partially or completely obscured by any overlapping
+ windows.
+
+ <hwnd>
+ Identifies the pop-up or child window that is to be brought to the top.
+
+ The return value is nonzero if the function is successful. Otherwise it is
+ zero. (updated for Win3.1 compatability -- this returned void for Win3.0)
+--*/
+
+ULONG FASTCALL WU32BringWindowToTop(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PBRINGWINDOWTOTOP16 parg16;
+
+ GETARGPTR(pFrame, sizeof(BRINGWINDOWTOTOP16), parg16);
+
+ ul = GETBOOL16(BringWindowToTop(HWND32(parg16->f1)));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+/*++
+ HWND ChildWindowFromPoint(<hwndParent>, <Point>)
+ HWND <hwndParent>;
+ POINT <Point>;
+
+ The %ChildWindowFromPoint% function determines which, if any, of the child
+ windows belonging to the given parent window contains the specified point.
+
+ <hwndParent>
+ Identifies the parent window.
+
+ <Point>
+ Specifies the client coordinates of the point to be tested.
+
+ The return value identifies the child window that contains the point. It is
+ NULL if the given point lies outside the parent window. If the point is
+ within the parent window but is not contained within any child window, the
+ handle of the parent window is returned.
+--*/
+
+ULONG FASTCALL WU32ChildWindowFromPoint(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT t2;
+ register PCHILDWINDOWFROMPOINT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CHILDWINDOWFROMPOINT16), parg16);
+ COPYPOINT16(parg16->f2, t2);
+
+ ul = GETHWND16(ChildWindowFromPoint(HWND32(parg16->f1), t2));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void CloseWindow(<hwnd>)
+ HWND <hwnd>;
+
+ The %CloseWindow% function minimizes the specified window. If the window is
+ an overlapped window, it is minimized by removing the client area and
+ caption of the open window from the display screen and moving the window's
+ icon into the icon area of the screen.
+
+ <hwnd>
+ Identifies the window to be minimized.
+
+ This function does not return a value.
+
+ This function has no effect if the <hwnd> parameter is a handle to a pop-up
+ or child window.
+--*/
+
+ULONG FASTCALL WU32CloseWindow(PVDMFRAME pFrame)
+{
+ register PCLOSEWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CLOSEWINDOW16), parg16);
+
+ CloseWindow(
+ HWND32(parg16->f1)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ HWND CreateWindow(<lpClassName>, <lpWindowName>, <dwStyle>, <X>, <Y>,
+ <nWidth>, <nHeight>, <hwndParent>, <hMenu>, <hInstance>, <lpParam>)
+ LPSTR <lpClassName>;
+ LPSTR <lpWindowName>;
+ DWORD <dwStyle>;
+ int <X>;
+ int <Y>;
+ int <nWidth>;
+ int <nHeight>;
+ HWND <hwndParent>;
+ HMENU <hMenu>;
+ HANDLE <hInstance>;
+ LPSTR <lpParam>;
+
+ The %CreateWindow% function creates an overlapped, pop-up, or child
+ window. The %CreateWindow% function specifies the window class, window
+ title, window style, and (optionally) initial position and size of the
+ window. The %CreateWindow% function also specifies the window's parent (if
+ any) and menu.
+
+ For overlapped, pop-up, and child windows, the %CreateWindow% function sends
+ WM_CREATE, WM_GETMINMAXINFO, and WM_NCCREATE messages to the window. The
+ <lParam> parameter of the WM_CREATE message contains a pointer to a
+ %CREATESTRUCT% structure. If WS_VISIBLE style is given, %CreateWindow%
+ sends the window all the messages required to activate and show the window.
+
+ If the window style specifies a title bar, the window title pointed to by
+ the <lpWindowName> parameter is displayed in the title bar. When using
+ %CreateWindow% to create controls such as buttons, check boxes, and text
+ controls, the <lpWindowName> parameter specifies the text of the control.
+
+ <lpClassName>
+ Points to a null-terminated string that names the window class. The
+ class name can be any name registered with the RegisterClass function or
+ any of the predefined control-class names specified in Table T.2,
+ "Control Classes."
+
+ <lpWindowName>
+ Points to a null-terminated string that represents the window name.
+
+ <dwStyle>
+ Specifies the style of window being created. It can be any
+ combination of the styles given in Table *** <$R[C#]> ***.3, Window
+ Styles the control styles given in Table 4.4, Control Styles, or a
+ combination of styles created by using the bitwise OR operator. ,
+
+ <X>
+ Specifies the initial <x>-position of the window. For an
+ overlapped or pop-up window, the <X> parameter is the initial
+ <x>-coordinate of the window's upper-left corner (in screen
+ coordinates). If this value is CW_USEDEFAULT, Windows selects the
+ default position for the window's upper-left corner. For a child window,
+ <X> is the <x>-coordinate of the upper-left corner of the window in the
+ client area of its parent window.
+
+ <Y>
+ Specifies the initial <y>-position of the window. For an
+ overlapped window, the <Y> parameter is the initial <y>-coordinate of
+ the window's upper-left corner. For a pop-up window, <Y> is the
+ <y>-coordinate (in screen coordinates) of the upper-left corner of the
+ pop-up window. For list-box controls, <Y> is the <y>-coordinate of the
+ upper-left corner of the control's client area. For a child window, <Y>
+ is the <y>-coordinate of the upper-left corner of the child window. All
+ of these coordinates are for the window, not the window's client area.
+
+ <nWidth>
+ Specifies the width (in device units) of the window. For
+ overlapped windows, the <nWidth> parameter is either the window's width
+ (in screen coordinates) or CW_USEDEFAULT. If <nWidth> is CW_USEDEFAULT,
+ Windows selects a default width and height for the window (the default
+ width extends from the initial <x>-position to the right edge of the
+ screen, and the default height extends from the initial <y>-position to
+ the top of the icon area).
+
+ <nHeight>
+ Specifies the height (in device units) of the window. For
+ overlapped windows, the <nHeight> parameter is the window's height in
+ screen coordinates. If the <nWidth> parameter is CW_USEDEFAULT, Windows
+ ignores <nHeight>.
+
+ <hwndParent>
+ Identifies the parent or owner window of the window being
+ created. A valid window handle must be supplied when creating a child
+ window or an owned window. An owned window is an overlapped window that
+ is destroyed when its owner window is destroyed, hidden when its owner
+ is made iconic, and which is always displayed on top of its owner
+ window. For pop-up windows, a handle can be supplied, but is not
+ required. If the window does not have a parent or is not owned by
+ another window, the <hwndParent> parameter must be set to NULL.
+
+ <hMenu>
+ Identifies a menu or a child-window identifier. The meaning
+ depends on the window style. For overlapped or pop-up windows, the
+ <hMenu> parameter identifies the menu to be used with the window. It can
+ be NULL, if the class menu is to be used. For child windows, <hMenu>
+ specifies the child-window identifier, an integer value that is used by
+ a dialog-box control to notify its parent of events (such as the
+ EN_HSCROLL message). The child-window identifier is determined by the
+ application and should be unique for all child windows with the same
+ parent window.
+
+ <hInstance>
+ Identifies the instance of the module to be associated with the
+ window.
+
+ <lpParam>
+ Points to a value that is passed to the window through the
+ %CREATESTRUCT% structure referenced by the <lParam> parameter of
+ the WM_CREATE message. If an application is calling %CreateWindow% to
+ create a multiple document interface (MDI) client window, <lpParam> must
+ point to a %CLIENTCREATESTRUCT% structure.
+
+ The return value identifies the new window. It is NULL if the window is not
+ created.
+
+ The %CreateWindow% function sends a WM_CREATE message to to the window
+ procedure before it returns.
+
+ For overlapped windows where the <X> parameter is CW_USEDEFAULT, the <Y>
+ parameter can be one of the show-style parameters described with the
+ %ShowWindow% function, or, for the first overlapped window to be created by
+ the application, it can be the <nCmdShow> parameter passed to the WinMain
+ function.
+
+ BUTTON
+ Designates a small rectangular child window that represents a button the
+ user can turn on or off by clicking it. Button controls can be used
+ alone or in groups, and can either be labeled or appear without text.
+ Button controls typically change appearance when the user clicks them.
+
+ COMBOBOX
+ Designates a control consisting of a selection field similar to an edit
+ control plus a list box. The list box may be displayed at all times or
+ may be dropped down when the user selects a pop box next to the
+ selection field.
+
+ Depending on the style of the combo box, the user can or cannot edit the
+ contents of the selection field. If the list box is visible, typing
+ characters into the selection box will cause the first list box entry
+ that matches the characters typed to be highlighted. Conversely,
+ selecting an item in the list box displays the selected text in the
+ selection field.
+
+ EDIT
+ Designates a rectangular child window in which the user can enter text
+ from the keyboard. The user selects the control, and gives it the input
+ focus by clicking it or moving to it by using the ^TAB^ key. The user
+ can enter text when the control displays a flashing caret. The mouse can
+ be used to move the cursor and select characters to be replaced, or to
+ position the cursor for inserting characters. The ^BACKSPACE^ key can be
+ used to delete characters.
+
+ Edit controls use the variable-pitch system font and display ANSI
+ characters. Applications compiled to run with previous versions of
+ Windows display text with a fixed-pitch system font unless they have
+ been marked by the Windows 3.0 %MARK% utility with the %MEMORY FONT%
+ option. An application can also send the WM_SETFONT message to the edit
+ control to change the default font.
+
+ Edit controls expand tab characters into as many space characters as are
+ required to move the cursor to the next tab stop. Tab stops are assumed
+ to be at every eighth character position.
+
+ LISTBOX
+ Designates a list of character strings. This control is used whenever an
+ application needs to present a list of names, such as filenames, that
+ the user can view and select. The user can select a string by pointing
+ to it and clicking. When a string is selected, it is highlighted and a
+ notification message is passed to the parent window. A vertical or
+ horizontal scroll bar can be used with a list-box control to scroll
+ lists that are too long for the control window. The list box
+ automatically hides or shows the scroll bar as needed.
+
+ MDICLIENT
+ Designates an MDI client window. The MDI client window receives messages
+ which control the MDI application's child windows. The recommended style
+ bits are WS_CLIPCHILDREN and WS_CHILD. To create a scrollable MDI client
+ window which allows the user to scroll MDI child windows into view, an
+ application can also use the WS_HSCROLL and WS_VSCROLL styles.
+
+ SCROLLBAR
+ Designates a rectangle that contains a thumb and has direction arrows at
+ both ends. The scroll bar sends a notification message to its parent
+ window whenever the user clicks the control. The parent window is
+ responsible for updating the thumb position, if necessary. Scroll-bar
+ controls have the same appearance and function as scroll bars used in
+ ordinary windows. Unlike scroll bars, scroll-bar controls can be
+ positioned anywhere in a window and used whenever needed to provide
+ scrolling input for a window.
+
+ The scroll-bar class also includes size-box controls. A size-box control
+ is a small rectangle that the user can expand to change the size of the
+ window.
+
+ STATIC
+ Designates a simple text field, box, or rectangle that can be used to
+ label, box, or separate other controls. Static controls take no input
+ and provide no output.
+
+ DS_LOCALEDIT
+ Specifies that edit controls in the dialog box will use memory in the
+ application's data segment. By default, all edit controls in dialog
+ boxes use memory outside the application's data segment. This feature
+ may be suppressed by adding the DS_LOCALEDIT flag to the STYLE command
+ for the dialog box. If this flag is not used, EM_GETHANDLE and
+ EM_SETHANDLE messages must not be used since the storage for the control
+ is not in the application's data segment. This feature does not affect
+ edit controls created outside of dialog boxes.
+
+ DS_MODALFRAME
+ Creates a dialog box with a modal dialog-box frame that can be combined
+ with a title bar and System menu by specifying the WS_CAPTION and
+ WS_SYSMENU styles.
+
+ DS_NOIDLEMSG
+ Suppresses WM_ENTERIDLE messages that Windows would otherwise send to
+ the owner of the dialog box while the dialog box is displayed.
+
+ DS_SYSMODAL
+ Creates a system-modal dialog box.
+
+ WS_BORDER
+ Creates a window that has a border.
+
+ WS_CAPTION
+ Creates a window that has a title bar (implies the WS_BORDER style).
+ This style cannot be used with the WS_DLGFRAME style.
+
+ WS_CHILD
+ Creates a child window. Cannot be used with the WS_POPUP style.
+
+ WS_CHILDWINDOW
+ Creates a child window that has the WS_CHILD style.
+
+ WS_CLIPCHILDREN
+ Excludes the area occupied by child windows when drawing within the
+ parent window. Used when creating the parent window.
+
+ WS_CLIPSIBLINGS
+ Clips child windows relative to each other; that is, when a particular
+ child window receives a paint message, the WS_CLIPSIBLINGS style clips
+ all other overlapped child windows out of the region of the child window
+ to be updated. (If WS_CLIPSIBLINGS is not given and child windows
+ overlap, it is possible, when drawing within the client area of a child
+ window, to draw within the client area of a neighboring child window.)
+ For use with the WS_CHILD style only.
+
+ WS_DISABLED
+ Creates a window that is initially disabled.
+
+ WS_DLGFRAME
+ Creates a window with a double border but no title.
+
+ WS_GROUP
+ Specifies the first control of a group of controls in which the user can
+ move from one control to the next by using the ^DIRECTION^ keys. All
+ controls defined with the WS_GROUP style after the first control belong
+ to the same group. The next control with the WS_GROUP style ends the
+ style group and starts the next group (that is, one group ends where the
+ next begins). Only dialog boxes use this style.
+
+ WS_HSCROLL
+ Creates a window that has a horizontal scroll bar.
+
+ WS_ICONIC
+ Creates a window that is initially iconic. For use with the
+ WS_OVERLAPPED style only.
+
+ WS_MAXIMIZE
+ Creates a window of maximum size.
+
+ WS_MAXIMIZEBOX
+ Creates a window that has a maximize box.
+
+ WS_MINIMIZE
+ Creates a window of minimum size.
+
+ WS_MINIMIZEBOX
+ Creates a window that has a minimize box.
+
+ WS_OVERLAPPED
+ Creates an overlapped window. An overlapped window has a caption and a
+ border.
+
+ WS_OVERLAPPEDWINDOW
+ Creates an overlapped window having the WS_OVERLAPPED, WS_CAPTION,
+ WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles.
+
+ WS_POPUP
+ Creates a pop-up window. Cannot be used with the WS_CHILD style.
+
+ WS_POPUPWINDOW
+ Creates a pop-up window that has the WS_BORDER, WS_POPUP, and WS_SYSMENU
+ styles. The WS_CAPTION style must be combined with the WS_POPUPWINDOW
+ style to make the system menu visible.
+
+ WS_SYSMENU
+ Creates a window that has a System-menu box in its title bar. Used only
+ for windows with title bars.
+
+ WS_TABSTOP
+ Specifies one of any number of controls through which the user can move
+ by using the ^TAB^ key. The ^TAB^ key moves the user to the next control
+ specified by the WS_TABSTOP style. Only dialog boxes use this style.
+
+ WS_THICKFRAME
+ Creates a window with a thick frame that can be used to size the
+ window.
+
+ WS_VISIBLE
+ Creates a window that is initially visible. This applies to overlapped
+ and pop-up windows. For overlapped windows, the <Y> parameter is used as
+ a %ShowWindow% function parameter.
+
+ WS_VSCROLL
+ Creates a window that has a vertical scroll bar.
+--*/
+
+ULONG FASTCALL WU32CreateWindow(PVDMFRAME pFrame)
+{
+ dwExStyle = 0;
+ return W32CreateWindow(pFrame);
+}
+
+
+/*++
+ HWND CreateWindowEx(<dwExStyle>, <lpszClass>, <lpszName>,
+ <dwStyle>, <x>, <y>, <cx>, <cy>, <hwndParent>, <hMenu>,
+ <hInstance>, <lpCreateParams>)
+ DWORD <dwExStyle>;
+ LPSTR <lpszClass>;
+ LPSTR <lpszName>;
+ DWORD <dwStyle>;
+ int <x>;
+ int <y>;
+ int <cx>;
+ int <cy>;
+ HWND <hwndParent>;
+ HMENU <hMenu>;
+ HANDLE <hInstance>;
+ LPSTR <lpCreateParams>;
+
+ The %CreateWindowEx% function creates an overlapped, pop-up, or child window
+ with an extended style specified in the <dwExStyle> parameter. Otherwise,
+ this function is identical to the %CreateWindow% function. See the
+ description of the %CreateWindow% function for more information on creating
+ a window and for a full descriptions of the other parameters of
+ %CreateWindowEx%.
+
+ <dwExStyle>
+ Specifies the extended style of the window being created. It may be one
+ of the following values:
+
+ WS_EX_DLGMODALFRAME
+ Designates a window with a double border that may optionally be created
+ with a title bar by specifying the WS_CAPTION style flag in the
+ <dwStyle> parameter.
+
+ WS_EX_NOPARENTNOTIFY
+ Specifies that a child window created with this style will not send the
+ WM_PARENTNOTIFY message to its parent window when the child window is
+ created or destroyed.
+
+ WS_EX_TOPMOST
+ ???
+
+ WS_EX_ACCEPTFILES
+ ???
+
+ <lpszClass>
+ Points to a null-terminated string containing the name of the window
+ class.
+
+ <lpszName>
+ Points to a null-terminated string containing the window name.
+
+ <dwStyle>
+ Specifies the style of window being created.
+
+ <x>
+ Specifies the initial left side position of the window.
+
+ <y>
+ Specifies the initial top position of the window.
+
+ <cx>
+ Specifies the width (in device units) of the window.
+
+ <cy>
+ Specifies the height (in device units) of the window.
+
+ <hwndParent>
+ Identifies the parent or owner window of the window being
+ created.
+
+ <hMenu>
+ Identifies a menu or a child-window identifier. The meaning
+ depends on the window style.
+
+ <hInstance>
+ Identifies the instance of the module to be associated with the
+ window.
+
+ <lpCreateParams>
+ Contains any application-specific creation parameters. The window being
+ created may access this data when the %CREATESTRUCT% structure is passed
+ to the window via the WM_NCCREATE and WM_CREATE messages.
+
+ The return value identifies the new window. It is NULL if the window is not
+ created.
+
+ The %CreateWindowEx% function sends the following messages to the window
+ being created:
+
+ WM_NCCREATE
+ WM_NCCALCSIZE
+ WM_CREATE
+ WM_OTHERWINDOWCREATED
+--*/
+
+ULONG FASTCALL WU32CreateWindowEx(PVDMFRAME pFrame)
+{
+ register PCREATEWINDOWEX16 parg16;
+
+ GETARGPTR(pFrame, sizeof(CREATEWINDOWEX16), parg16);
+ dwExStyle = DWORD32(parg16->f1);
+ FREEARGPTR(parg16);
+ RETURN(W32CreateWindow(pFrame));
+}
+
+ULONG FASTCALL W32CreateWindow(PVDMFRAME pFrame)
+{
+ PSZ psz1;
+ PSZ pszClass;
+ PSZ psz2;
+ HWND hwnd32;
+ HMENU hmenu32;
+ PWC pwc;
+ WW ww;
+ register PCREATEWINDOW16 parg16;
+ CLIENTCREATESTRUCT clientcreatestruct;
+ LPVOID vpparam;
+ CHAR szAtomName[WOWCLASS_ATOM_NAME];
+ DWORD dwStyle;
+ INT iClass;
+
+ GETARGPTR(pFrame, sizeof(CREATEWINDOW16), parg16);
+ GETPSZIDPTR(parg16->vpszClass, psz1);
+ GETPSZPTR(parg16->vpszWindow, psz2);
+
+ if ( HIWORD(psz1) == 0 ) {
+ pszClass = szAtomName;
+ GetAtomName( (ATOM)psz1, pszClass, WOWCLASS_ATOM_NAME );
+ } else {
+ pszClass = psz1;
+ }
+
+ //
+ // For child windows, the hMenu parameter is just a child window ID
+ //
+ if (DWORD32(parg16->dwStyle) & WS_CHILD) {
+ hmenu32 = (HMENU)parg16->hMenu;
+
+ // Invalidate SendDlgItemMessage cache
+ hdlgSDIMCached = NULL ;
+ }
+ else
+ hmenu32 = (HMENU32(parg16->hMenu));
+
+ if (_stricmp(pszClass, "MDIClient")) {
+ vpparam = (LPVOID)DWORD32(parg16->vpParam);
+ } else {
+ GETCLIENTCREATESTRUCT16(parg16->vpParam, &clientcreatestruct );
+ vpparam = &clientcreatestruct;
+ }
+
+ dwStyle = DWORD32(parg16->dwStyle);
+
+ //
+ // Fill in the WOW WORDs (WW) structure. This contains all the
+ // handle aliasing information in it.
+ //
+ pwc = FindClass16(pszClass, parg16->hInstance);
+
+ if (pwc) {
+
+ if (iClass = GetStdClassNumber(pszClass)) {
+ ww.iClass = iClass;
+ ww.vpfnWndProc = 0;
+ }
+ else {
+ // Look to see if the 16:16 proc is a thunk for a 32-bit proc.
+ // QUICKEN: registers wow class with 16bit listboxwndproc
+ // We treat this window as a WOWCLASS and therfore all
+ // LB_* messages remain unthunked (they remained > WM_USER).
+ //
+ // The following code checks for such a wndproc and
+ // sets the system class appropriately.
+
+ if (HIWORD(pwc->vpfnWndProc) == gUser16CS) {
+ LOGDEBUG(LOG_WARNING,("Creating Private Class window with System WndProc\n"));
+ IsThunkWindowProc((DWORD)pwc->vpfnWndProc, &iClass);
+ ww.iClass = iClass;
+ }
+ else {
+ ww.iClass = WOWCLASS_WIN16;
+ }
+
+ ww.vpfnWndProc = pwc->vpfnWndProc;
+ }
+ ww.vpfnDlgProc = 0;
+ ww.flState = WWSTATE_ICLASSISSET;
+
+
+
+ hwnd32 = (pfnOut.pfnCsCreateWindowEx)(
+ dwExStyle,
+ pszClass,
+ psz2,
+ dwStyle,
+ INT32DEFAULT(parg16->x),
+ INT32DEFAULT(parg16->y),
+ INT32DEFAULT(parg16->cx),
+ INT32DEFAULT(parg16->cy),
+ HWND32(parg16->hwndParent),
+ hmenu32,
+ HMODINST32(parg16->hInstance),
+ vpparam,
+ CW_FLAGS_ANSI,
+ (LPDWORD)&ww);
+
+ } else { // The class doesn't exist.
+
+ hwnd32 = NULL;
+
+ }
+
+#ifdef DEBUG
+ if (hwnd32) {
+ CHAR szClassName[80];
+
+ LOGDEBUG(LOG_WARNING,(" Window %04x created on class = %s\n", GETHWND16(hwnd32),
+ (GetClassName(hwnd32, szClassName, sizeof(szClassName)) ? szClassName : "Unknown")));
+ } else {
+ LOGDEBUG(LOG_WARNING,(" CreateWindow failed, class = %s\n", pszClass));
+ }
+#endif
+
+ FREEPSZPTR(psz1);
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN((ULONG) GETHWND16(hwnd32));
+}
+
+
+/*++
+ HANDLE BeginDeferWindowPos(<nNumWindows>)
+ int <nNumWindows>;
+
+ The %BeginDeferWindowPos% function allocates memory to contain a multiple
+ window-position data structure and returns a handle to the structure. The
+ %DeferWindowPos% function fills this structure with information about the
+ target position for a window that is about to be moved. The
+ %EndDeferWindowPos% function accepts this structure and instantaneously
+ repositions the windows using the information stored in the structure.
+
+ <nNumWindows>
+ Specifies the initial number of windows for which position information
+ is to be stored in the structure. The %DeferWindowPos% function
+ increases the size of the structure if needed.
+
+ The return value identifies the multiple window-position structure. The
+ return value is NULL if system resources are not available to allocate the
+ structure.
+--*/
+
+ULONG FASTCALL WU32DeferWindowPos(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ HDWP h32;
+ register PDEFERWINDOWPOS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DEFERWINDOWPOS16), parg16);
+
+ h32 = HDWP32(parg16->f1);
+
+ ul = (ULONG) DeferWindowPos(
+ h32,
+ HWND32(parg16->f2),
+ HWNDIA32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ INT32(parg16->f6),
+ INT32(parg16->f7),
+ WORD32(parg16->f8) & SWP_VALID
+ );
+
+ if (ul != (ULONG) h32) {
+ ul = GETHDWP16(ul);
+ LOGDEBUG (12, ("WOW::DeferWindowsPos: ul = %08x, h32 = %08x\n", ul, h32));
+ }
+ else {
+ ul = parg16->f1;
+ LOGDEBUG (12, ("WOW::DeferWindowsPos: ul = %08x, parg = %08x\n", ul, parg16->f1));
+ }
+
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL DestroyWindow(<hwnd>)
+ HWND <hwnd>;
+
+ The %DestroyWindow% function destroys the specified window. The
+ %DestroyWindow% function sends appropriate messages to the window to
+ deactivate it and remove the input focus. It also destroys the window's
+ menu, flushes the application queue, destroys outstanding timers, removes
+ clipboard ownership, and breaks the clipboard-viewer chain, if the window is
+ at the top of the viewer chain. It sends WM_DESTROY and WM_NCDESTROY
+ messages to the window.
+
+ If the given window is the parent of any windows, these child windows are
+ automatically destroyed when the parent window is destroyed. The
+ %DestroyWindow% function destroys child windows first, and then the window
+ itself.
+
+ The %DestroyWindow% function also destroys modeless dialog boxes created by
+ the %CreateDialog% function.
+
+ <hwnd>
+ Identifies the window to be destroyed.
+
+ The return value specifies whether or not the specified window is destroyed.
+ It is TRUE if the window is destroyed. Otherwise, it is FALSE.
+
+ If the window being destroyed is a top-level window, a
+ WM_OTHERWINDOWDESTROYED message will be broadcast to all top-level windows.
+
+ If the window being destroyed is a child window and does not have the
+ WS_NOPARENTNOTIFY style set, then a WM_PARENTNOTIFY message is sent to the
+ parent.
+--*/
+
+ULONG FASTCALL WU32DestroyWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PDESTROYWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(DESTROYWINDOW16), parg16);
+
+ ul = GETBOOL16(DestroyWindow(HWND32(parg16->f1)));
+
+ // Invalidate SendDlgItemMessage cache
+ hdlgSDIMCached = NULL ;
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL EnableWindow(<hwnd>, <bEnable>)
+ HWND <hwnd>;
+ BOOL <bEnable>;
+
+ The %EnableWindow% function enables or disables mouse and keyboard input to
+ the specified window or control. When input is disabled, input such as mouse
+ clicks and key presses are ignored by the window. When input is enabled, all
+ input is processed.
+
+ The %EnableWindow% function enables mouse and keyboard input to a window if
+ the <bEnable> parameter is TRUE, and disables it if <bEnable> is FALSE.
+
+ <hwnd>
+ Identifies the window to be enabled or disabled.
+
+ <bEnable>
+ Specifies whether the given window is to be enabled or disabled.
+
+ The return value indicates the state of the window before the %EnableWindow%
+ function was called. A return value of TRUE indicates mouse and keyboard was
+ originally disabled. A return value of FALSE indicates it was enabled. A
+ return value of FALSE is also returned if the window handle specified by
+ the <hwnd> parameter is invalid.
+
+ A window must be enabled before it can be activated. For example, if an
+ application is displaying a modeless dialog box and has disabled its main
+ window, the main window must be enabled before the dialog box is destroyed.
+ Otherwise, another window will get the input focus and be activated. If a
+ child window is disabled, it is ignored when Windows tries to determine
+ which window should get mouse messages.
+
+ Initially, all windows are enabled by default. %EnableWindow% must be used
+ to disable a window explicitly.
+--*/
+
+ULONG FASTCALL WU32EnableWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PENABLEWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENABLEWINDOW16), parg16);
+
+ ul = GETBOOL16(EnableWindow(
+ HWND32(parg16->f1),
+ BOOL32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void EndDeferWindowPos(<hWinPosInfo>)
+ HANDLE <hWinPosInfo>;
+
+ The %EndDeferWindowPos% function simultaneously updates the position and
+ size of one or more windows in a single screen-refresh cycle. The
+ <hWinPosInfo> parameter identifies a multiple window-position structure that
+ contains the update information for the windows. The %DeferWindowPos%
+ function stores the update information in the structure; the
+ %BeginDeferWindowPos% function creates the initial structure used by these
+ functions.
+
+ <hWinPosInfo>
+ Identifies a multiple window-position structure that contains size
+ and position information for one or more windows. This structure is
+ returned by the %BeginDeferWindowPos% function or the most recent call to
+ the %DeferWindowPos% function.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32EndDeferWindowPos(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PENDDEFERWINDOWPOS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENDDEFERWINDOWPOS16), parg16);
+
+ ul = (ULONG)EndDeferWindowPos(HDWP32(parg16->f1));
+ FREEHDWP16(parg16->f1);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+BOOL W32EnumWindowFunc(HWND hwnd, DWORD lParam)
+{
+ BOOL fReturn;
+ PARM16 Parm16;
+
+ WOW32ASSERT(lParam);
+
+ Parm16.EnumWndProc.hwnd = GETHWND16(hwnd);
+ STOREDWORD(Parm16.EnumWndProc.lParam, ((PWNDDATA)lParam)->dwUserWndParam);
+ CallBack16(RET_ENUMWINDOWPROC, &Parm16, ((PWNDDATA)lParam)->vpfnEnumWndProc, (PVPVOID)&fReturn);
+
+ return (BOOL16)fReturn;
+}
+
+
+/*++
+ BOOL EnumChildWindows(<hwndParent>, <lpEnumFunc>, <lParam>)
+ HWND <hwndParent>;
+ FARPROC <lpEnumFunc>;
+ DWORD <lParam>;
+
+ The %EnumChildWindows% function enumerates the child windows that belong to
+ the specified parent window by passing the handle of each child window, in
+ turn, to the application-supplied callback function pointed to by the
+ <lpEnumFunc> parameter.
+
+ The %EnumChildWindows% function continues to enumerate windows until the
+ called function returns zero or until the last child window has been
+ enumerated.
+
+ <hwndParent>
+ Identifies the parent window whose child windows are to be enumerated.
+
+ <lpEnumFunc>
+ Is the procedure-instance address of the callback function.
+
+ <lParam>
+ Specifies the value to be passed to the callback function for
+ the application's use.
+
+ The return value is TRUE if all child windows have been enumerated.
+ Otherwise, it is FALSE.
+
+ This function does not enumerate pop-up windows that belong to the
+ <hwndParent> parameter.
+
+ The address passed as the <lpEnumFunc> parameter must be created by using
+ the %MakeProcInstance% function.
+
+ The callback function must use the Pascal calling convention and must be
+ declared %FAR%.
+
+ Callback Function:
+
+ BOOL FAR PASCAL <EnumFunc>(<hwnd>, <lParam>)
+ HWND <hwnd>;
+ DWORD <lParam>;
+
+ <EnumFunc> is a placeholder for the application-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the application's module-definition file.
+
+ <hwnd>
+ Identifies the window handle.
+
+ <lParam>
+ Specifies the long parameter argument of the %EnumChildWindows%
+ function.
+
+ The callback function should return TRUE to continue enumeration; it should
+ return FALSE to stop enumeration.
+--*/
+
+ULONG FASTCALL WU32EnumChildWindows(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ WNDDATA WndData;
+ register PENUMCHILDWINDOWS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENUMCHILDWINDOWS16), parg16);
+
+ WndData.vpfnEnumWndProc = DWORD32(parg16->f2);
+ WndData.dwUserWndParam = DWORD32(parg16->f3);
+
+ ul = GETBOOL16(EnumChildWindows(HWND32(parg16->f1),
+ (WNDENUMPROC)W32EnumWindowFunc,
+ (LONG)&WndData));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/*++
+ BOOL EnumTaskWindows(<hTask>, <lpEnumFunc>, <lParam>)
+ HANDLE <hTask>;
+ FARPROC <lpEnumFunc>;
+ DWORD <lParam>;
+
+ The %EnumTaskWindows% function enumerates all windows associated with the
+ <hTask> parameter, which is returned by the %GetCurrentTask% function. (A
+ task is any program that executes as an independent unit. All applications
+ are executed as tasks and each instance of an application is a task.) The
+ enumeration terminates when the callback function, pointed to by
+ <lpEnumFunc>, returns FALSE.
+
+ <hTask>
+ Identifies the specified task. The GetCurrentTask function returns this
+ handle.
+
+ <lpEnumFunc>
+ Specifies the procedure-instance address of the window's callback
+ function.
+
+ <lParam>
+ Specifies the 32-bit value that contains additional parameters
+ that are sent to the callback function pointed to by <lpEnumFunc>.
+
+ The return value specifies the outcome of the function. It is TRUE if all
+ the windows associated with a particular task are enumerated. Otherwise, it
+ is FALSE.
+
+ The callback function must use the Pascal calling convention and must be
+ declared %FAR%. The callback function must have the following form:
+
+ Callback Function:
+
+ BOOL FAR PASCAL <EnumFunc>(<hwnd>, <lParam>)
+ HWND <hwnd>;
+ DWORD <lParam>;
+
+ <EnumFunc> is a placeholder for the application-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the application's module-definition file.
+
+ <hwnd>
+ Identifies a window associated with the current task.
+
+ <lParam>
+ Specifies the same argument that was passed to the %EnumTaskWindows%
+ function.
+
+ The callback function can carry out any desired task. It must return TRUE to
+ continue enumeration, or FALSE to stop it.
+--*/
+
+ULONG FASTCALL WU32EnumTaskWindows(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ WNDDATA WndData;
+ register PENUMTASKWINDOWS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENUMTASKWINDOWS16), parg16);
+
+ WndData.vpfnEnumWndProc = DWORD32(parg16->f2);
+ WndData.dwUserWndParam = DWORD32(parg16->f3);
+
+ ul = GETBOOL16(EnumThreadWindows(THREADID32(parg16->f1),
+ (WNDENUMPROC)W32EnumWindowFunc,
+ (LONG)&WndData));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/*++
+ BOOL EnumWindows(<lpEnumFunc>, <lParam>)
+ FARPROC <lpEnumFunc>;
+ DWORD <lParam>;
+
+ The %EnumWindows% function enumerates all parent windows on the screen by
+ passing the handle of each window, in turn, to the callback function pointed
+ to by the <lpEnumFunc> parameter. Child windows are not enumerated.
+
+ The %EnumWindows% function continues to enumerate windows until the called
+ function returns zero or until the last window has been enumerated.
+
+ <lpEnumFunc>
+ Is the procedure-instance address of the callback function. See the
+ following "Comments" section for details.
+
+ <lParam>
+ Specifies the value to be passed to the callback function for
+ the application's use.
+
+ The return value is TRUE if all windows have been enumerated. Otherwise, it
+ is FALSE.
+
+ The address passed as the <lpEnumFunc> parameter must be created by using
+ the %MakeProcInstance% function.
+
+ The callback function must use the Pascal calling convention and must be
+ declared %FAR%. The callback function must have the following form:
+
+ Callback Function:
+
+ BOOL FAR PASCAL <EnumFunc>(<hwnd>, <lParam>)
+ HWND <hwnd>;
+ DWORD <lParam>;
+
+ <EnumFunc> is a placeholder for the application-supplied function name. The
+ actual name must be exported by including it in an %EXPORTS% statement in
+ the application's module-definition file.
+
+ <hwnd>
+ Identifies the window handle.
+
+ <lParam>
+ Specifies the 32-bit argument of the %EnumWindows% function.
+
+ The function must return TRUE to continue enumeration, or FALSE to stop it.
+--*/
+
+ULONG FASTCALL WU32EnumWindows(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ WNDDATA WndData;
+ register PENUMWINDOWS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(ENUMWINDOWS16), parg16);
+
+ WndData.vpfnEnumWndProc = DWORD32(parg16->f1);
+ WndData.dwUserWndParam = DWORD32(parg16->f2);
+
+ ul = GETBOOL16(EnumWindows((WNDENUMPROC)W32EnumWindowFunc, (LONG)&WndData));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+
+/*++
+ HWND FindWindow(<lpClassName>, <lpWindowName>)
+ LPSTR <lpClassName>;
+ LPSTR <lpWindowName>;
+
+ The %FindWindow% function returns the handle of the window whose class is
+ given by the <lpClassName> parameter and whose window name, or caption, is
+ given by the <lpWindowName> parameter. This function does not search child
+ windows.
+
+ <lpClassName>
+ Points to a null-terminated string that specifies the window's class
+ name. If lpClassName is NULL, all class names match.
+
+ <lpWindowName>
+ Points to a null-terminated string that specifies the window name (the
+ window's text caption). If <lpWindowName> is NULL, all window names
+ match.
+
+ The return value identifies the window that has the specified class name and
+ window name. It is NULL if no such window is found.
+--*/
+
+ULONG FASTCALL WU32FindWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz1;
+ PSZ psz2;
+ PSZ pszClass;
+ register PFINDWINDOW16 parg16;
+ CHAR szAtomName[WOWCLASS_ATOM_NAME];
+
+ GETARGPTR(pFrame, sizeof(FINDWINDOW16), parg16);
+ GETPSZIDPTR(parg16->f1, psz1);
+ GETOPTPTR(parg16->f2, 0, psz2);
+
+ if ( psz1 && HIWORD(psz1) == 0 ) {
+ pszClass = szAtomName;
+ GetAtomName( (ATOM)psz1, pszClass, WOWCLASS_ATOM_NAME );
+ } else {
+ pszClass = psz1;
+ }
+
+
+ // Some apps during their installation try to find Program Manager's
+ // window handle by doing FindWindow. Once they get the window handle
+ // then they do DDE with program manager to create app group. An app
+ // can call FindWindow in one of the three ways.
+ //
+ // FindWindow ("progman", NULL)
+ // FindWindow (NULL, "program manager")
+ // FindWindow ("progman", "program manager")
+ //
+ // The case 2 and 3 of the above will fail on NT because the title of
+ // the program manager window under NT is "Program Manager - xxx\yyy".
+ // Where xxx is the domain name and yyy is the user name.
+ //
+ // To provide the Win 3.1 compatibility to the 16 bit apps, we check for
+ // the above cases. For these cases we call FindWindow ("progman", NULL)
+ // to get the window handle of the program manager's top level window.
+ //
+ // AmiPro calls FindWindow as case two of the above to find the window
+ // handle of the program manager to do DDE with.
+ // ChandanC, 5/18/93
+ //
+
+ // Some apps send WM_SYSCOMMAND - SC_CLOSE messages to program manager
+ // with the shift key down to get it to save its settings. They do
+ // this by 1st finding the program manager window...
+
+ if ((pszClass && !_stricmp (pszClass, "progman")) ||
+ (psz2 && !_stricmp (psz2, "program manager"))) {
+
+ ul = GETHWND16(FindWindow("progman", NULL));
+
+ // Some apps send WM_SYSCOMMAND - SC_CLOSE messages to program manager
+ // with the shift key down to get it to save its settings. They do
+ // this by 1st finding the program manager window...
+ // So, save this window handle for later.
+ hwndProgman = (HWND)ul;
+ }
+ else {
+ ul = GETHWND16(FindWindow(pszClass, psz2));
+ }
+
+ FREEPSZPTR(psz1);
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL FlashWindow(<hwnd>, <bInvert>)
+ HWND <hwnd>;
+ BOOL <bInvert>;
+
+ The %FlashWindow% function flashes the given window once. Flashing a window
+ means changing the appearance of its caption bar as if the window were
+ changing from inactive to active status, or vice versa. (An inactive caption
+ bar changes to an active caption bar; an active caption bar changes to an
+ inactive caption bar.)
+
+ Typically, a window is flashed to inform the user that the window requires
+ attention, but that it does not currently have the input focus.
+
+ <hwnd>
+ Identifies the window to be flashed. The window can be either open or
+ iconic.
+
+ <bInvert>
+ Specifies whether the window is to be flashed or returned to its
+ original state. The window is flashed from one state to the other if the
+ <bInvert> parameter is TRUE. If the <bInvert> parameter is FALSE, the
+ window is returned to its original state (either active or inactive).
+
+ The return value specifies the window's state before call to the
+ %FlashWindow% function. It is TRUE if the window was active before the
+ call. Otherwise, it is FALSE.
+
+ The %FlashWindow% function flashes the window only once; for successive
+ flashing, the application should create a system timer.
+
+ The <bInvert> parameter should be FALSE only when the window is getting the
+ input focus and will no longer be flashing; it should be TRUE on
+ successive calls while waiting to get the input focus.
+
+ This function always returns TRUE for iconic windows. If the window is
+ iconic, %FlashWindow% will simply flash the icon; <bInvert> is ignored for
+ iconic windows.
+--*/
+
+ULONG FASTCALL WU32FlashWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PFLASHWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(FLASHWINDOW16), parg16);
+
+ ul = GETBOOL16(FlashWindow(
+ HWND32(parg16->f1),
+ BOOL32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HWND GetActiveWindow(VOID)
+
+ The %GetActiveWindow% function retrieves the window handle of the active
+ window. The active window is either the window that has the current input
+ focus, or the window explicitly made active by the %SetActiveWindow%
+ function.
+
+ This function has no parameters.
+
+ The return value identifies the active window.
+--*/
+
+ULONG FASTCALL WU32GetActiveWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+
+ UNREFERENCED_PARAMETER(pFrame);
+
+ ul = (ULONG)GetActiveWindow();
+
+ // GetActiveWindow returned NULL. So try GetForegroundWindow.
+ // Some apps like Toolbook donot paint if GetActiveWindow returns NULL.
+ //
+ // Alternatively we can return the wowexec's window handle.. basically
+ // something NON-NULL
+ //
+ // NOTE: Win31 and Win32 GetActiveWindow differ semantically and hence
+ // the need for fooling with this API.
+ //
+ // - Nanduri Ramakrishna
+ //
+ // We need to do something different now, since JimA recently changed
+ // GetForegroundWindow() so that it can return NULL if the caller doesn't
+ // have access to the foreground window.
+ //
+ // - Dave Hart
+ //
+ // When GetForegroundWindow() returns null, now we return wowexec's
+ // window handle. This theoretically could have some strange effects
+ // since it is a hidden window. It might be better to return, say,
+ // the desktop window. However, for reasons currently unknown,
+ // this screws a shutdown scenario with Micrografix Designer (it
+ // gpfaults).
+ // - Neil Sandlin
+
+ if (ul == (ULONG)NULL) {
+ ul = (ULONG)GetForegroundWindow();
+ }
+
+ if (ul == (ULONG)NULL) {
+ ul = (ULONG)ghwndShell;
+ }
+
+ ul = GETHWND16(ul);
+
+ WOW32ASSERT(ul);
+ RETURN(ul);
+}
+
+
+/*++
+ HDC GetWindowDC(<hwnd>)
+ HWND <hwnd>;
+
+ The %GetWindowDC% function retrieves the display context for the entire
+ window, including caption bar, menus, and scroll bars. A window display
+ context permits painting anywhere in a window, including the caption bar,
+ menus, and scroll bars, since the origin of the context is the upper-left
+ corner of the window instead of the client area.
+
+ %GetWindowDC% assigns default attributes to the display context each time it
+ retrieves the context. Previous attributes are lost.
+
+ <hwnd>
+ Identifies the window whose display context is to be retrieved.
+
+ The return value identifies the display context for the given window if the
+ function is successful. Otherwise, it is NULL.
+
+ The %GetWindowDC% function is intended to be used for special painting
+ effects within a window's nonclient area. Painting in nonclient areas of any
+ window is not recommended.
+
+ The %GetSystemMetrics% function can be used to retrieve the dimensions of
+ various parts of the nonclient area, such as the caption bar, menu, and
+ scroll bars.
+
+ After painting is complete, the %ReleaseDC% function must be called to
+ release the display context. Failure to release a window display context
+ will have serious effects on painting requested by applications.
+--*/
+
+ULONG FASTCALL WU32GetWindowDC(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETWINDOWDC16 parg16;
+ HAND16 htask16 = pFrame->wTDB;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWDC16), parg16);
+
+ ReleaseCachedDCs(htask16, parg16->f1, 0, 0, SRCHDC_TASK16_HWND16);
+
+ ul = GETHDC16(GetWindowDC(
+ HWND32(parg16->f1)
+ ));
+
+ if (ul)
+ StoreDC(htask16, parg16->f1, (HAND16)ul);
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/*++
+ LONG GetWindowLong(<hwnd>, <nIndex>)
+ HWND <hwnd>;
+ int <nIndex>;
+
+ The %GetWindowLong% function retrieves information about the window
+ identified by the <hwnd> parameter.
+
+ <hwnd>
+ Identifies the window.
+
+ <nIndex>
+ Specifies the byte offset of the value to be retrieved. It can
+ also be one of the following values:
+
+ GWL_EXSTYLE
+ Extended window style.
+
+ GWL_STYLE
+ Window style
+
+ GWL_WNDPROC
+ Long pointer to the window function
+
+ The return value specifies information about the given window.
+
+ To access any extra four-byte values allocated when the window-class
+ structure was created, use a positive byte offset as the index specified by
+ the <nIndex> parameter, starting at zero for the first four-byte value in
+ the extra space, 4 for the next four-byte value and so on.
+--*/
+
+ULONG FASTCALL WU32GetWindowLong(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ INT iOffset;
+ register PWW pww;
+ register PGETWINDOWLONG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWLONG16), parg16);
+
+ // Make sure Win32 didn't change offsets for GWL constants
+
+#if (GWL_WNDPROC != (-4) || GWL_STYLE != (-16) || GWL_EXSTYLE != (-20))
+#error Win16/Win32 GWL constants differ
+#endif
+
+#ifndef WIN16_GWW_HINSTANCE
+#define WIN16_GWW_HINSTANCE (-6)
+#define WIN16_GWW_HWNDPARENT (-8)
+#define WIN16_GWW_ID (-12)
+#endif
+
+ // Make sure the 16-bit app is requesting allowable offsets
+
+ iOffset = INT32(parg16->f2);
+ WOW32ASSERT(iOffset >= 0 ||
+ iOffset == GWL_WNDPROC ||
+ iOffset == GWL_STYLE || iOffset == GWL_EXSTYLE ||
+ iOffset == WIN16_GWW_HINSTANCE ||
+ iOffset == WIN16_GWW_HWNDPARENT ||
+ iOffset == WIN16_GWW_ID );
+
+ ul = 0;
+ switch( iOffset ) {
+ case DWL_DLGPROC:
+ if (pww = FindPWW(HWND32(parg16->f1), WOWCLASS_UNKNOWN)) {
+
+ //
+ // if vpfnDlgProc exists then assume this is a dialog
+ //
+
+ if (pww->vpfnDlgProc) {
+ ul = pww->vpfnDlgProc;
+ }
+ else if (pww->iClass == WOWCLASS_DIALOG ||
+ (pww->flState & WWSTATE_FAKEDIALOGCLASS)) {
+
+ //
+ // this is some dialog we don't know about, like
+ // the window created by a call to MessageBox().
+ //
+
+ DWORD dwDlgProc32Cur;
+ dwDlgProc32Cur = GetWindowLong(HWND32(parg16->f1), DWL_DLGPROC);
+
+ if (dwDlgProc32Cur) {
+ ul = GetThunkWindowProc(dwDlgProc32Cur, 0, pww, HWND32(parg16->f1));
+ } else {
+ ul = 0;
+ }
+ }
+ else {
+ // not a dialog. default processing
+
+ goto defgwl;
+ }
+ }
+ break;
+
+ case GWL_WNDPROC:
+ if (pww = FindPWW(HWND32(parg16->f1), WOWCLASS_UNKNOWN)) {
+ DWORD dwWndProc32Cur;
+
+ dwWndProc32Cur = GetWindowLong(HWND32(parg16->f1), GWL_WNDPROC);
+
+ if ( dwWndProc32Cur & WNDPROC_WOW ) {
+ if ( HIWORD(dwWndProc32Cur) == WNDPROC_HANDLE ) {
+ /*
+ ** Has a 32-bit WindowProc that is a handle-based value
+ ** (if it needs a 32-bit Ansi-Unicode transition, or
+ ** vice versa.)
+ */
+ ul = GetThunkWindowProc( dwWndProc32Cur, NULL, pww, HWND32(parg16->f1) );
+ } else {
+ /*
+ ** Has a WOW WindowProc
+ */
+ ul = dwWndProc32Cur & WNDPROC_MASK;
+
+ //
+ // if the actual selector had the high bit on then we turned off
+ // bit 2 of the selector (the LDT bit, which will always be on)
+ //
+ if (!(ul & WOWCLASS_VIRTUAL_NOT_BIT31)) {
+ ul |= (WNDPROC_WOW | WOWCLASS_VIRTUAL_NOT_BIT31);
+ }
+ }
+ } else {
+ /*
+ ** Has a 32-bit WindowProc
+ */
+ ul = GetThunkWindowProc( dwWndProc32Cur, NULL, pww, HWND32(parg16->f1) );
+ }
+ }
+ break;
+
+ case GWL_EXSTYLE:
+ // Lotus Approach needs the WS_EX_TOPMOST bit cleared on
+ // GetWindowLong of NETDDE AGENT window.
+ ul = GetWindowLong(HWND32(parg16->f1), iOffset);
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_GWLCLRTOPMOST) {
+ char szBuf[40];
+
+ if (GetClassName(HWND32(parg16->f1), szBuf, sizeof(szBuf))) {
+ if (!_stricmp(szBuf, "NDDEAgnt")) {
+ ul &= !WS_EX_TOPMOST;
+ }
+ }
+ }
+
+ break;
+
+defgwl:
+ default:
+
+ // This is a real HACK for PowerBuild 3.0. Before we change the offset
+ // from 2 to 4, we nneed to make sure that we are doing it correctly for
+ // this specific class.
+ // The class in this case is "PaList".
+ //
+ // ChandanC Marh 9th 1994
+ //
+
+ if (iOffset == 2) {
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_GWLINDEX2TO4) {
+ char Buffer[40];
+
+ if (GetClassName (HWND32(parg16->f1), Buffer, sizeof(Buffer))) {
+ if (!_stricmp (Buffer, "PaList")) {
+ iOffset = 4;
+ }
+ }
+ }
+ }
+
+ ul = GetWindowLong(HWND32(parg16->f1), iOffset);
+ break;
+
+ case WIN16_GWW_HINSTANCE:
+ /*
+ ** We might need to set the high 16-bits to
+ ** some mysterious value (See Win 3.1 WND structure)
+ */
+ ul = (ULONG)((WORD)GetWindowLong(HWND32(parg16->f1),
+ GWL_HINSTANCE));
+ break;
+ case WIN16_GWW_HWNDPARENT:
+ /*
+ ** We might need to set the high 16-bits to
+ ** some mysterious value (See Win 3.1 WND structure)
+ */
+
+ ul = (ULONG)GETHWND16((HAND32)GetWindowLong(HWND32(parg16->f1),
+ GWL_HWNDPARENT));
+ break;
+
+ case WIN16_GWW_ID:
+ /*
+ ** We might need to set the high 16-bits to
+ ** some mysterious value (See Win 3.1 WND structure)
+ */
+ ul = (ULONG)((WORD)GetWindowLong(HWND32(parg16->f1), GWL_ID));
+ break;
+
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HANDLE GetWindowTask(<hwnd>)
+ HWND <hwnd>;
+
+ The %GetWindowTask% function searches for the handle of a task associated
+ with the <hwnd> parameter. A task is any program that executes as an
+ independent unit. All applications are executed as tasks. Each instance of
+ an application is a task.
+
+ <hwnd>
+ Identifies the window for which a task handle is retrieved.
+
+ The return value identifies the task associated with a particular window.
+--*/
+
+ULONG FASTCALL WU32GetWindowTask(PVDMFRAME pFrame)
+{
+ register PGETWINDOWTASK16 parg16;
+ DWORD dwThreadID, dwProcessID;
+ PTD ptd;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWTASK16), parg16);
+
+ dwThreadID = GetWindowThreadProcessId(HWND32(parg16->f1), &dwProcessID);
+
+ //
+ // return corresponding htask16 if window belongs to a WOW thread
+ // else return WowExec's htask.
+ //
+
+ ptd = ThreadProcID32toPTD(dwThreadID, dwProcessID);
+
+ if (ptd == NULL) {
+ ptd = gptdShell;
+ }
+
+ FREEARGPTR(parg16);
+ return (ULONG)ptd->htask16;
+}
+
+
+/*++
+ int GetWindowText(<hwnd>, <lpString>, <nMaxCount>)
+ HWND <hwnd>;
+ LPSTR <lpString>;
+ int <nMaxCount>;
+
+ The %GetWindowText% function copies the given window's caption title (if it
+ has one) into the buffer pointed to by the <lpString> parameter. If the
+ <hwnd> parameter identifies a control, the %GetWindowText% function copies
+ the text within the control instead of copying the caption.
+
+ <hwnd>
+ Identifies the window or control whose caption or text is to be copied.
+
+ <lpString>
+ Points to the buffer that is to receive the copied string.
+
+ <nMaxCount>
+ Specifies the maximum number of characters to be copied to the
+ buffer. If the string is longer than the number of characters specified
+ in the <nMaxCount> parameter, it is truncated.
+
+ The return value specifies the length of the copied string. It is zero if
+ the window has no caption or if the caption is empty.
+
+ This function causes a WM_GETTEXT message to be sent to the given window or
+ control.
+--*/
+
+ULONG FASTCALL WU32GetWindowText(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ PSZ psz2;
+ register PGETWINDOWTEXT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWTEXT16), parg16);
+ ALLOCVDMPTR(parg16->f2, parg16->f3, psz2);
+
+ ul = GETINT16(GetWindowText(
+ HWND32(parg16->f1),
+ psz2,
+ WORD32(parg16->f3)
+ ));
+
+ FLUSHVDMPTR(parg16->f2, (USHORT)ul+1, psz2);
+ FREEVDMPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ int GetWindowTextLength(<hwnd>)
+ HWND <hwnd>;
+
+ The %GetWindowTextLength% function returns the length of the given window's
+ caption title. If the <hwnd> parameter identifies a control, the
+ %GetWindowTextLength% function returns the length of the text within the
+ control instead of the caption.
+
+ <hwnd>
+ Identifies the window or control.
+
+ The return value specifies the text length. It is zero if no such text
+ exists.
+--*/
+
+ULONG FASTCALL WU32GetWindowTextLength(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PGETWINDOWTEXTLENGTH16 parg16;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWTEXTLENGTH16), parg16);
+
+ ul = GETINT16(GetWindowTextLength(
+ HWND32(parg16->f1)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ WORD GetWindowWord(<hwnd>, <nIndex>)
+ HWND <hwnd>;
+ int <nIndex>;
+
+ The %GetWindowWord% function retrieves information about the window
+ identified by <hwnd>.
+
+ <hwnd>
+ Identifies the window.
+
+ <nIndex>
+ Specifies the byte offset of the value to be retrieved. It can
+ also be one of the following values:
+
+ GWL_HINSTANCE
+ Instance handle of the module that owns the window.
+
+ GWL_HWNDPARENT
+ Handle of the parent window, if any. The %SetParent% function changes
+ the parent window of a child window. An application should not call the
+ %SetWindowLong% function to change the parent of a child window.
+
+ GWL_ID
+ Control ID of the child window.
+
+ The return value specifies information about the given window.
+
+
+ To access any extra two-byte values allocated when the window-class
+ structure was created, use a positive byte offset as the index specified by
+ the <nIndex> parameter, starting at zero for the first two-byte value in the
+ extra space, 2 for the next two-byte value and so on.
+--*/
+
+ULONG FASTCALL WU32GetWindowWord(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ HWND hwnd;
+ INT iOffset;
+ PWW pww;
+ PGETWINDOWWORD16 parg16;
+ DWORD dwThreadID32, dwProcessID32;
+ HTASK16 htask16;
+ PWOAINST pWOA;
+ PTD ptd;
+
+ GETARGPTR(pFrame, sizeof(GETWINDOWWORD16), parg16);
+
+ // Make sure Win32 didn't change offsets
+
+#if (GWL_HINSTANCE != (-6) || GWL_HWNDPARENT != (-8) || GWL_ID != (-12))
+#error Win16/Win32 window-word constants differ
+#endif
+
+ // Make sure the 16-bit app is requesting allowable offsets
+
+ iOffset = INT32(parg16->f2);
+ WOW32ASSERT(iOffset >= 0 ||
+ iOffset == GWL_HINSTANCE ||
+ iOffset == GWL_STYLE ||
+ iOffset == GWL_HWNDPARENT || iOffset == GWL_ID);
+
+ hwnd = HWND32(parg16->f1);
+
+ switch(iOffset) {
+ case GWL_STYLE:
+ // Wordperfect for windows calls GetWindowWord with GWL_STYLE.
+ ul = (ULONG)GetWindowLong(hwnd, iOffset);
+ break;
+
+ case GWL_HINSTANCE:
+ ul = (ULONG)GetWindowLong(hwnd, iOffset);
+
+ //
+ // Special hack for OLE 2.0 busy dialog, see WOLE2.C for long
+ // comment.
+ //
+ // The below if does not exclude window's whose HINSTANCE is zero.
+ // This is because some 32-bit applications put 0 in the HINSTANCE
+ // stuff for their window (its optional for 32-bit windows).
+ //
+ if ( !ISINST16(ul) ) {
+ // here if ul = NULL or ul = 0xZZZZ0000
+ //
+ // if (ul is 0xZZZZ0000) return 16bit user.exe instance.
+ // PowerBuilder 3.0 does
+ // hInst = GetWindowWord(Dialog, GWL_HINSTANCE)
+ // hIcon = CreateIcon(... hInst ...);
+ // CreateIcon will fail if hInst is invalid (say BOGUSGDT). So
+ // we return 16bit user.exe hinstance in all such cases.
+ //
+
+ dwProcessID32 = (DWORD)-1;
+ dwThreadID32 = GetWindowThreadProcessId( hwnd, &dwProcessID32 );
+
+ //
+ // Check if this window belongs to a task we spawned via
+ // WinOldAp, if so, return WinOldAp's hmodule.
+ //
+
+ ptd = CURRENTPTD();
+ pWOA = ptd->pWOAList;
+ while (pWOA && pWOA->dwChildProcessID != dwProcessID32) {
+ pWOA = pWOA->pNext;
+ }
+
+ if (pWOA) {
+ ul = pWOA->ptdWOA->hInst16;
+ LOGDEBUG(LOG_ALWAYS, ("WOW32 GetWindowWord(0x%x, GWW_HINSTANCE) returning 0x%04x\n",
+ hwnd, ul));
+ } else {
+
+ ul = (ul) ? gUser16hInstance : ul;
+
+ if (cHtaskAliasCount != 0 ) {
+
+ //
+ // Must be some 32-bit process, not a wow app's window
+ //
+
+ if ( dwThreadID32 != 0 ) {
+
+ htask16 = FindHtaskAlias( dwThreadID32 );
+
+ if ( htask16 != 0 ) {
+ ul = (ULONG)htask16;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case GWL_HWNDPARENT:
+ ul = (ULONG)GETHWND16((HAND32)GetWindowLong(hwnd, iOffset));
+ break;
+
+ case GWL_ID:
+ ul = GetWindowLong(hwnd, iOffset);
+ if (!(GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)) {
+ ul = (ULONG)GETHMENU16(ul);
+ }
+ break;
+
+ // Under Windows index 4 of a static control could be the icon
+ case 4:
+ pww = FindPWW(hwnd, WOWCLASS_UNKNOWN);
+ if (pww) {
+ if ((GetWindowLong(hwnd, GWL_STYLE) & SS_ICON) && (pww->iClass == WOWCLASS_STATIC)) {
+ ul = SendMessage(hwnd, STM_GETICON, 0, 0);
+ return GETHICON16(ul);
+ }
+ }
+ // FALL THROUGH!
+
+
+ default:
+ //
+ // Offset is non-negative, this is the cbWndExtra bytes that
+ // are fair game.
+ //
+
+ //
+ // Gross app hack for Adonis' Clip-Art Window Shopper online
+ // clipart software that comes with CA-Cricket Presents.
+ // These bozos SetWindowWord(hwnd, 3, wWhatever), thereby
+ // overwriting the 4th and 5th bytes of per-window data.
+ // The edit control itself only uses the first 2 bytes
+ // on 3.1, and has 6 bytes reserved, so this works. On
+ // NT the first 4 bytes are used (32-bit handle), and so
+ // this P.O.S. overwrites the high byte of the handle.
+ // So if it's the compatibility flag is set and the class name
+ // matches the one this bogus app uses, and it's storing a
+ // word at offset 3, change it to 4. This is safe because
+ // the NT edit control only uses the first 4 of its 6
+ // reserved window extra bytes.
+ //
+
+ if (3 == iOffset && (CURRENTPTD()->dwWOWCompatFlags & WOWCF_EDITCTRLWNDWORDS)) {
+
+ char szClassName[30];
+
+ if (GetClassName(hwnd, szClassName, sizeof(szClassName)) &&
+ !strcmp(szClassName, "SuperPassEdit")) {
+
+ iOffset = 4;
+
+ LOGDEBUG(LOG_ALWAYS,("WOW WU32GetWindowWord: SHOPPER hack triggered, using offset 4, rc = %x.\n",
+ GetWindowWord(hwnd, iOffset)));
+
+ }
+ }
+
+ ul = GetWindowWord(hwnd, iOffset);
+ break;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ BOOL MoveWindow(<hwnd>, <left>, <top>, <width>, <height>, <fRepaint>)
+ HWND <hwnd>;
+ int <left>;
+ int <top>;
+ int <width>;
+ int <height>;
+ BOOL <fRepaint>;
+
+ The %MoveWindow% function changes the position and dimensions of a window.
+
+ <hwnd>
+ Identifies the window to change.
+
+ <left>
+ Specifies the new position of the left side of the window.
+
+ <top>
+ Specifies the new position of the top of the window.
+
+ <width>
+ Specifies the new width of the window.
+
+ <height>
+ Specifies the new height of the window.
+
+ <fRepaint>
+ Specifies whether or not the window is to be repainted. If this
+ parameter is TRUE, the window is repainted.
+
+ The return value is nonzero if the function is successful. Otherwise it is
+ zero. (updated for Win3.1 compatability -- this returned void for Win3.0)
+
+ For top-level windows the <left> and <top> parameters are relative to the
+ upper-left corner of the screen. For child windows, they are relative to the
+ upper-left corner of the parent window's client area.
+
+ The %MoveWindow% function sends a WM_GETMINMAXINFO message to the window
+ being moved. This gives the window being moved the opportunity to modify
+ the default values for the largest and smallest possible windows. If the
+ parameters to the %MoveWindow% function exceed these values, the values will
+ be replaced by the minimum or maximum values specified in the
+ WM_GETMINMAXINFO message.
+--*/
+
+ULONG FASTCALL WU32MoveWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PMOVEWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(MOVEWINDOW16), parg16);
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_DBASEHANDLEBUG) {
+ RECT ParentRect;
+ RECT ScreenRect;
+
+ GetWindowRect(GetDesktopWindow(), &ScreenRect);
+ if ((INT32(parg16->f2) > ScreenRect.right) ||
+ (INT32(parg16->f3) > ScreenRect.bottom) ||
+ (INT32(parg16->f4) > ScreenRect.right) ||
+ (INT32(parg16->f5) > ScreenRect.bottom)) {
+ int x, y, cx, cy;
+
+ GetWindowRect(GetParent(HWND32(parg16->f1)), &ParentRect);
+ x = ParentRect.left;
+ y = ParentRect.top;
+ cx = ParentRect.right - ParentRect.left;
+ cy = ParentRect.bottom - ParentRect.top;
+
+
+ ul = GETBOOL16(MoveWindow(HWND32(parg16->f1), x, y, cx, cy,
+ BOOL32(parg16->f6)));
+ FREEARGPTR(parg16);
+ RETURN(ul);
+ }
+ }
+
+ ul = GETBOOL16(MoveWindow(HWND32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ BOOL32(parg16->f6)));
+
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+/*++
+ void ScrollWindow(<hwnd>, <XAmount>, <YAmount>, <lpRect>, <lpClipRect>)
+ HWND <hwnd>;
+ int <XAmount>;
+ int <YAmount>;
+ LPRECT <lpRect>;
+ LPRECT <lpClipRect>;
+
+ The %ScrollWindow% function scrolls a window by moving the contents of the
+ window's client area the number of units specified by the <XAmount>
+ parameter along the screen's <x>-axis and the number of units specified by
+ the <YAmount> parameter along the <y>-axis. The scroll moves right if
+ <XAmount> is positive and left if it is negative. The scroll moves down if
+ <YAmount> is positive and up if it is negative.
+
+ <hwnd>
+ Identifies the window whose client area is to be scrolled.
+
+ <XAmount>
+ Specifies the amount (in device units) to scroll in the <x>
+ direction.
+
+ <YAmount>
+ Specifies the amount (in device units) to scroll in the <y>
+ direction.
+
+ <lpRect>
+ Points to a %RECT% structure that specifies the portion of
+ the client area to be scrolled. If <lpRect> is NULL, the entire client
+ area is scrolled.
+
+ <lpClipRect>
+ Points to a %RECT% structure that specifies the clipping
+ rectangle to be scrolled. Only bits inside this rectangle are scrolled.
+ If <lpClipRect> is NULL, the entire window is scrolled.
+
+ This function does not return a value.
+
+ If the caret is in the window being scrolled, %ScrollWindow% automatically
+ hides the caret to prevent it from being erased, then restores the caret
+ after the scroll is finished. The caret position is adjusted accordingly.
+
+ The area uncovered by the %ScrollWindow% function is not repainted, but is
+ combined into the window's update region. The application will eventually
+ receive a WM_PAINT message notifying it that the region needs repainting. To
+ repaint the uncovered area at the same time the scrolling is done, call the
+ %UpdateWindow% function immediately after calling %ScrollWindow%.
+
+ If the <lpRect> parameter is NULL, the positions of any child windows in the
+ window are offset by the amount specified by <XAmount> and <YAmount>, and
+ any invalid (unpainted) areas in the window are also offset. %ScrollWindow%
+ is faster when <lpRect> is NULL.
+
+ If the <lpRect> parameter is not NULL, the positions of child windows are
+ <not> changed, and invalid areas in the window are <not> offset. To prevent
+ updating problems when <lpRect> is not NULL, call the %UpdateWindow%
+ function to repaint the window before calling %ScrollWindow%.
+--*/
+
+ULONG FASTCALL WU32ScrollWindow(PVDMFRAME pFrame)
+{
+ RECT t4, *p4;
+ RECT t5, *p5;
+ register PSCROLLWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SCROLLWINDOW16), parg16);
+ p4 = GETRECT16(parg16->f4, &t4);
+ p5 = GETRECT16(parg16->f5, &t5);
+
+ ScrollWindow(
+ HWND32(parg16->f1),
+ INT32(parg16->f2),
+ INT32(parg16->f3),
+ p4,
+ p5
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ HWND SetActiveWindow(<hwnd>)
+ HWND <hwnd>;
+
+ The %SetActiveWindow% function makes a top-level window the active window.
+
+ <hwnd>
+ Identifies the top-level window to be activated.
+
+ The return value identifies the window that was previously active. The
+ %SetActiveWindow% function should be used with care since it allows an
+ application to arbitrarily take over the active window and input focus.
+ Normally, Windows takes care of all activation.
+--*/
+
+ULONG FASTCALL WU32SetActiveWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETACTIVEWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETACTIVEWINDOW16), parg16);
+
+ ul = GETHWND16(SetActiveWindow(HWND32(parg16->f1)));
+
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ HWND SetParent(<hwndChild>, <hwndNewParent>)
+ HWND <hwndChild>;
+ HWND <hwndNewParent>;
+
+ The %SetParent% function changes the parent window of a child window. If the
+ window identified by the <hwndChild> parameter is visible, Windows performs
+ the appropriate redrawing and repainting.
+
+ <hwndChild>
+ Identifies the child window.
+
+ <hwndNewParent>
+ Identifies the new parent window.
+
+ The return value identifies the previous parent window.
+--*/
+
+ULONG FASTCALL WU32SetParent(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETPARENT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETPARENT16), parg16);
+
+ ul = GETHWND16(SetParent(HWND32(parg16->f1),
+ HWND32(parg16->f2)));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+
+/*++
+ LONG SetWindowLong(<hwnd>, <nIndex>, <dwNewLong>)
+ HWND <hwnd>;
+ int <nIndex>;
+ DWORD <dwNewLong>;
+
+ The %SetWindowLong% function changes an attribute of the window specified by
+ the <hwnd> parameter.
+
+ <hwnd>
+ Identifies the window.
+
+ <nIndex>
+ Specifies the byte offset of the attribute to be changed. It may
+ also be one of the following values:
+
+ GWL_EXSTYLE
+ Sets a new extended window style.
+
+ GWL_STYLE
+ Sets a new window style.
+
+ GWL_WNDPROC
+ Sets a new long pointer to the window procedure.
+
+ <dwNewLong>
+ Specifies the replacement value.
+
+ The return value specifies the previous value of the specified long
+ integer.
+
+ If the %SetWindowLong% function and the GWL_WNDPROC index are used to set a
+ new window function, that function must have the window-function form and be
+ exported in the module-definition file of the application. For more
+ information, see the %RegisterClass% function, earlier in this chapter.
+
+ Calling %SetWindowLong% with the GCL_WNDPROC index creates a subclass of the
+ window class used to create the window. See Chapter 1, Window Manager
+ Interface Functions, for more information on window subclassing. An
+ application should not attempt to create a window subclass for standard
+ Windows controls such as combo boxes and buttons.
+
+ To access any extra four-byte values allocated when the window-class
+ structure was created, use a positive byte offset as the index specified by
+ the <nIndex> parameter, starting at zero for the first four-byte value in
+ the extra space, 4 for the next four-byte value and so on.
+--*/
+ULONG FASTCALL WU32SetWindowLong(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ INT iOffset, iClass;
+ register PWW pww;
+ register PSETWINDOWLONG16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWLONG16), parg16);
+
+ // Make sure Win32 didn't change offsets for GWL constants
+
+#if (GWL_WNDPROC != (-4) || GWL_STYLE != (-16) || GWL_EXSTYLE != (-20))
+#error Win16/Win32 GWL constants differ
+#endif
+
+ // Make sure the 16-bit app is requesting allowable offsets
+
+ iOffset = INT32(parg16->f2);
+ WOW32ASSERT(iOffset >= 0 ||
+ iOffset == GWL_WNDPROC ||
+ iOffset == GWL_STYLE || iOffset == GWL_EXSTYLE);
+
+ ul = 0;
+ if (iOffset == GWL_WNDPROC) {
+
+ if (pww = FindPWW(HWND32(parg16->f1), WOWCLASS_UNKNOWN)) {
+ DWORD dwWndProc32Old;
+ DWORD dwWndProc32New;
+
+ // Look to see if the new 16:16 proc is a thunk for a 32-bit proc.
+ dwWndProc32New = IsThunkWindowProc(LONG32(parg16->f3), &iClass );
+
+ if ( dwWndProc32New != 0 ) {
+ //
+ // They are attempting to set the window proc to an existing
+ // 16-bit thunk that is really just a thunk for a 32-bit
+ // routine. We can just set it back to the 32-bit routine.
+ //
+ dwWndProc32Old = SetWindowLong(HWND32(parg16->f1), GWL_WNDPROC, dwWndProc32New);
+
+ // If the 32 bit set failed, perhaps because its another process,
+ // then we want to fail too
+ if (!dwWndProc32Old)
+ goto SWL_Cleanup;
+
+ SETWL(HWND32(parg16->f1), GWL_WOWvpfnWndProc, 0 );
+ SETWL(HWND32(parg16->f1), GWL_WOWiClassAndflState,
+ MAKECLASSANDSTATE(iClass, pww->flState | WWSTATE_ICLASSISSET));
+ } else {
+ //
+ // They are attempting to set it to a real 16:16 proc.
+ //
+ LONG l;
+
+ l = LONG32(parg16->f3);
+
+ //
+ // FEATURE-O-RAMA
+ //
+ // if the selector already has the high bit on then turn off
+ // bit 2 of the selector (the LDT bit, which should always be
+ // on). we need a way to not blindly strip off the high bit
+ // in our wndproc.
+ //
+
+ if (l & WNDPROC_WOW) {
+ WOW32ASSERT(l & WOWCLASS_VIRTUAL_NOT_BIT31);
+ l &= ~WOWCLASS_VIRTUAL_NOT_BIT31;
+ }
+
+ dwWndProc32Old = SetWindowLong(HWND32(parg16->f1), GWL_WNDPROC, l | WNDPROC_WOW);
+
+ // If the 32 bit set failed, perhaps because its another process,
+ // then we want to fail too
+ if (!dwWndProc32Old)
+ goto SWL_Cleanup;
+
+ SETWL(HWND32(parg16->f1), GWL_WOWvpfnWndProc, LONG32(parg16->f3));
+ }
+
+ if ( dwWndProc32Old & WNDPROC_WOW ) {
+ if ( HIWORD(dwWndProc32Old) == WNDPROC_HANDLE ) {
+ //
+ // If the return value was a handle to a proc (due to
+ // the need for unicode-ansi transitions, or vice versa)
+ // then treat it as a 32-bit thunk.
+ //
+ ul = GetThunkWindowProc(dwWndProc32Old, NULL, pww, HWND32(parg16->f1));
+ } else {
+ //
+ // Previous proc was a 16:16 proc
+ //
+ ul = dwWndProc32Old & WNDPROC_MASK;
+
+ //
+ // if the actual selector had the high bit on then we turned off
+ // bit 2 of the selector (the LDT bit, which will always be on)
+ //
+
+ if (!(ul & WOWCLASS_VIRTUAL_NOT_BIT31)) {
+ ul |= (WNDPROC_WOW | WOWCLASS_VIRTUAL_NOT_BIT31);
+ }
+ }
+ } else {
+ //
+ // Previous proc was a 32-bit proc, use an allocated thunk
+ //
+ ul = GetThunkWindowProc(dwWndProc32Old, NULL, pww, HWND32(parg16->f1));
+ }
+ }
+
+ }
+ else if (iOffset == DWL_DLGPROC) {
+ if (pww = FindPWW(HWND32(parg16->f1), WOWCLASS_UNKNOWN)) {
+ DWORD dwDlgProc32Old;
+ DWORD dwDlgProc32New;
+
+ //
+ // first see if this is a dialog or not
+ //
+
+ if (!(pww->vpfnDlgProc || pww->iClass == WOWCLASS_DIALOG ||
+ (pww->flState & WWSTATE_FAKEDIALOGCLASS))) {
+
+ goto defswp; // not a dialog
+ }
+
+ // Look to see if the new 16:16 proc is a thunk for a 32-bit proc.
+ dwDlgProc32New = IsThunkWindowProc(LONG32(parg16->f3), NULL);
+
+ if ( dwDlgProc32New != 0 ) {
+ //
+ // They want to set the dialog proc to an existing
+ // 16-bit thunk that is really just a thunk for a 32-bit
+ // routine. We can just set it back to the 32-bit routine.
+ // assume they had already changed the dlgproc once and
+ // return the old vpfnDlgProc.
+ //
+ SetWindowLong(HWND32(parg16->f1), DWL_DLGPROC, dwDlgProc32New);
+ ul = pww->vpfnDlgProc;
+ SETWL(HWND32(parg16->f1), GWL_WOWvpfnDlgProc, 0);
+
+ } else { // subclass this dialogproc
+
+ dwDlgProc32Old = SetWindowLong(HWND32(parg16->f1), iOffset,
+ (parg16->f3) ? (LONG)W32DialogFunc : 0);
+
+ if (dwDlgProc32Old == (DWORD)W32DialogFunc) {
+ ul = pww->vpfnDlgProc;
+
+ } else if (dwDlgProc32Old) {
+ ul = GetThunkWindowProc(dwDlgProc32Old, 0, pww, HWND32(parg16->f1));
+
+ } else {
+ ul = 0;
+ }
+
+ SETWL(HWND32(parg16->f1), GWL_WOWvpfnDlgProc, LONG32(parg16->f3));
+ }
+ }
+ }
+ else { // not GWL_WNDPROC or GWL_DLGPROC
+defswp:
+
+ // This is a real HACK for PowerBuild 3.0. Before we change the offset
+ // from 2 to 4, we nneed to make sure that we are doing it for this
+ // specific class.
+ // The class in this case is "PaList".
+ //
+ // ChandanC Marh 9th 1994
+ //
+
+ if (iOffset == 2) {
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_GWLINDEX2TO4) {
+ char Buffer[40];
+
+ if (GetClassName (HWND32(parg16->f1), Buffer, sizeof(Buffer))) {
+ if (!_stricmp (Buffer, "PaList")) {
+ iOffset = 4;
+ }
+ }
+ }
+ }
+
+ ul = SetWindowLong(HWND32(parg16->f1), iOffset, LONG32(parg16->f3));
+ }
+
+SWL_Cleanup:
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+/*++
+ BOOL SetWindowPos(<hwnd>, <hwndInsertAfter>, <X>, <Y>, <cx>, <cy>, <wFlags>)
+ HWND <hwnd>;
+ HWND <hwndInsertAfter>;
+ int <X>;
+ int <Y>;
+ int <cx>;
+ int <cy>;
+ WORD <wFlags>;
+
+ The %SetWindowPos% function changes the size, position, and ordering of
+ child, pop-up, and top-level windows. Child, pop-up, and top-level windows
+ are ordered according to their appearance on the screen; the topmost window
+ receives the highest rank, and it is the first window in the list. This
+ ordering is recorded in a window list.
+
+ <hwnd>
+ Identifies the window that will be positioned.
+
+ <hwndInsertAfter>
+ Identifies a window in the window-manager's list that will
+ precede the positioned window.
+
+ <X>
+ Specifies the <x->coordinate of the window's upper-left corner.
+
+ <Y>
+ Specifies the <y->coordinate of the window's upper-left corner.
+
+ <cx>
+ Specifies the new window's width.
+
+ <cy>
+ Specifies the new window's height.
+
+ <wFlags>
+ Specifies one of eight possible 16-bit values that affect the
+ sizing and positioning of the window. It must be one of the following
+ values:
+
+ SWP_DRAWFRAME
+ Draws a frame (defined in the window's class description) around the
+ window.
+
+ SWP_HIDEWINDOW
+ Hides the window.
+
+ SWP_NOACTIVATE
+ Does not activate the window.
+
+ SWP_NOMOVE
+ Retains current position (ignores the <x> and <y> parameters).
+
+ SWP_NOSIZE
+ Retains current size (ignores the <cx> and <cy> parameters).
+
+ SWP_NOREDRAW
+ Does not redraw changes.
+
+ SWP_NOZORDER
+ Retains current ordering (ignores the <hwndInsertAfter> parameter).
+
+ SWP_SHOWWINDOW
+ Displays the window.
+
+ The return value is nonzero if the function is successful. Otherwise it is
+ zero. (updated for Win3.1 compatability -- this returned void for Win3.0)
+
+ If the SWP_NOZORDER flag is not specified, Windows places the window
+ identified by the <hwnd> parameter in the position following the window
+ identified by the <hwndInsertAfter> parameter. If <hwndInsertAfter> is NULL,
+ Windows places the window identified by <hwnd> at the top of the list. If
+ <hwndInsertAfter> is set to 1, Windows places the window identified by
+ <hwnd> at the bottom of the list.
+
+ If the SWP_SHOWWINDOW or the SWP_HIDEWINDOW flags are set, scrolling and
+ moving cannot be done simultaneously.
+
+ All coordinates for child windows are relative to the upper-left corner of
+ the parent window's client area.
+--*/
+
+ULONG FASTCALL WU32SetWindowPos(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSETWINDOWPOS16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWPOS16), parg16);
+
+ ul = GETBOOL16(SetWindowPos(HWND32(parg16->f1),
+ HWNDIA32(parg16->f2),
+ INT32(parg16->f3),
+ INT32(parg16->f4),
+ INT32(parg16->f5),
+ INT32(parg16->f6),
+ WORD32(parg16->f7) & SWP_VALID));
+
+ FREEARGPTR(parg16);
+
+ RETURN(ul);
+}
+
+
+/*++
+ void SetWindowText(<hwnd>, <lpString>)
+
+ The %SetWindowText% function sets the given window's caption title (if one
+ exists) to the string pointed to by the <lpString> parameter. If the <hwnd>
+ parameter is a handle to a control, the %SetWindowText% function sets the
+ text within the control instead of within the caption.
+
+ <hwnd>
+ Identifies the window or control whose text is to be changed.
+
+ <lpString>
+ Points to a null-terminated string.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32SetWindowText(PVDMFRAME pFrame)
+{
+ PSZ psz2;
+ register PSETWINDOWTEXT16 parg16;
+ HANDLE handle;
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWTEXT16), parg16);
+ GETPSZPTR(parg16->f2, psz2);
+ handle = HWND32(parg16->f1);
+
+ if (NULL != psz2) {
+ AddParamMap((DWORD)psz2, FETCHDWORD(parg16->f2));
+ }
+
+ if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_DBASEHANDLEBUG) {
+
+ if (NULL == handle) {
+ handle = (HANDLE) ((PTDB)SEGPTR(pFrame->wTDB,0))->TDB_CompatHandle;
+ }
+ }
+
+ SetWindowText(handle, psz2);
+
+ // if we used param map successfully - then nuke there
+
+ if (NULL != psz2) {
+ DeleteParamMap((DWORD)psz2, PARAM_32, NULL);
+ }
+
+ FREEPSZPTR(psz2);
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ WORD SetWindowWord(<hwnd>, <nIndex>, <wNewWord>)
+
+ The %SetWindowWord% function changes an attribute of the window specified by
+ the <hwnd> parameter.
+
+ <hwnd>
+ Identifies the window to be modified.
+
+ <nIndex>
+ Specifies the byte offset of the word to be changed. It can also
+ be one of the following values:
+
+ GWL_HINSTANCE
+ Instance handle of the module that owns the window.
+
+ GWL_ID
+ Control ID of the child window.
+
+ <wNewWord>
+ Specifies the replacement value.
+
+ The return value specifies the previous value of the specified word.
+
+ To access any extra two-byte values allocated when the window-class
+ structure was created, use a positive byte offset as the index specified by
+ the <nIndex> parameter, starting at zero for the first two-byte value in the
+ extra space, 2 for the next two-byte value and so on.
+--*/
+
+ULONG FASTCALL WU32SetWindowWord(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ HWND hwnd;
+ INT iOffset;
+ PSETWINDOWWORD16 parg16;
+ PWW pww;
+
+ GETARGPTR(pFrame, sizeof(SETWINDOWWORD16), parg16);
+
+ // Make sure Win32 didn't change offsets
+
+#if (GWL_HINSTANCE != (-6) || GWL_HWNDPARENT != (-8) || GWL_ID != (-12))
+#error Win16/Win32 window-word constants differ
+#endif
+
+ // Make sure the 16-bit app is requesting allowable offsets
+
+ iOffset = INT32(parg16->f2);
+ WOW32ASSERT(iOffset >= 0 ||
+ iOffset == GWL_HINSTANCE || iOffset == GWL_ID ||
+ iOffset == GWL_HWNDPARENT);
+
+ hwnd = HWND32(parg16->f1);
+ ul = WORD32(parg16->f3);
+
+ switch(iOffset) {
+ case GWL_HINSTANCE:
+ ul = GETHINST16(SetWindowLong(hwnd,
+ iOffset,
+ (LONG)HMODINST32(parg16->f3)));
+ break;
+
+ case GWL_HWNDPARENT:
+ // ul = 0; // not allowed to set this
+ ul = SetWindowLong(hwnd, iOffset, (LONG)HWND32(parg16->f3));
+ ul = GETHWND16((HAND32)ul);
+ break;
+
+ case GWL_ID:
+ {
+ // if this isn't a child window then the value should be a
+ // menu handle
+ BOOL fChild = (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD);
+ ul = SetWindowLong(hwnd,
+ iOffset,
+ fChild ? (LONG)ul : (LONG)HMENU32(parg16->f3));
+
+ if (!fChild)
+ ul = (ULONG)GETHMENU16(ul);
+
+ // Invalidate the SendDlgItemMessage cache
+ hdlgSDIMCached = NULL ;
+ }
+ break;
+
+ // Under Windows index 4 of a static control could be the icon
+ case 4:
+ pww = FindPWW(hwnd, WOWCLASS_UNKNOWN);
+ if (pww) {
+ if ((GetWindowLong(hwnd, GWL_STYLE) & SS_ICON) && (pww->iClass == WOWCLASS_STATIC)) {
+ ul = SendMessage(hwnd, STM_SETICON, (WPARAM)HICON32(ul), 0);
+ return GETHICON16(ul);
+ }
+ }
+ // FALL THROUGH!
+
+ default:
+ //
+ // Offset is non-negative, this is the cbWndExtra bytes that
+ // are fair game.
+ //
+
+ //
+ // Gross app hack for Adonis' Clip-Art Window Shopper online
+ // clipart software that comes with CA-Cricket Presents.
+ // These bozos SetWindowWord(hwnd, 3, wWhatever), thereby
+ // overwriting the 4th and 5th bytes of per-window data.
+ // The edit control itself only uses the first 2 bytes
+ // on 3.1, and has 6 bytes reserved, so this works. On
+ // NT the first 4 bytes are used (32-bit handle), and so
+ // this P.O.S. overwrites the high byte of the handle.
+ // So if it's an app called "SHOPPER" and it's storing a
+ // word at offset 3, change it to 4. This is safe because
+ // the NT edit control only uses the first 4 of its 6
+ // reserved window extra bytes.
+ //
+
+ if (3 == iOffset && (CURRENTPTD()->dwWOWCompatFlags & WOWCF_EDITCTRLWNDWORDS)) {
+
+ char szClassName[30];
+
+ if (GetClassName(hwnd, szClassName, sizeof(szClassName)) &&
+ !strcmp(szClassName, "SuperPassEdit")) {
+
+ iOffset = 4;
+
+ LOGDEBUG(LOG_ALWAYS,("WOW WU32SetWindowWord: SHOPPER hack triggered, using offset 4.\n"));
+ }
+ }
+
+ ul = SetWindowWord(hwnd, iOffset, (WORD)ul);
+ break;
+ }
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++
+ void ShowScrollBar(<hwnd>, <wBar>, <bShow>)
+
+ The %ShowScrollBar% function displays or hides a scroll bar, depending on
+ the value of the <bShow> parameter. If <bShow> is TRUE, the scroll bar is
+ displayed; if <bShow> is FALSE, the scroll bar is hidden.
+
+ <hwnd>
+ Identifies a window that contains a scroll bar in its nonclient area if
+ the wBar parameter is SB_HORZ, SB_VERT, or SB_BOTH. If wBar is SB_CTL,
+ hwnd identifies a scroll-bar control.
+
+ <wBar>
+ %WORD% Specifies whether the scroll bar is a control or part of a
+ window's nonclient area. If it is part of the nonclient area, <wBar>
+ also indicates whether the scroll bar is positioned horizontally,
+ vertically, or both. It must be one of the following values:
+
+ SB_BOTH Specifies the window's horizontal and vertical scroll bars.
+ SB_CTL Specifies that the scroll bar is a control.
+ SB_HORZ Specifies the window's horizontal scroll bar.
+ SB_VERT Specifies the window's vertical scroll bar.
+
+ <bShow>
+ Specifies whether or not Windows hides the scroll bar. If <bShow> is
+ FALSE, the scroll bar is hidden. Otherwise, the scroll bar is
+ displayed.
+
+ This function does not return a value.
+
+ An application should not call this function to hide a scroll bar while
+ processing a scroll-bar notification message.
+--*/
+
+ULONG FASTCALL WU32ShowScrollBar(PVDMFRAME pFrame)
+{
+ register PSHOWSCROLLBAR16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SHOWSCROLLBAR16), parg16);
+
+ ShowScrollBar(
+ HWND32(parg16->f1),
+ WORD32(parg16->f2),
+ BOOL32(parg16->f3)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0);
+}
+
+
+/*++
+ BOOL ShowWindow(<hwnd>, <nCmdShow>)
+
+ The %ShowWindow% function displays or removes the given window, as specified
+ by the <nCmdShow> parameter.
+
+ <hwnd>
+ Identifies the window.
+
+ <nCmdShow>
+ Specifies how the window is to be shown. It must be one of the
+ following values:
+
+ SW_HIDE
+ Hides the window and passes activation to another window.
+
+ SW_MINIMIZE
+ Minimizes the specified window and activates the top-level window in the
+ window-manager's list.
+
+ SW_RESTORE
+ Same as SW_SHOWNORMAL.
+
+ SW_SHOW
+ Activates a window and displays it in its current size and position.
+
+ SW_SHOWMAXIMIZED
+ Activates the window and displays it as a maximized window.
+
+ SW_SHOWMINIMIZED
+ Activates the window and displays it as iconic.
+
+ SW_SHOWMINNOACTIVE
+ Displays the window as iconic. The window that is currently active
+ remains active.
+
+ SW_SHOWNA
+ Displays the window in its current state. The window that is currently
+ active remains active.
+
+ SW_SHOWNOACTIVATE
+ Displays a window in its most recent size and position. The window that
+ is currently active remains active.
+
+ SW_SHOWNORMAL
+ Activates and displays a window. If the window is minimized or
+ maximized, Windows restores it to its original size and position.
+
+ The return value specifies the previous state of the window. It is TRUE
+ if the window was previously visible. It is FALSE if the window was
+ previously hidden.
+
+ The %ShowWindow% function must be called only once per program with the
+ <nCmdShow> parameter from the WinMain function. Subsequent calls to
+ %ShowWindow% must use one of the values listed above, instead of one
+ specified by the <nCmdShow> parameter from the WinMain function.
+--*/
+
+ULONG FASTCALL WU32ShowWindow(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ register PSHOWWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(SHOWWINDOW16), parg16);
+
+ ul = GETBOOL16(ShowWindow(
+ HWND32(parg16->f1),
+ INT32(parg16->f2)
+ ));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
+
+
+/*++ user
+ void UpdateWindow(<hwnd>)
+
+ The %UpdateWindow% function updates the client area of the given window by
+ sending a WM_PAINT message to the window if the update region for the window
+ is not empty. The %UpdateWindow% function sends a WM_PAINT message directly
+ to the window function of the given window, bypassing the application
+ queue. If the update region is empty, no message is sent.
+
+ <hwnd>
+ Identifies the window to be updated.
+
+ This function does not return a value.
+--*/
+
+ULONG FASTCALL WU32UpdateWindow(PVDMFRAME pFrame)
+{
+ register PUPDATEWINDOW16 parg16;
+
+ GETARGPTR(pFrame, sizeof(UPDATEWINDOW16), parg16);
+
+ UpdateWindow(
+ HWND32(parg16->f1)
+ );
+
+ FREEARGPTR(parg16);
+ RETURN(0xcdef); // ack! same as win31
+}
+
+
+/*++
+ HWND WindowFromPoint(<Point>)
+
+ The %WindowFromPoint% function identifies the window that contains the given
+ point; <Point> must specify the screen coordinates of a point on the screen.
+
+ <Point>
+ Specifies a %POINT% structure that defines the point to be checked.
+
+ The return value identifies the window in which the point lies. It is NULL
+ if no window exists at the given point.
+--*/
+
+ULONG FASTCALL WU32WindowFromPoint(PVDMFRAME pFrame)
+{
+ ULONG ul;
+ POINT t1;
+ register PWINDOWFROMPOINT16 parg16;
+
+ GETARGPTR(pFrame, sizeof(WINDOWFROMPOINT16), parg16);
+ COPYPOINT16(parg16->f1, t1);
+
+ ul = GETHWND16(WindowFromPoint(t1));
+
+ FREEARGPTR(parg16);
+ RETURN(ul);
+}
diff --git a/private/mvdm/wow32/wuwind.h b/private/mvdm/wow32/wuwind.h
new file mode 100644
index 000000000..111013464
--- /dev/null
+++ b/private/mvdm/wow32/wuwind.h
@@ -0,0 +1,68 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WUWIND.H
+ * WOW32 16-bit User API support
+ *
+ * History:
+ * Created 07-Mar-1991 by Jeff Parsons (jeffpar)
+--*/
+
+
+/* Enumeration handler data
+ */
+typedef struct _WNDDATA { /* wnddata */
+ VPPROC vpfnEnumWndProc; // 16-bit enumeration function
+ DWORD dwUserWndParam; // user param, if any
+} WNDDATA, *PWNDDATA;
+
+
+/* Function prototypes
+ */
+ULONG FASTCALL WU32AdjustWindowRect(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AdjustWindowRectEx(PVDMFRAME pFrame);
+ULONG FASTCALL WU32AnyPopup(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ArrangeIconicWindows(PVDMFRAME pFrame);
+ULONG FASTCALL WU32BeginDeferWindowPos(PVDMFRAME pFrame);
+ULONG FASTCALL WU32BringWindowToTop(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ChildWindowFromPoint(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CloseWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CreateWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32CreateWindowEx(PVDMFRAME pFrame);
+ULONG FASTCALL W32CreateWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DeferWindowPos(PVDMFRAME pFrame);
+ULONG FASTCALL WU32DestroyWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EnableWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EndDeferWindowPos(PVDMFRAME pFrame);
+
+BOOL W32EnumWindowFunc(HWND hwnd, DWORD lParam);
+
+ULONG FASTCALL WU32EnumChildWindows(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EnumTaskWindows(PVDMFRAME pFrame);
+ULONG FASTCALL WU32EnumWindows(PVDMFRAME pFrame);
+ULONG FASTCALL WU32FindWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32FlashWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetActiveWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetWindowDC(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetWindowLong(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetWindowTask(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetWindowText(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetWindowTextLength(PVDMFRAME pFrame);
+ULONG FASTCALL WU32GetWindowWord(PVDMFRAME pFrame);
+ULONG FASTCALL WU32MoveWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ScrollWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetActiveWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetParent(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetWindowLong(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetWindowPos(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetWindowText(PVDMFRAME pFrame);
+ULONG FASTCALL WU32SetWindowWord(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ShowScrollBar(PVDMFRAME pFrame);
+ULONG FASTCALL WU32ShowWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32UpdateWindow(PVDMFRAME pFrame);
+ULONG FASTCALL WU32WindowFromPoint(PVDMFRAME pFrame);
+
+extern HWND hwndProgman;
diff --git a/private/mvdm/wow32/wwstbl2.h b/private/mvdm/wow32/wwstbl2.h
new file mode 100644
index 000000000..1bfab65fe
--- /dev/null
+++ b/private/mvdm/wow32/wwstbl2.h
@@ -0,0 +1,198 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WWSTBL2.h
+ * WOW32 16-bit Winsock API tables
+ *
+ * History:
+ * Created 02-Oct-1992 by David Treadwell (davidtr)
+ *
+ * This file is included into the master thunk table.
+ *
+--*/
+
+ {W32FUN(UNIMPLEMENTEDAPI, "DUMMYENTRY", MOD_WINSOCK, 0)},
+ {W32FUN(WWS32accept, "ACCEPT", MOD_WINSOCK, sizeof(ACCEPT16))},
+ {W32FUN(WWS32bind, "BIND", MOD_WINSOCK, sizeof(BIND16))},
+ {W32FUN(WWS32closesocket, "CLOSESOCKET", MOD_WINSOCK, sizeof(CLOSESOCKET16))},
+ {W32FUN(WWS32connect, "CONNECT", MOD_WINSOCK, sizeof(CONNECT16))},
+ {W32FUN(WWS32getpeername, "GETPEERNAME", MOD_WINSOCK, sizeof(GETPEERNAME16))},
+ {W32FUN(WWS32getsockname, "GETSOCKNAME", MOD_WINSOCK, sizeof(GETSOCKNAME16))},
+ {W32FUN(WWS32getsockopt, "GETSOCKOPT", MOD_WINSOCK, sizeof(GETSOCKOPT16))},
+ {W32FUN(WWS32htonl, "HTONL", MOD_WINSOCK, sizeof(HTONL16))},
+ {W32FUN(WWS32htons, "HTONS", MOD_WINSOCK, sizeof(HTONS16))},
+
+ /*** 0010 ***/
+ {W32FUN(WWS32inet_addr, "INET_ADDR", MOD_WINSOCK, sizeof(INET_ADDR16))},
+ {W32FUN(WWS32inet_ntoa, "INET_NTOA", MOD_WINSOCK, sizeof(INET_NTOA16))},
+ {W32FUN(WWS32ioctlsocket, "IOCTLSOCKET", MOD_WINSOCK, sizeof(IOCTLSOCKET16))},
+ {W32FUN(WWS32listen, "LISTEN", MOD_WINSOCK, sizeof(LISTEN16))},
+ {W32FUN(WWS32ntohl, "NTOHL", MOD_WINSOCK, sizeof(NTOHL16))},
+ {W32FUN(WWS32ntohs, "NTOHS", MOD_WINSOCK, sizeof(NTOHS16))},
+ {W32FUN(WWS32recv, "RECV", MOD_WINSOCK, sizeof(RECV16))},
+ {W32FUN(WWS32recvfrom, "RECVFROM", MOD_WINSOCK, sizeof(RECVFROM16))},
+ {W32FUN(WWS32select, "SELECT", MOD_WINSOCK, sizeof(SELECT16))},
+ {W32FUN(WWS32send, "SEND", MOD_WINSOCK, sizeof(SEND16))},
+
+ /*** 0020 ***/
+ {W32FUN(WWS32sendto, "SENDTO", MOD_WINSOCK, sizeof(SENDTO16))},
+ {W32FUN(WWS32setsockopt, "SETSOCKOPT", MOD_WINSOCK, sizeof(SETSOCKOPT16))},
+ {W32FUN(WWS32shutdown, "SHUTDOWN", MOD_WINSOCK, sizeof(SHUTDOWN16))},
+ {W32FUN(WWS32socket, "SOCKET", MOD_WINSOCK, sizeof(SOCKET16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0030 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0040 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0050 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(WWS32gethostbyaddr, "GETHOSTBYADDR", MOD_WINSOCK, sizeof(GETHOSTBYADDR16))},
+ {W32FUN(WWS32gethostbyname, "GETHOSTBYNAME", MOD_WINSOCK, sizeof(GETHOSTBYNAME16))},
+ {W32FUN(WWS32getprotobyname, "GETPROTOBYNAME", MOD_WINSOCK, sizeof(GETPROTOBYNAME16))},
+ {W32FUN(WWS32getprotobynumber, "GETPROTOBYNUMBER", MOD_WINSOCK, sizeof(GETPROTOBYNUMBER16))},
+ {W32FUN(WWS32getservbyname, "GETSERVBYNAME", MOD_WINSOCK, sizeof(GETSERVBYNAME16))},
+ {W32FUN(WWS32getservbyport, "GETSERVBYPORT", MOD_WINSOCK, sizeof(GETSERVBYPORT16))},
+ {W32FUN(WWS32gethostname, "GETHOSTNAME", MOD_WINSOCK, sizeof(GETHOSTNAME16))},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0060 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0070 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0080 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0090 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0100 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(WWS32WSAAsyncSelect, "WSAASYNCSELECT", MOD_WINSOCK, sizeof(WSAASYNCSELECT16))},
+ {W32FUN(WWS32WSAAsyncGetHostByAddr, "WSAASYNCGETHOSTBYADDR", MOD_WINSOCK, sizeof(WSAASYNCGETHOSTBYADDR16))},
+ {W32FUN(WWS32WSAAsyncGetHostByName, "WSAASYNCGETHOSTBYNAME", MOD_WINSOCK, sizeof(WSAASYNCGETHOSTBYNAME16))},
+ {W32FUN(WWS32WSAAsyncGetProtoByNumber, "WSAASYNCGETPROTOBYNUMBER",MOD_WINSOCK, sizeof(WSAASYNCGETPROTOBYNUMBER16))},
+ {W32FUN(WWS32WSAAsyncGetProtoByName, "WSAASYNCGETPROTOBYNAME", MOD_WINSOCK, sizeof(WSAASYNCGETPROTOBYNAME16))},
+ {W32FUN(WWS32WSAAsyncGetServByPort, "WSAASYNCGETSERVBYPORT", MOD_WINSOCK, sizeof(WSAASYNCGETSERVBYPORT16))},
+ {W32FUN(WWS32WSAAsyncGetServByName, "WSAASYNCGETSERVBYNAME", MOD_WINSOCK, sizeof(WSAASYNCGETSERVBYNAME16))},
+ {W32FUN(WWS32WSACancelAsyncRequest, "WSACANCELASYNCREQUEST", MOD_WINSOCK, sizeof(WSACANCELASYNCREQUEST16))},
+ {W32FUN(WWS32WSASetBlockingHook, "WSASETBLOCKINGHOOK", MOD_WINSOCK, sizeof(WSASETBLOCKINGHOOK16))},
+
+ /*** 0110 ***/
+ {W32FUN(WWS32WSAUnhookBlockingHook, "WSAUNHOOKBLOCKINGHOOK", MOD_WINSOCK, 0)},
+ {W32FUN(WWS32WSAGetLastError, "WSAGETLASTERROR", MOD_WINSOCK, 0)},
+ {W32FUN(WWS32WSASetLastError, "WSASETLASTERROR", MOD_WINSOCK, sizeof(WSASETLASTERROR16))},
+ {W32FUN(WWS32WSACancelBlockingCall, "WSACANCELBLOCKINGCALL", MOD_WINSOCK, 0)},
+ {W32FUN(WWS32WSAIsBlocking, "WSAISBLOCKING", MOD_WINSOCK, 0)},
+ {W32FUN(WWS32WSAStartup, "WSASTARTUP", MOD_WINSOCK, sizeof(WSASTARTUP16))},
+ {W32FUN(WWS32WSACleanup, "WSACLEANUP", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0120 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0130 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0140 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+
+ /*** 0150 ***/
+ {W32FUN(UNIMPLEMENTEDAPI, "", MOD_WINSOCK, 0)},
+ {W32FUN(WWS32__WSAFDIsSet, "__WSAFDISSET", MOD_WINSOCK, sizeof(__WSAFDISSET16))},